試探Galaxy的音頻設計框架

http://blog.csdn.net/sepnic/article/details/7307506

之前轉載過一篇文章-智能手機音頻系統概述,描述了手機音頻系統設計框圖。實際上那是一個簡單的做法,應用中有較大的侷限性。那麼一個完善的音頻框架應該是什麼樣的呢?這兩天根據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設備。

  1. struct pcm_config pcm_config_mm = {  
  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 pcm_config pcm_config_mm_ul = {  
  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 pcm_config pcm_config_vx = {  
  18.     .channels = 2,  
  19.     .rate = VX_NB_SAMPLING_RATE,  
  20.     .period_size = 160,  
  21.     .period_count = 2,  
  22.     .format = PCM_FORMAT_S16_LE,  
  23. };  
struct pcm_config pcm_config_mm = {
    .channels = 2,
    .rate = MM_FULL_POWER_SAMPLING_RATE,
    .period_size = LONG_PERIOD_SIZE,
    .period_count = PLAYBACK_LONG_PERIOD_COUNT,
    .format = PCM_FORMAT_S16_LE,
};

struct pcm_config pcm_config_mm_ul = {
    .channels = 2,
    .rate = MM_FULL_POWER_SAMPLING_RATE,
    .period_size = SHORT_PERIOD_SIZE,
    .period_count = CAPTURE_PERIOD_COUNT,
    .format = PCM_FORMAT_S16_LE,
};

struct pcm_config pcm_config_vx = {
    .channels = 2,
    .rate = VX_NB_SAMPLING_RATE,
    .period_size = 160,
    .period_count = 2,
    .format = PCM_FORMAT_S16_LE,
};
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)。

  1. struct route_setting hf_output[] = {  
  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 route_setting hs_output[] = {  
  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. // ......  
struct route_setting hf_output[] = {
    {
        .ctl_name = MIXER_HF_LEFT_PLAYBACK,
        .strval = MIXER_PLAYBACK_HF_DAC,
    },
    {
        .ctl_name = MIXER_HF_RIGHT_PLAYBACK,
        .strval = MIXER_PLAYBACK_HF_DAC,
    },
    {
        .ctl_name = NULL,
    },
};

struct route_setting hs_output[] = {
    {
        .ctl_name = MIXER_HS_LEFT_PLAYBACK,
        .strval = MIXER_PLAYBACK_HS_DAC,
    },
    {
        .ctl_name = MIXER_HS_RIGHT_PLAYBACK,
        .strval = MIXER_PLAYBACK_HS_DAC,
    },
    {
        .ctl_name = NULL,
    },
};
// ......
1、hf_output:headfree輸出路徑;

2、hs_output:headset輸出路徑;

3、......

根據上層的audio_devices_t選擇打開或關閉對應的音頻路徑部件,如:

  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. // ...  
// ...
headset_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
headphone_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
// ...
set_route_by_array(adev->mixer, hs_output, headset_on | headphone_on);
set_route_by_array(adev->mixer, hf_output, speaker_on);
// ...


以上的mode和device都是由Android更上一層的音頻策略所決定的,不在本模塊的討論範疇,這裏僅需要按照音頻策略來打開正確的音頻通道。

另外有一個我非常疑惑的地方:tuna的audio_hw.c中選用的採樣率是48khz,但是Android的framework層是先SRC到44.1khz的,因此這會犯高通同樣的錯誤-雙重SRC(48khz->44.1khz->48khz),對音質的損害非常大。爲什麼不直接使用44.1khz的採樣率呢?


kernel


如我們所知,galaxy nexus用的是omap4460,音頻芯片是twl6040。因此我們下載omap的kernel代碼:

  1. $ git clone https://android.googlesource.com/kernel/omap.git  
$ 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端的工作就簡單多了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章