RK3288_Android7.1在HAL层audio音频通路小结
这里先说下rk3288 HDMIin音频通路:
hdmiin:
HDMIIn声音直接通过codec输出到喇叭、耳机,不需要送到主控进行处理:
TC358749XBG-> alc5651 i2s2 -> alc5651 dac -> hp/lineout
alsa HAL 层
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 audio route通路介绍
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;
HAL层通过一定转换跟android上层对应
在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.h1110 const struct config_route_table rt5651_config_table = {1111 //speaker1112 .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[] = {5657 {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.c89 /**90 * @brief route_init91 *92 * @returns93 */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是第0个声卡,串口执行cat /proc/asound/card0/id可以查看
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。
rk3288:/ # cat /proc/asound/card0/id
realtekrt5651co
文件:./hardware/rockchip/audio/tinyalsa_hal/codec_config/config_list.h71 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 },103104 {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}, },158159 // SPEAKER_NORMAL_ROUTE HEADSET_NORMAL_ROUTE160 { .ctl_name = "LOUT MIX OUTVOL L Switch", .int_val = {on}, },161 { .ctl_name = "LOUT MIX OUTVOL R Switch", .int_val = {on}, },162163 { .ctl_name = "LOUT L Playback Switch", .int_val = {on}, },164 { .ctl_name = "LOUT R Playback Switch", .int_val = {on}, },165166 //{ .ctl_name = "OUT Playback Volume", .int_val = {26, 26}, }, // 31 31167168 { .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()->
如何debug
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.h62 typedef enum _AudioRoute {63 SPEAKER_NORMAL_ROUTE = 0,64 SPEAKER_INCALL_ROUTE, // 165 SPEAKER_RINGTONE_ROUTE,66 SPEAKER_VOIP_ROUTE,6768 EARPIECE_NORMAL_ROUTE, // 469 EARPIECE_INCALL_ROUTE,70 EARPIECE_RINGTONE_ROUTE,71 EARPIECE_VOIP_ROUTE,7273 HEADPHONE_NORMAL_ROUTE, // 874 HEADPHONE_INCALL_ROUTE,75 HEADPHONE_RINGTONE_ROUTE,76 SPEAKER_HEADPHONE_NORMAL_ROUTE,77 SPEAKER_HEADPHONE_RINGTONE_ROUTE,78 HEADPHONE_VOIP_ROUTE,7980 HEADSET_NORMAL_ROUTE, // 1481 HEADSET_INCALL_ROUTE,82 HEADSET_RINGTONE_ROUTE,83 HEADSET_VOIP_ROUTE,8485 BLUETOOTH_NORMAL_ROUTE, // 1886 BLUETOOTH_INCALL_ROUTE,87 BLUETOOTH_VOIP_ROUTE,
......
}AudioRoute;
RK3288_Android7.1在HAL层audio音频通路小结相关推荐
- Android Audio音频通路(七)
android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...
- Qualcomm Audio HAL 音频通路设置
1. 音频框图概述 | Front End PCMs | SoC DSP | Back End DAIs | Audio devices |************* PCM0 <------- ...
- RK Audio HAL 音频通路设置与Codec原理
由 b178903294创建, 最后修改于3月 18, 2020 一个平板项目中采用螃蟹卡ALC56561 作为硬件codec.由于声音播放前后过程中有pop声,所以对其硬件原理和驱动控制做了一番研究 ...
- Qualcomm Audio HAL 音频通路设置(基于8996平台)
1. 音频框图概述 | Front End PCMs | SoC DSP | Back End DAIs | Audio devices |************* PCM0 <------- ...
- Qualcomm Audio HAL 音频通路设置【转】
本文转载自:https://blog.csdn.net/azloong/article/details/79383323 1. 音频框图概述 | Front End PCMs | SoC DSP | ...
- Android9 Audio模块Hal层加载流程及修改方法
摘要:在Android9中Audio模块调用Hal一般有两种路径: 1.通过AudioFlinger调用到Hal,这是众多原生接口走的路径,一般我们不会在这里增加方法,但是会修改这里面的方法 2.如果 ...
- android音频hal层简介
如下图为android音频hal层所处的位置: 从上图可以看出,HAL层下面使用TiniAlsa(Android下一个简约的Alsa版本).HAL层分为两部分,一部分为各种音频设备,每种音频设备由一个 ...
- Android Audio 服务层与HAL层之间的接口分析 Service<->interface<->HAL
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.AudioFlinger 二.服务层接口分析 2.1由DevicesFactoryHalInterface可以找到Dev ...
- <一>Android Audio音频框架
目录 1.0 设备驱动 2.0 android hal层 3.0 选择设备的暗箱策略AudioPolicy 4.0 软件层面的混音,AudioFlinger 5.0 完整的对外接口 AudioS ...
- 理解 Audio 音频系统二 之 audioserver AudioPolicyService
理解 Audio 音频系统二 之 AudioPolicyService 二.audioserver & AudioPolicyService + AudioPolicy 启动流程总结 1. A ...
最新文章
- MySQL优化篇:show profile进行SQL分析
- MFC调用批处理文件(.bat)
- 基于ARM的Qt Creator嵌入式开发环境搭建
- Careers support for Masters students cambridge
- 客户端本地存储的比较及使用window.name数据传输
- 自称比特币创造者中本聪,如今这人被法官怒怼作伪证!
- 再送 5000 份红包封面!
- 深入浅出 Python Iterators 迭代器
- 女生学计算机和遥感哪个好就业,遥感科学与技术有性别歧视吗知乎
- Jeecg-Boot 使用技巧
- linux etc xdg,Xdg-menu (简体中文)
- 关于常用第三方统计平台比较
- 天涯上拣来的爱情哲学
- openBSD安装桌面
- ajax发送put请求参数,请求参数和PUT方法(Request params and PUT method)
- python get pip.py_get-pip.py 安装
- Rainbow 开发 step1
- java编写购书系统
- 新加坡首富张勇的烦恼
- 大数据技术原理与应用作业七
热门文章
- 同步异步-阻塞非阻塞
- c++程序设计原理与实践 第二十四章部分答案
- enumerateObjectsUsingBlock 、for 、for(... in ...) 的区别 性能测试
- Delphi 正则表达式语法(2): 或者与重复
- 【往届已EI稳定检索】第二届计算机科学与管理科技国际学术会议,多主题征稿!...
- 字节跳动 AI Lab 21届校招启动啦!
- NLP基础—3.文本表示
- 深度学习2.0-26.Regularization减轻overfitting
- 深度学习2.0-12.神经网络与全连接层之数据集的加载
- 梯度消失与梯度爆炸原因剖析