之前转载过一篇文章-智能手机音频系统概述,描述了手机音频系统设计框图。实际上那是一个简单的做法,应用中有较大的局限性。那么一个完善的音频框架应该是什么样的呢?这两天根据Android4.0源码的一些线索,找到了相应的硬件资料,摘录下来。

注:以samsung tuna方案(即galaxy nexus)为例。

audio_hw

在ANDROID音频系统散记之四:4.0音频系统HAL初探中,提及到samsung的tuna方案,其实就是大名鼎鼎的galaxy nexus了。

android-4.0.3_r1\device\samsung\tuna\audio\audio_hw.c,这文件就是tuna的音频HAL了,从中我们看出:根据上层的音频策略打开/关闭相应的pcm设备。

[cpp] 
    view plain 
   copy 
  
 
 
1. struct
2.     .channels = 2,  
3.     .rate = MM_FULL_POWER_SAMPLING_RATE,  
4.     .period_size = LONG_PERIOD_SIZE,  
5.     .period_count = PLAYBACK_LONG_PERIOD_COUNT,  
6.     .format = PCM_FORMAT_S16_LE,  
7. };  
8.   
9. struct
10.     .channels = 2,  
11.     .rate = MM_FULL_POWER_SAMPLING_RATE,  
12.     .period_size = SHORT_PERIOD_SIZE,  
13.     .period_count = CAPTURE_PERIOD_COUNT,  
14.     .format = PCM_FORMAT_S16_LE,  
15. };  
16.   
17. struct
18.     .channels = 2,  
19.     .rate = VX_NB_SAMPLING_RATE,  
20.     .period_size = 160,  
21.     .period_count = 2,  
22.     .format = PCM_FORMAT_S16_LE,  
23. };  
 1、mm:media playback设备,即audio download link; 
2、mm_ul:audio record设备,即audio upload link;
3、vx:voice设备,通话模块的声音就是经过这个设备的。
根据上层声音模式audio_mode_t来选择打开不同的pcm设备,详细见select_mode()函数。
 audio_hw.c还定义了各种音频路径(音频路径概念见:DAPM之二:audio paths与dapm kcontrol)。
 
 
   [cpp] 
    view plain 
   copy 
  
 
 
1. struct
2.     {  
3.         .ctl_name = MIXER_HF_LEFT_PLAYBACK,  
4.         .strval = MIXER_PLAYBACK_HF_DAC,  
5.     },  
6.     {  
7.         .ctl_name = MIXER_HF_RIGHT_PLAYBACK,  
8.         .strval = MIXER_PLAYBACK_HF_DAC,  
9.     },  
10.     {  
11.         .ctl_name = NULL,  
12.     },  
13. };  
14.   
15. struct
16.     {  
17.         .ctl_name = MIXER_HS_LEFT_PLAYBACK,  
18.         .strval = MIXER_PLAYBACK_HS_DAC,  
19.     },  
20.     {  
21.         .ctl_name = MIXER_HS_RIGHT_PLAYBACK,  
22.         .strval = MIXER_PLAYBACK_HS_DAC,  
23.     },  
24.     {  
25.         .ctl_name = NULL,  
26.     },  
27. };  
28. // ......
 1、hf_output:headfree输出路径; 
2、hs_output:headset输出路径;
3、......
根据上层的audio_devices_t选择打开或关闭对应的音频路径部件,如:
 
 
   [cpp] 
    view plain 
   copy 
  
 
 
1. // ...
2. headset_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADSET;  
3. headphone_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;  
4. // ...
5. set_route_by_array(adev->mixer, hs_output, headset_on | headphone_on);  
6. set_route_by_array(adev->mixer, hf_output, speaker_on);  
7. // ...
 

 以上的mode和device都是由Android更上一层的音频策略所决定的,不在本模块的讨论范畴,这里仅需要按照音频策略来打开正确的音频通道。 

kernel
如我们所知,galaxy nexus用的是omap4460,音频芯片是twl6040。因此我们下载omap的kernel代码:
 
 
   [plain] 
    view plain 
   copy 
  
 
 
1. $ git clone https://android.googlesource.com/kernel/omap.git

详见:

http://source.android.com/source/downloading.html

就本篇的讨论内容来看,我们只需关注如下几个源文件:

1、sound\soc\codecs\twl6040.c

2、sound\soc\omap\omap-abe-dsp.c和sound\soc\omap\omap-abe.c

twl6040.c是音频芯片twl6040的驱动代码,这部分是通用的;

omap-abe是omap4460的音频后端处理(Audio Back-End)驱动代码,这是平台相关的。结合后面的硬件框图来看,就会明白audio_hw很大程度是直接控制abe。

其中omap的dsp代码是以firmware的形式提供的,因此omap-abe-dsp.c用于调用dsp的接口函数。

hardware diagram

omap4460数据手册及设计资料如下:

datasheet:http://www.ti.com/general/docs/wtbu/wtbuproductcontent.tsp?templateId=6123&navigationId=12843&contentId=53243

ABE:http://focus.ti.com/pdfs/wtbu/OMAP4430_ES2%20x_4460_ES1%200_PUBLIC_TRM_Addendum_ABE_HAL_vC.pdf

音频系统框图如下:

左边是OMAP的ABE,右边是codec twl4060,由此可知:音频先经过OMAP ABE的处理,再送到codec输出。

通话下行路径:ABE[VX_DL -> DL_Mixer -> ...] -> PDM_DL -> CODEC[DAC -> Earpiece/Headfree/Headset]

其中在ABE端还要经过一些EQ、Gain、SRC、Echo部件,这里不一一列出了。可见OMAP ABE是非常复杂的一个模块,声音在这里处理好之后才送到CODEC,相比之下CODEC端的工作就简单多了。