1、 福州瑞芯微电子有限公司 密级状态:绝密 ( ) 秘密 ( ) 内部 ( ) 公开 ( ) RK音频简介以及常见问题 debug方法 (技术部 ) 文件状态: 正在修改 正式发布 当前版本: V1.1 作 者: 罗肖谭 完成日期: 2016-5-5 审 核: 完成日期: 福州瑞芯微电子有限公司 Fuzhou Rockchips Semiconductor Co . , Ltd (版本所有 ,翻版必究 ) 福州瑞芯微电子有限公司 版 本 历 史 版本号 作者 修改日期 修改说明 备注 V1.0 Lxt 2015-10-13 初始版本 V1.1 Lxt 2016-5-5 福州瑞芯微电子有限公司 1
2、 目目 录录 音频系统基本硬件电路 . 2 SOUND CARD 驱动配置相关代码 . 5 ALSA HAL 层 . 7 ANDROID AUDIO ROUTE 通路介绍 . 8 如何 DEBUG 13 第一步首先看 声卡有没有注册 13 第二步 确认 ROUTE 是否正常 13 CODEC CONFIG LIST 配置说明举例 15 一般 route 的错误 17 如何调试新的 SOUND CARD 驱动 24 第一步看 CODEC 芯片资料 24 CODEC 需要通路的配置 25 以 es8323 为例调试新的驱动 25 蓝牙通话 3G 通话的方案 DEBUG . 30 312X 平台 C
3、ODEC DEBUG 30 POP 音问题 . 30 关于 ALC 功能 . 31 关于降噪算法 . 31 ALSA 的上层应用程序 . 32 福州瑞芯微电子有限公司 2 音频系统基本硬件电路 音频编解码器 Codec 负责处理音频信息,包括 ADC,DAC,Mixer,DSP,输入输出以及音量控制等所有与音频相关的功能。 Codec 与处理器之间通过 I2C 总线和数字音频接口 DAI 进行通信。 I2C 总 线 - 实现对 Codec 寄存器数据的读写。 DAI ( digital audio interface) 实现音频数据在 CPU 和 Codec 间的通信,包括 I2S、 PCM
4、和 AC97等。 蓝牙立体声音乐播放走的是蓝牙跟 CPU 直接的 UART 接口。 在只有一组 I2S 的主控上面, 蓝牙通话 SCO 暂时是通过 Codec 中继,即通过 codec 来路由选择是否走通话,走的是 I2S 接口 。如果主控有两组 I2S,那么可以将 BT PCM 直接接到主控的 PCM 接口上。 S/DIF( Sony/Philips Digital Interface Format),通过光纤或同轴电缆传输音频,保证音频质量。 Codec 内部通路举例 RK616 福州瑞芯微电子有限公司 3 录音通路 MIC1N/P -BST-L-MUXMIC- MIXIN_L-PGAL-
5、ADCL-I2S SDI-主控 放音 通路 主控 - I2S SDO-DACL-HPMIX-SPKL-喇叭 I2S 信号如下 主从模式 : 福州瑞芯微电子有限公司 4 下图描述的是 RK 8channel 的 i2s 时序格式,一般使用 I2S0_SDO0 I2S0_SDI0 作为一组引出到外部 codec 使用形成左右声 道的输入输出立体声效果。 关于 7.1 声道: 7.1 声道输出,是需要使用 I2S0_SDO0I2S0_SDO3 共 4 组数据线组成 8 声道的音频数据,这里主要给 HDMI 用形成 7.1 声道 输出 ,同时 7.1 声道的话还需要播放器解码器音频源等支持,目前在 B
6、OX SDK 上面 可以通过透传的方式支持 HDMI 输出 7.1 声道, MID 不支持 。 关于采样率和采样深度 目前我们 MID Android 系统的支持的最大采样率是 48K 16bit, 这个主要是限制是在 android framework 包括 解码器和 audio flinger 等, linux 软件驱动是可以支持 192K 32bit 等高采样率高精度的音频格式。 关于 HIFI 播放器 (高采样率高精度 一般要支持 192K 24 BIT WAV FLAC 等无损播放) 方案一 3188 4.2 的 SDK 上面有做过 192K 24bit 的 HIFI 播放器,主要是
7、更改系统的解码器 audio flinger HAL 层以及 linux sound card 驱动, 优点是使用系统的 api 即可播放 hifi 福州瑞芯微电子有限公司 5 音频,缺点是 SDK 到 4.4 更新之后无法再 使用。 另外一种方案是 不使用系统提供的 api 接口,可以自己实现 hifi 播放器,使用 ffmpeg 解码器,将 ffmpeg 解码出来的 PCM 数据通过 alsa 接口写到声卡实现 HiFi 播放,当然这个也需要声卡驱动的支持。 优点是 SDK 升级之后还可以使用,因为是不依赖于 android 系统的 api。 Sound card 驱动配置相关代码 Dts
8、 Dts 里面主要是一些资源的配置,例如 161 rockchip-es8323 162 compatible = “rockchip-es8323“; 163 dais 164 dai0 165 audio-codec = ; 166 i2s-controller = ; 167 format = “i2s“; 168 /continuous-clock; 169 /bitclock-inversion; 170 /frame-inversion; 171 /bitclock-master; 172 /frame-master; 173 ; 174 ; 175 ; 553 555 rt563
9、1: rt56311a 556 compatible = “rt5631“; 557 reg = ; 558 ; 559 es8323: es832310 560 compatible = “es8323“; 福州瑞芯微电子有限公司 6 561 reg = ; 562 ; Sound Config ALSA 驱动目录结构 lxtrksz-server101:/rk312x-sdk-4.4.4/kernel/sound$ tree -L 1 ac97_bus.c aoa arm atmel built-in.mod.c built-in.o core drivers firewire i2c i
10、sa Kconfig last.c last.o Makefile mips oss parisc pci pcmcia ppc sh soc sound_core.c soundcore.mod.c sound_core.o soundcore.o sound_firmware.c sparc spi synth 福州瑞芯微电子有限公司 7 usb 20 directories, 13 files 嵌入式设备的音频系统可以被划分为板载硬件( Machine)、 Soc( Platform)、 Codec 三大部分 同时音频驱动有三部分: Machine driver sound/soc/ro
11、ckchip/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 的 寄存器通路的 配置 想要 深入了解 alsa 驱动 最后的办法是阅读 kernel 代码 这个 blog 写的不错 http:/ alsa HAL 层 android 5.1 BOX MID
12、 的 SDK 之后统一使用这个目录下面的代码 hardwarerockchipaudiotinyalsa_hal 4.4 MID HAL 代码路径 hardwarerk29audio 4.4 BOX HAL 代码路径 福州瑞芯微电子有限公司 8 hardwarealsa_sound android audio route 通路介绍 android 定义了很多的音频 devices 如 AudioSystem .java 中: 211 / output devices, be sure to update AudioManager.java also 212 public static fina
13、l int DEVICE_OUT_EARPIECE = 0x1; 213 public static final int DEVICE_OUT_SPEAKER = 0x2; 214 public static final int DEVICE_OUT_WIRED_HEADSET = 0x4; 215 public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8; 216 public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10; 217 public static final int DE
14、VICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20; 218 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40; 219 public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80; 220 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100; 221 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPE
15、AKER = 0x200; 222 public static final int DEVICE_OUT_AUX_DIGITAL = 0x400; 223 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800; 224 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000; 225 public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000; 226 public static final int DE
16、VICE_OUT_USB_DEVICE = 0x4000; 227 public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000; HAL 层通过一定转换跟 android 上层 对应 在 audio/alsa_route.c 中通过 route_set_controls(route)中通过 get_route_config(int route)将以上的各个 route 值转换为 codec_config中的 xxx.h 配置文件 const struct config_route *get_route_config(unsigned ro
17、ute) ALOGV(“get_route_config() route %d“, route); if (!route_table) ALOGE(“get_route_config() route_table is NULL!“); 福州瑞芯微电子有限公司 9 return NULL; switch (route) case SPEAKER_NORMAL_ROUTE: return case SPEAKER_INCALL_ROUTE: return case SPEAKER_RINGTONE_ROUTE: return case SPEAKER_VOIP_ROUTE: return case
18、 EARPIECE_NORMAL_ROUTE: return case EARPIECE_INCALL_ROUTE: return case EARPIECE_RINGTONE_ROUTE: return case EARPIECE_VOIP_ROUTE: return case HEADPHONE_NORMAL_ROUTE: return case HEADPHONE_INCALL_ROUTE: return case HEADPHONE_RINGTONE_ROUTE: HAL 层中定义 的 route table,在通过 route_set_controls 将这些 table 配置,最终
19、设置到 codec 的寄存器 struct config_route_table const struct config_route speaker_normal; const struct config_route speaker_incall; const struct config_route speaker_ringtone; const struct config_route speaker_voip; const struct config_route earpiece_normal; const struct config_route earpiece_incall; 福州瑞芯微
20、电子有限公司 10 const struct config_route earpiece_ringtone; const struct config_route earpiece_voip; const struct config_route headphone_normal; const struct config_route headphone_incall; const struct config_route headphone_ringtone; const struct config_route speaker_headphone_normal; const struct confi
21、g_route speaker_headphone_ringtone; const struct config_route headphone_voip; const struct config_route headset_normal; const struct config_route headset_incall; const struct config_route headset_ringtone; const struct config_route headset_voip; const struct config_route bluetooth_normal; const stru
22、ct config_route bluetooth_incall; const struct config_route bluetooth_voip; const struct config_route main_mic_capture; const struct config_route hands_free_mic_capture; const struct config_route bluetooth_sco_mic_capture; const struct config_route playback_off; const struct config_route capture_off
23、; const struct config_route incall_off; const struct config_route voip_off; const struct config_route hdmi_normal; const struct config_route usb_normal; const struct config_route usb_capture; const struct config_route spdif_normal; ; HAL 层会根据 sound card name 选择使用哪个 table,如果没有匹配默认使用 default_config.h
24、struct alsa_sound_card_config sound_card_config_list = .sound_card_name = “RKRK616“, 福州瑞芯微电子有限公司 11 .route_table = case RCV: 原先 tinyalsa关闭 incall时会调用, HAL层修改后,现在不会调用。 break; case SPK_PATH: case RING_SPK: 开启喇叭播放音乐通路 break; case HP_PATH: case HP_NO_MIC: case RING_HP: case RING_HP_NO_MIC: 开启耳机播放音乐通路 br
25、eak; case BT: 蓝牙播放音乐通路不会调用 Playback Path,这边不做处理 break; case SPK_HP: case RING_SPK_HP: 开启耳机、喇叭同时播放音乐通路 break; default: return -EINVAL; return 0; 福州瑞芯微电子有限公司 13 如何 debug 第一步首先看 声卡有没有注册 通过看 kernel log 确认 alsa sound card 有没有注册 2.713102 Enter:rk29_rt3261_init-218 2.721654 asoc: rt5639-aif1 rk29_i2s.1 map
26、ping ok 2.728488 asoc: rt5639-aif2 rk29_i2s.1 mapping ok 2.729289 ALSA device list: 2.729318 #0: RK29_RT5639 声卡没有注册参考 Audio 部分常见问题处理方法 声卡注册问题 debug。 第二步 确认 route 是否正常 声卡注册好之后确认 alsa route 是否正确 通过命令 logcat -s alsa_route rootHCTT1:/ # logcat -s alsa_route logcat -s alsa_route - beginning of /dev/log/s
27、ystem - beginning of /dev/log/main D/alsa_route( 90): route_info-sound_card 0, route_info-devices 0 E/alsa_route( 90): route_pcm_open() DEVICES_0 D/alsa_route( 90): route_set_controls() set route 0 E/alsa_route( 90): route_pcm_close()route 24 D/alsa_route( 90): route_set_controls() set route 24 上面 命
28、令跑了两个路由 route 0 route 24 各个 route 表示的意义 在 hardwarerk29audio alsa_audio.h 中定义,表示打开了一次 speaker 后面又关闭了一次 speaker typedef enum _AudioRoute SPEAKER_NORMAL_ROUTE = 0, SPEAKER_INCALL_ROUTE, / 1 SPEAKER_RINGTONE_ROUTE, SPEAKER_VOIP_ROUTE, EARPIECE_NORMAL_ROUTE, / 4 EARPIECE_INCALL_ROUTE, 福州瑞芯微电子有限公司 14 EARP
29、IECE_RINGTONE_ROUTE, EARPIECE_VOIP_ROUTE, HEADPHONE_NORMAL_ROUTE, / 8 HEADPHONE_INCALL_ROUTE, HEADPHONE_RINGTONE_ROUTE, SPEAKER_HEADPHONE_NORMAL_ROUTE, SPEAKER_HEADPHONE_RINGTONE_ROUTE, HEADPHONE_VOIP_ROUTE, HEADSET_NORMAL_ROUTE, / 14 HEADSET_INCALL_ROUTE, HEADSET_RINGTONE_ROUTE, HEADSET_VOIP_ROUTE,
30、 BLUETOOTH_NORMAL_ROUTE, / 18 BLUETOOTH_INCALL_ROUTE, BLUETOOTH_VOIP_ROUTE, MAIN_MIC_CAPTURE_ROUTE, / 21 HANDS_FREE_MIC_CAPTURE_ROUTE, BLUETOOTH_SOC_MIC_CAPTURE_ROUTE, PLAYBACK_OFF_ROUTE, / 24 CAPTURE_OFF_ROUTE, INCALL_OFF_ROUTE, VOIP_OFF_ROUTE, HDMI_NORMAL_ROUTE, / 28 USB_NORMAL_ROUTE, / 29 USB_CAP
31、TURE_ROUTE, MAX_ROUTE, / 31 AudioRoute; 福州瑞芯微电子有限公司 15 Codec config list 配置说明举例 喇叭放音乐 下面 3项配置一样 .controls = rt3224_speaker_normal_controls, .controls = rt3224_speaker_ringtone_controls, .controls = rt3224_speaker_voip_controls, 3G 通话 喇叭配置,系统没有的话可不用配置 .controls = rt3224_speaker_incall_controls, earpi
32、ece 听筒暂时不用配置 .controls = rt3224_earpiece_normal_controls, .controls = rt3224_earpiece_incall_controls, .controls = rt3224_earpiece_ringtone_controls, .controls = rt3224_earpiece_voip_controls, 下面 6项是 3段, 4段耳机 耳机放音的通话配置 配置一样 .controls = rt3224_headphone_normal_controls, .controls = rt3224_headphone_v
33、oip_controls, .controls = rt3224_headphone_ringtone_controls, .controls = rt3224_headset_ringtone_controls, .controls = rt3224_headset_voip_controls, .controls = rt3224_headset_normal_controls, 福州瑞芯微电子有限公司 16 喇叭 耳机同时放音输出 配置一样 .controls = rt3224_speaker_headphone_normal_controls, .controls = rt3224_s
34、peaker_headphone_ringtone_controls, 耳机通话耳机放音配置 配置一样 .controls = rt3224_headphone_incall_controls, .controls = rt3224_headset_incall_controls, 蓝牙 PCM 的配置, 没有就填空 .controls = rt3224_bluetooth_normal_controls, .controls = rt3224_bluetooth_incall_controls, .controls = rt3224_bluetooth_voip_controls, 主板 M
35、IC 录音配置 .controls = rt3224_main_mic_capture_controls, 4端耳机录音配置具 .controls = rt3224_hands_free_mic_capture_controls, 蓝牙通话 mic输入 没有可不配置 .controls = rt3224_bluetooth_sco_mic_capture_controls, 关闭通路 .controls = rt3224_playback_off_controls, .controls = rt3224_capture_off_controls, .controls = rt3224_inca
36、ll_off_controls, 福州瑞芯微电子有限公司 17 .controls = rt3224_voip_off_controls, 一般 route 的错误 1)、 耳机喇叭切换 有误 这个时候需要确认耳机检测是否正常 通过 cat sys/class/switch/h2w/state 查看耳机插入状态: rootHCTT1:/sys/class/switch/h2w # cat state cat state 0 state ; 672 pinctrl-names = “default“; 673 pinctrl-0 = ; 674 io-channels = ; 675 /* 67
37、6 hook_gpio = ; 677 hook_down_type = ; /interrupt hook key down status 678 */ 福州瑞芯微电子有限公司 18 679 ; 680 三段 四段耳机的区分 有两种方案 一种是通过 adc 另外一种是通过 GPIO 区分是 3 段耳机还是 4段耳机插入 ,详情参考 RK android 带 MIC 耳机检测以及 hook-kernel.pdf 、 android 耳机监听路由切换 -framework-hal.pdf 通过 adc 来区分 dts 中配置 io-channels = ; 通过 GPIO 来区分 676 hoo
38、k_gpio = ; 677 hook_down_type = ; /interrupt hook key down status 如下所示是使用 GPIO 来区分 3,4 段耳机的插入, 耳机上按键按下获取松开 gpio 电平有高低变化系统可以通过这个变化 向系统 上报 按键 默认 media。 福州瑞芯微电子有限公司 19 2)、多声卡切换 系统默认支持 codec sound card card0 Hdmi(spdif) 为 card 1 插入 HDMI 时候系统会自动切换到 card1 可以通过 route 来确认 route =28 插 HDMI 不需要 进行声卡切换, 可以更改 f
39、ramework diff -git a/services/java/com/android/server/WiredAccessoryManager.java b/services/java/com/android/server/WiredAccessoryManager.java index c8d35102fb231e 100644 - a/services/java/com/android/server/WiredAccessoryManager.java + b/services/java/com/android/server/WiredAccessoryManager.java -
40、374,7 +374,7 final class WiredAccessoryManager implements WiredAccessoryCallbacks / / If the kernel does not have an “hdmi_audio“ switch, just fall back on the older / “hdmi“ switch instead. - uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0); +/* uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDM
41、I_AUDIO, 0); if (uei.checkSwitchExists() retVal.add(uei); else -385,7 +385,7 final class WiredAccessoryManager implements WiredAccessoryCallbacks Slog.w(TAG, “This kernel does not have HDMI audio support“); - +*/ return retVal; 或者 将 kernel 里面的 HDMI 读取到的 state 不进行上报 diff -git a/drivers/video/rockchip
42、/hdmi/rk_hdmi_task.c b/drivers/video/rockchip/hdmi/rk_hdmi_task.c index 6cdb9eb2ca862f 100755 - a/drivers/video/rockchip/hdmi/rk_hdmi_task.c 福州瑞芯微电子有限公司 20 + b/drivers/video/rockchip/hdmi/rk_hdmi_task.c -258,7 +258,7 void hdmi_work(struct work_struct *work) hdmi_dbg(hdmi-dev,“base_audio_support =%d,
43、sink_hdmi = %dn“,hdmi-edid.base_audio_suppo #ifdef CONFIG_SWITCH if(hdmi-edid.base_audio_support = 1 + switch_set_state( #endif #ifdef CONFIG_RK_HDMI_CTL_CODEC #ifdef CONFIG_MACH_RK_FAC Usb audio 为 card2 4.4 SDK 默 认支持 usb audio route =29 、 30, 5.1 之后的 SDK kernel 固定usb audio 为 card3,使用 google 原生的 usb
44、 audio hal。 /usb audio .usb_normal = .sound_card = 2, .devices = DEVICES_0, .controls_count = 0, , .usb_capture = .sound_card = 2, .devices = DEVICES_0, .controls_count = 0, , 3)、 两个声卡同时输出 需要同时向两个声卡同时 write audio data 即可, 4.4 的实例代码如下 : diff -git a/AudioHardware.cpp b/AudioHardware.cpp index bc2e5536
45、0df29e 100755 - a/AudioHardware.cpp 福州瑞芯微电子有限公司 21 + b/AudioHardware.cpp -84,6 +84,7 AudioHardware:AudioHardware() : mInit(false), mMicMute(false), mPcm(NULL), + mPcm1(NULL), mPcmOpenCnt(0), mMixerOpenCnt(0), mInCallAudioMode(false), -117,6 +118,10 AudioHardware:AudioHardware() TRACE_DRIVER_OUT + if
46、(mPcm1) + + route_pcm1_close(); + TRACE_DRIVER_IN(DRV_MIXER_CLOSE) route_uninit(); TRACE_DRIVER_OUT -685,6 +690,7 struct pcm *AudioHardware:openPcmOut_l() mPcmOpenCnt-; mPcm = NULL; + mPcm1 = route_pcm1_open(1, flags); return mPcm; -703,6 +709,8 void AudioHardware:closePcmOut_l() route_pcm_close(PLA
47、YBACK_OFF_ROUTE); TRACE_DRIVER_OUT mPcm = NULL; + route_pcm1_close(); + mPcm1= NULL; -987,7 +995,9 ssize_t AudioHardware:AudioStreamOutALSA:write(const void* buffer, size_t byte 福州瑞芯微电子有限公司 22 TRACE_DRIVER_IN(DRV_PCM_WRITE) + / ret = pcm_write(mHardware-getPcm(),(void*) p, bytes); ret = pcm_write(mHar