hdmiin:
HDMIIn声音直接通过codec输出到喇叭、耳机,不需要送到主控进行处理:
TC358749XBG-> alc5651 i2s2 -> alc5651 dac -> hp/lineout
RK平台 android 5.1 BOX MID的SDK之后统一使用这个目录下面的代码
\hardware\rockchip\audio\tinyalsa_hal
嵌入式设备的音频系统可以被划分为板载硬件(Machine)、Soc(Platform)、Codec 三大部分
1、音频编解码器 Codec 负责处理音频信息,包括 ADC,DAC,Mixer,DSP,输入输出以及音量控制等所有
与音频相关的功能。
Codec 与处理器之间通过 I2C 总线和数字音频接口 DAI 进行通信。
I2C 总线 - 实现对 Codec 寄存器数据的读写。
2、DAI –(digital audio interface)实现音频数据在 CPU 和 Codec 间的通信,包括 I2S、PCM 和 AC97
等。
蓝牙立体声音乐播放走的是蓝牙跟 CPU 直接的 UART 接口。
在只有一组 I2S 的主控上面,蓝牙通话 SCO 暂时是通过 Codec 中继,即通过 codec 来路由选择是
否走通话,走的是 I2S 接口 。如果主控有两组 I2S,那么可以将 BT PCM 直接接到主控的 PCM 接
口上。
S/DIF(Sony/Philips Digital Interface Format),通过光纤或同轴电缆传输音频,保证音频质量。
Codec 内部通路举例 RK616
同时音频驱动有三部分:
Machine driver
sound/soc/rockchip/rk_rk616.c
其中的 Machine 驱动负责 Platform 和 Codec 之间的耦合以及部分和设备或板子特定的代码采样率
时钟配置
Platform driver
sound/soc/ rockchip /rk30_i2s.c
I2S 控制器驱动 采样率时钟 DMA 等配置
Codec driver
sound/soc/codecs/rk616_codec.c
codec 的寄存器通路的配置
android定义了很多的音频devices:在frameworks/base/media/java/android/media/AudioSystem.java文件中
349 // output devices, be sure to update AudioManager.java also
350 public static final int DEVICE_OUT_EARPIECE = 0x1;
351 public static final int DEVICE_OUT_SPEAKER = 0x2;
352 public static final int DEVICE_OUT_WIRED_HEADSET = 0x4;
353 public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8;
354 public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10;
355 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20;
356 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40;
357 public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80;
358 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
359 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
360 public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
361 public static final int DEVICE_OUT_HDMI = DEVICE_OUT_AUX_DIGITAL;
362 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
363 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
364 public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000;
365 public static final int DEVICE_OUT_USB_DEVICE = 0x4000;
366 public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000;
367 public static final int DEVICE_OUT_TELEPHONY_TX = 0x10000;
368 public static final int DEVICE_OUT_LINE = 0x20000;
369 public static final int DEVICE_OUT_HDMI_ARC = 0x40000;
370 public static final int DEVICE_OUT_SPDIF = 0x80000;
371 public static final int DEVICE_OUT_FM = 0x100000;
372 public static final int DEVICE_OUT_AUX_LINE = 0x200000;
373 public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000;
374 public static final int DEVICE_OUT_IP = 0x800000;
375 public static final int DEVICE_OUT_BUS = 0x1000000;
在hardware/rockchip/audio/tinyalsa_hal/alsa_route.c 中通过route_set_controls(route)中通过 get_route_config(int route)将以上的各个route值转换为codec_config中的xxx.h配置文件。
文件:./hardware/rockchip/audio/tinyalsa_hal/alsa_route.c
282 const struct config_route *get_route_config(unsigned route) //即在这里获取音频路由设备
283 {
284 ALOGV("get_route_config() route %d", route);
285
286
287 if (!route_table) {
288 ALOGE("get_route_config() route_table is NULL!");
289 return NULL;
290 }
291 switch (route) {
292 case SPEAKER_NORMAL_ROUTE:
293 return &(route_table->speaker_normal);
......
HAL层中定义的 route table,再通过route_set_controls将这些table配置,最终设置到codec的寄存器
文件:./hardware/rockchip/audio/tinyalsa_hal/codec_config/rt5651_config.h
1110 const struct config_route_table rt5651_config_table = {
1111 //speaker
1112 .speaker_normal = {
1113 .sound_card = 0,
1114 .devices = DEVICES_0,
1115 .controls = rt5651_speaker_normal_controls,
1116 .controls_count = sizeof(rt5651_speaker_normal_controls) / sizeof(struct config_control),
1117 },
......
48 const struct config_control rt5651_speaker_normal_controls[] = {
56
57 {
58 .ctl_name = "DAC MIXL INF1 Switch",
59 .int_val = {on},
60 },
61 {
62 .ctl_name = "DAC MIXR INF1 Switch",
63 .int_val = {on},
64 },
65 {
66 .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
67 .int_val = {on},
68 },
69 {
70 .ctl_name = "Stereo DAC MIXR DAC R1 Switch",
71 .int_val = {on},
72 },
73 {
74 .ctl_name = "OUT MIXL DAC L1 Switch",
75 .int_val = {on},
76 },
77 {
78 .ctl_name = "OUT MIXR DAC R1 Switch",
79 .int_val = {on},
80 },
81
HAL层会根据sound card name选择使用哪个table,如果没有匹配默认使用default_config.h
文件:./hardware/rockchip/audio/tinyalsa_hal/alsa_route.c
89 /**
90 * @brief route_init
91 *
92 * @returns
93 */
94 int route_init(void)
95 {
96 char soundCardID[20] = "";
97 static FILE * fp;
98 unsigned i, config_count = sizeof(sound_card_config_list) / sizeof(struct alsa_sound_card_config);
99 size_t read_size;
100
101 ALOGV("route_init()");
102
103 fp = fopen("/proc/asound/card0/id", "rt");
104 if (!fp) {
105 ALOGE("Open sound card0 id error!");
106 } else {
107 read_size = fread(soundCardID, sizeof(char), sizeof(soundCardID), fp);
108 fclose(fp);
109
110 if (soundCardID[read_size - 1] == '\n') {
111 read_size--;
112 soundCardID[read_size] = '\0';
113 }
114
115 ALOGV("Sound card0 is %s", soundCardID);
116
117 for (i = 0; i < config_count; i++) {
118 if (!(sound_card_config_list + i) || !sound_card_config_list[i].sound_card_name ||
119 !sound_card_config_list[i].route_table)
120 continue;
121
122 if (strncmp(sound_card_config_list[i].sound_card_name, soundCardID, //根据sound card name选择使用哪个table
123 read_size) == 0) {
124 route_table = sound_card_config_list[i].route_table;
125 ALOGD("Get route table for sound card0 %s", soundCardID);
126 }
127 }
128 }
129
130 if (!route_table) {
131 route_table = &default_config_table; //如果没有匹配默认使用default_config.h
132 ALOGD("Can not get config table for sound card0 %s, so get default config table.", soundCardID);
133 }
134
135 for (i = PCM_DEVICE0_PLAYBACK; i < PCM_MAX; i++)
136 mPcm[i] = NULL;
137
138 return 0;
139 }
HAL层声卡名称sound card name和配置表列表table的声明在 ./tinyalsa_hal/codec_config/config_list.h 文件中。Audio将获取config_route_table并根据声卡0和sound_card_name的名称设置路由route。
文件:./hardware/rockchip/audio/tinyalsa_hal/codec_config/config_list.h
71 struct alsa_sound_card_config sound_card_config_list[] = {
72 {
73 .sound_card_name = "RKRK616",
74 .route_table = &rk616_config_table,
75 },
76 {
77 .sound_card_name = "RK29RT3224",
78 .route_table = &rt3224_config_table,
79 },
80 {
81 .sound_card_name = "rockchiprt5640c",
82 .route_table = &rt5640_config_table,
83 },
84 {
85 .sound_card_name = "rockchipes8396c",
86 .route_table = &es8396_config_table,
87 },
88 {
89 .sound_card_name = "RK29RT3261",
90 .route_table = &rt3261_config_table,
91 },
92 {
93 .sound_card_name = "RK29WM8960",
94 .route_table = &wm8960_config_table,
95 },
96 {
97 .sound_card_name = "RKRT3224",
98 .route_table = &rt3224_config_table,
99 },
100 {
101 .sound_card_name = "RKRT3261",
102 .route_table = &rt3261_config_table,
103 },
104 {
105 .sound_card_name = "RKWM8960",
106 .route_table = &wm8960_config_table,
107 },
108 {
109 .sound_card_name = "RKRT5616",
110 .route_table = &rt5616_config_table,
111 },
112 {
113 .sound_card_name = "realtekrt5651co",
114 .route_table = &rt5651_config_table,
115 },
......
.route_table的引用对应在xxxx_config.h文件中有定义,例如.route_table = &rt5651_config_table在rt5651_config.h中。
文件:/hardware/rockchip/audio/tinyalsa_hal/codec_config/rt5651_config.h
1143 const struct config_route_table rt5651_config_table = {
1144 //speaker
1145 .speaker_normal = {
1146 .sound_card = 0,
1147 .devices = DEVICES_0,
1148 .controls = rt5651_speaker_normal_controls,
1149 .controls_count = sizeof(rt5651_speaker_normal_controls) / sizeof(struct config_control),
1150 },
1151 .speaker_incall = {
1152 .sound_card = 0,
1153 .devices = DEVICES_0,
1154 .controls = rt5651_speaker_incall_controls,
1155 .controls_count = sizeof(rt5651_speaker_incall_controls) / sizeof(struct config_control),
1156 },
......
然后再在.controls当中配置ctl_name和int_val,例如rt5651_speaker_normal_controls的配置,对应在kernel层会获取到这里的设置。
const struct config_control rt5651_speaker_normal_controls[] = {
99 {
100 .ctl_name = "RT5651 ASRC Switch",
101 .int_val = {1},
102 },
103
104 {
105 .ctl_name = "DAC MIXL INF1 Switch",
106 .int_val = {on},
107 },
108 {
109 .ctl_name = "DAC MIXR INF1 Switch",
110 .int_val = {on},
111 },
112 {
113 .ctl_name = "Stereo DAC MIXL DAC L1 Switch",
114 .int_val = {on},
115 },
116 {
117 .ctl_name = "Stereo DAC MIXR DAC R1 Switch",
118 .int_val = {on},
119 },
120 {
121 .ctl_name = "OUT MIXL DAC L1 Switch",
122 .int_val = {on},
123 },
124 {
125 .ctl_name = "OUT MIXR DAC R1 Switch",
126 .int_val = {on},
127 },
128 {
129 .ctl_name = "HPOVOL L Switch",
130 .int_val = {on},
131 },
132 {
133 .ctl_name = "HPOVOL R Switch",
134 .int_val = {on},
135 },
136 {
137 .ctl_name = "HPO MIX HPVOL Switch",
138 .int_val = {on},
139 },
140 {
141 .ctl_name = "HPO MIX HPVOL Switch",
142 .int_val = {on},
143 },
144 {
145 .ctl_name = "HPO L Playback Switch",
146 .int_val = {on},
147 },
148 {
149 .ctl_name = "HPO R Playback Switch",
150 .int_val = {on},
151 },
156 { .ctl_name = "LOUT MIX DAC L1 Switch", .int_val = {on}, },
157 { .ctl_name = "LOUT MIX DAC R1 Switch", .int_val = {on}, },
158
159 // SPEAKER_NORMAL_ROUTE HEADSET_NORMAL_ROUTE
160 { .ctl_name = "LOUT MIX OUTVOL L Switch", .int_val = {on}, },
161 { .ctl_name = "LOUT MIX OUTVOL R Switch", .int_val = {on}, },
162
163 { .ctl_name = "LOUT L Playback Switch", .int_val = {on}, },
164 { .ctl_name = "LOUT R Playback Switch", .int_val = {on}, },
165
166 //{ .ctl_name = "OUT Playback Volume", .int_val = {26, 26}, }, // 31 31
167
168 { .ctl_name = "DAC1 Playback Volume", .int_val = {128, 128}, }, // {136, 136} //这里是音量设置
};
hardware/rockchip/audio/tinyalsa_hal/codec_config/rt5651_config.h
const struct config_control rt5651_bluetooth_voip_controls[] = {
// init IN2p/n for line in input.
const struct config_control rt5651_line_in_capture_controls[] = {
// try run it first, to fix conflict
{ .ctl_name = "RECMIXL INL1 Switch", .int_val = {on}, }, //Replace mic: conf for L.in.L used
{ .ctl_name = "RECMIXR INR1 Switch", .int_val = {on}, }, //Replace mic: conf for L.in.R used
{ .ctl_name = "RECMIXL BST2 Switch", .int_val = {off}, }, // close conf for micL used
{ .ctl_name = "RECMIXR BST2 Switch", .int_val = {off}, }, // close conf for micR used
{ .ctl_name = "RECMIXL BST1 Switch", .int_val = {off}, },
{ .ctl_name = "RECMIXR BST1 Switch", .int_val = {off}, },
{ .ctl_name = "RECMIXL BST3 Switch", .int_val = {off}, },
{ .ctl_name = "RECMIXR BST3 Switch", .int_val = {off}, },
{ .ctl_name = "Stereo1 ADC L1 Mux", .str_val = "ADC", },
{ .ctl_name = "Stereo1 ADC R1 Mux", .str_val = "ADC", },
{ .ctl_name = "Stereo1 ADC MIXL ADC1 Switch", .int_val = {on}, },
{ .ctl_name = "Stereo1 ADC MIXR ADC1 Switch", .int_val = {on}, },
{ .ctl_name = "ADC Capture Switch", .int_val = {on, on}, },
{ .ctl_name = "IN2 Boost", .int_val = {2}, },
{ .ctl_name = "ADC Capture Volume", .int_val = {47, 47}, },
// if you feel vol is low/high, can adjust it from 37 to 80. [63 is copied from rt5616]
{ .ctl_name = "ADC Capture Volume", .int_val = {63, 63}, }, // {57, 57} {47, 47} //这里调节音量值设置
#### route_pcm_open()
#### -> get_route_config(route)
#### -> route_set_controls()
#### -> route_pcm_close()
#### -> route_set_controls()
->
1、通过看 kernel log 确认 alsa sound card 有没有注册。
rk3288_mid:/ $ dmesg | grep ALSA -EC5
[ 1.551902] I : [File] : drivers/gpu/arm/mali400/mali/linux/mali_kernel_linux.c; [Line] : 417; [Func] : mali_module_init(); svn_rev_string_from_arm of this mali_ko is '-cf8da18', rk_ko_ver is '5', built at '11:19:29', on 'Jan 15 2020'.
[ 1.553256] Mali: Mali device driver loaded
[ 1.554211] of_get_named_gpiod_flags: parsed 'gpios' property of node '/rockchip-key/power-key[0]' - status (0)
[ 1.554274] of_get_named_gpiod_flags: parsed 'gpios' property of node '/rockchip-key/power-key[0]' - status (0)
[ 1.554741] input: rk29-keypad as /devices/platform/rockchip-key/input/input2
[ 1.556689] ALSA device list:
[ 1.556778] #0: realtek,rt5651-codec
[ 1.556977] #1: rk,hdmiin-tc358749x-codec
[ 1.557280] #2: rockchip,hdmi
[ 1.557312] #3: rockchip-cdndp-sound
[ 1.565498] mmc_host mmc2: Bus speed (slot 0) = 150000000Hz (slot req 150000000Hz, actual 150000000HZ div = 0)
2、确认 route 是否正常
声卡注册好之后确认 alsa route 是否正确
通过命令 logcat -s alsa_route
rk3288_mid:/ $ logcat -s alsa_route
--------- beginning of system
--------- beginning of main
01-01 01:19:51.274 255 324 D alsa_route: route_set_controls() set route 24
01-01 01:38:30.866 255 324 D alsa_route: route_info->sound_card 0, route_info->devices 0
01-01 01:38:30.866 255 324 D alsa_route: route_set_controls() set route 0
01-01 01:38:34.105 255 324 D alsa_route: route_set_controls() set route 24
01-01 01:38:35.655 255 324 D alsa_route: route_info->sound_card 0, route_info->devices 0
01-01 01:38:35.656 255 324 D alsa_route: route_set_controls() set route 0
01-01 01:39:23.035 255 324 D alsa_route: route_set_controls() set route 24
上面命令跑了两个路由 route 0 route 24。route的宏定义在alsa_audio.h中。
文件:hardware/rockchip/audio$ vi tinyalsa_hal/alsa_audio.h
62 typedef enum _AudioRoute {
63 SPEAKER_NORMAL_ROUTE = 0,
64 SPEAKER_INCALL_ROUTE, // 1
65 SPEAKER_RINGTONE_ROUTE,
66 SPEAKER_VOIP_ROUTE,
67
68 EARPIECE_NORMAL_ROUTE, // 4
69 EARPIECE_INCALL_ROUTE,
70 EARPIECE_RINGTONE_ROUTE,
71 EARPIECE_VOIP_ROUTE,
72
73 HEADPHONE_NORMAL_ROUTE, // 8
74 HEADPHONE_INCALL_ROUTE,
75 HEADPHONE_RINGTONE_ROUTE,
76 SPEAKER_HEADPHONE_NORMAL_ROUTE,
77 SPEAKER_HEADPHONE_RINGTONE_ROUTE,
78 HEADPHONE_VOIP_ROUTE,
79
80 HEADSET_NORMAL_ROUTE, // 14
81 HEADSET_INCALL_ROUTE,
82 HEADSET_RINGTONE_ROUTE,
83 HEADSET_VOIP_ROUTE,
84
85 BLUETOOTH_NORMAL_ROUTE, // 18
86 BLUETOOTH_INCALL_ROUTE,
87 BLUETOOTH_VOIP_ROUTE,
......
}AudioRoute;