RK3288_Android7.1 in HAL layer audio audio channel summary

Let’s talk about the rk3288 HDMIin audio channel first:

hdmiin:
The HDMIIn sound is directly output to the speaker and earphone through the codec, and does not need to be sent to the main control for processing:
TC358749XBG -> alc5651 i2s2 -> alc5651 dac -> hp/lineout

alsa HAL layer

RK platform android 5.1 BOX MID SDK will uniformly use the code under this directory
\hardware\rockchip\audio\tinyalsa_hal

The audio system of embedded devices can be divided into three parts: onboard hardware (Machine), Soc (Platform), and Codec

1. Audio codec Codec is responsible for processing audio information, including ADC, DAC, Mixer, DSP, input and output, and volume control, etc.
Audio-related functions.
Codec and processor communicate through I2C bus and digital audio interface DAI.
I2C bus – to read and write Codec register data.

2. DAI – (digital audio interface) realizes the communication of audio data between CPU and Codec, including I2S, PCM and AC97
wait.
The bluetooth stereo music player uses the direct UART interface between bluetooth and CPU.
On the master with only one set of I2S, the Bluetooth call SCO is temporarily relayed through the Codec, that is, the routing selection through the Codec is
If you don’t use the call, you use the I2S interface. If the main control has two sets of I2S, then the BT PCM can be directly connected to the PCM interface of the main control
verbal.
S/DIF (Sony/Philips Digital Interface Format), transmits audio through optical fiber or coaxial cable to ensure audio quality.

Codec internal path example RK616

At the same time, the audio driver has three parts:
Machine driver
sound/soc/rockchip/rk_rk616.c
The Machine driver is responsible for the coupling between Platform and Codec as well as part and device or board-specific code sampling rate
clock configuration

Platform driver
sound/soc/rockchip/rk30_i2s.c
I2S Controller Driver Sample Rate Clock DMA etc Configuration

Codec driver
sound/soc/codecs/rk616_codec.c
Configuration of the register path of the codec

Android audio route introduction

Android defines a lot of audio devices: in the frameworks/base/media/java/android/media/AudioSystem.java file

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;

The HAL layer corresponds to the upper layer of android through a certain conversion

In hardware/rockchip/audio/tinyalsa_hal/alsa_route.c, use get_route_config(int route) in route_set_controls(route) to convert the above route values into the xxx.h configuration file in codec_config.

File: ./hardware/rockchip/audio/tinyalsa_hal/alsa_route.c
282 const struct config_route *get_route_config(unsigned route) //Get the audio routing device here
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);
?…

The route table defined in the HAL layer, and then configure these tables through route_set_controls, and finally set them to the codec register

 file: ./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 },
?…
\t\t
48 const struct config_control rt5651_speaker_normal_controls[] = {<!-- -->
\t
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

The HAL layer will choose which table to use according to the sound card name, if there is no match, default_config.h will be used by default

File: ./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"); //id is the 0th sound card, execute cat /proc/asound/card0/id on the serial port to view
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] == '\
') {<!-- -->
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, //Choose which table to use according to the sound card name
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 = & amp;default_config_table; //If there is no match, default_config.h will be used by default
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}

The declaration of the sound card name of the HAL layer sound card name and the configuration table list table is in the ./tinyalsa_hal/codec_config/config_list.h file. Audio will get the config_route_table and set the route based on sound card 0 (the first in the list of recognized sound cards) and the name of sound_card_name.
rk3288:/ # cat /proc/asound/card0/id
realtekrt5651co

File: ./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 = "rockchips8396c",
 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 },
?…

The reference of .route_table is defined in the xxxx_config.h file, for example, .route_table = & rt5651_config_table is in rt5651_config.h.

 file: /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 },
?…

Then configure ctl_name and int_val in .controls, such as the configuration of rt5651_speaker_normal_controls, corresponding to the settings here will be obtained in the kernel layer.

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} //Here is the volume setting

};

Volume value adjustment:

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} //here Adjust the volume value setting

Audio open call process:

#### route_pcm_open()
#### -> get_route_config(route)
#### -> route_set_controls()
#### -> route_pcm_close()
#### -> route_set_controls()
->

How to debug

1. Check the kernel log to confirm whether the alsa sound card is registered.

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. Confirm whether the route is normal
After the sound card is registered, confirm whether the alsa route is correct
Through the command 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

The above command runs two routes route 0 route 24. The macro definition of route is in alsa_audio.h.

File: 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;