Android Audio框架

ASLA -Advanced Sound Linux Architecture
OSS -以前的Linux音頻體系結構,被ASLA取代併兼容
I2S/PCM/AC97 - Codec與CPU間音頻的通信協議/接口/總線
DAI - Digital Audio Interface 其實就是I2S/PCM/AC97
DAPM - Dynamic Audio Power Management

1) 播放音樂

這裏寫圖片描述

2) 錄音

這裏寫圖片描述

3)打電話

這裏寫圖片描述
這裏寫圖片描述

4) 通過藍牙打電話

這裏寫圖片描述
這裏寫圖片描述

Android系統上的音頻框架

這裏寫圖片描述

Framework

MediaPlayer和MediaRecorder
AudioTrack和AudioRecorder

Android系統還爲我們控制音頻系統提供了AudioManager、AudioService及AudioSystem類。這些都是framework爲便利上層應用開發所設計的。

libraries (AudioFlinger )

除了上面的類庫實現外,音頻系統還需要一個“核心中控”,或者用Android中通用的實現來講,需要一個系統服務(比如 ServiceManager、LocationManagerService、ActivityManagerService等等),這就是 AudioFlinger和AudioPolicyService。它們的代碼放置在frameworks/av/services /audioflinger,生成的最主要的庫叫做libaudioflinger。

音頻體系中另一個重要的系統服務是MediaPlayerService,它的位置在frameworks/av/media/libmediaplayerservice。

其一,以庫爲線索。比如AudioPolicyService和AudioFlinger都是在libaudioflinger庫中;而AudioTrack、AudioRecorder等一系列實現則在libmedia庫中。

其二,以進程爲線索。庫並不代表一個進程,進程則依賴於庫來運行。雖然有的類是在同一個庫中實現的,但並不代表它們會在同一個進程中被調用。比如 AudioFlinger和AudioPolicyService都駐留於名爲mediaserver的系統進程中;而 AudioTrack/AudioRecorder和MediaPlayer/MediaRecorder一樣實際上只是應用進程的一部分,它們通過 binder服務來與其它系統進程通信。

HAL( audio_hw.cpp ,audio.primary.so)

從設計上來看,硬件抽象層是AudioFlinger直接訪問的對象。這說明了兩個問題,一方面AudioFlinger並不直接調用底層的驅動程 序;另一方面,AudioFlinger上層(包括和它同一層的MediaPlayerService)的模塊只需要與它進行交互就可以實現音頻相關的功 能了。因而我們可以認爲AudioFlinger是Android音頻系統中真正的“隔離板”,無論下面如何變化,上層的實現都可以保持兼容。

Audio HAL提供了統一的接口來定義它與AudioFlinger/AudioPolicyService之間的通信方式,這就是* audio_hw_device、audio_stream_in及audio_stream_out*等等存在的目的,這些Struct數據類型內部大多 只是函數指針的定義,是一些“殼”。當AudioFlinger/AudioPolicyService初始化時,它們會去尋找系統中最匹配的實現(這些 實現駐留在以audio.primary.,audio.a2dp.爲名的各種庫中)來填充這些“殼”。

這裏寫圖片描述

AudioFlinger

Android中的系統服務分爲兩類,分別是Java層和Native層的System Services。其中AudioFlinger和SurfaceFlinger一樣,都屬於後者。Java層服務通常在 SystemServer.java中啓動,比如後面會看到的AudioService就是這種情況.

1.mediaserver

mediaserver的目錄下只有一個文件,它的任務很簡單,就是把所有媒體相關的native層服務(包括AudioFlinger,MediaPlayerService,CameraService和AudioPolicyService)啓動起來.

int main(int argc, char** argv)
{
    sp<ProcessState>proc(ProcessState::self());
    sp<IServiceManager>sm = defaultServiceManager();
   ALOGI("ServiceManager: %p", sm.get());
   AudioFlinger::instantiate();
   MediaPlayerService::instantiate();
   CameraService::instantiate();
   AudioPolicyService::instantiate();
   ProcessState::self()->startThreadPool();
   IPCThreadState::self()->joinThreadPool();
}

AudioFlinger 繼承BinderService

class AudioFlinger :
    public BinderService<AudioFlinger>,
    public BnAudioFlinger…
實際的初始化工作不在構造函數中,而在void AudioFlinger::onFirstRef()
2.音頻設備的管理

AudioPolicyService是策略的制定者,比如什麼時候打開音頻接口設備、某種Stream類型的音頻對應什麼設備等等。

AudioFlinger則是策略的執行者,例如具體如何與音頻設備通信,如何維護現有系統中的音頻設備,以及多個音頻流的混音如何處理等等都得由它來完 成。

Audio系統中支持的音頻設備接口(Audio Interface)分爲三大類,即:

/*frameworks/av/services/audioflinger/AudioFlinger.cpp*/
static const char * const audio_interfaces[] = {
   AUDIO_HARDWARE_MODULE_ID_PRIMARY, //主音頻設備,必須存在
   AUDIO_HARDWARE_MODULE_ID_A2DP, //藍牙A2DP音頻
   AUDIO_HARDWARE_MODULE_ID_USB, //USB音頻,早期的版本不支持
};

每種音頻設備接口由一個對應的so庫提供支持。

AudioFlinger::loadHwModule(const char *name)/*name就是前面audio_interfaces 數組
                                                            成員中的字符串*/
Step1@ loadHwModule_l. 首先查找mAudioHwDevs是否已經添加了變量name所指示的audio interface,如果是的話直接返回。第一次進入時mAudioHwDevs的size爲0,所以還會繼續往下執行。
Step2@ loadHwModule_l. 加載指定的audiointerface,比如“primary”、“a2dp”或者“usb”。函數load_audio_interface用來加載 設備所需的庫文件,然後打開設備並創建一個audio_hw_device_t實例。音頻接口設備所對應的庫文件名稱是有一定格式的,比如a2dp的模塊 名可能是audio.a2dp.so或者audio.a2dp.default.so等等。查找路徑主要有兩個,即:
/** Base path of the hal modules */
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
Step3@ loadHwModule_l,進行初始化操作。其中init_check是爲了確定這個audio interface是否已經成功初始化,0是成功,其它值表示失敗。接下來如果這個device支持主音量,我們還需要通過 set_master_volume進行設置。在每次操作device前,都要先改變mHardwareStatus的狀態值,操作結束後將其復原爲 AUDIO_HW_IDLE(根據源碼中的註釋,這樣做是爲了方便dump時正確輸出內部狀態,這裏我們就不去深究了)。
Step4@ loadHwModule_l. 把加載後的設備添加入mAudioHwDevs鍵值對中,其中key的值是由nextUniqueId生成的,這樣做保證了這個audiointerface擁有全局唯一的id號。

AudioFlinger是如何打開一個Output通道

audio_io_handle_t  AudioFlinger::openOutput(audio_module_handle_tmodule, audio_devices_t *pDevices,
                                          uint32_t *pSamplingRate,audio_format_t *pFormat,
                                          audio_channel_mask_t *pChannelMask,
                                          uint32_t *pLatencyMs, audio_output_flags_t flags)
/*入參中的module是由前面的loadHwModule 獲得的,它是一個audiointerface的id號,可以通過此id在mAudioHwDevs中查找到對應的AudioHwDevice對象*/

outHwDev用於記錄一個打開的音頻接口設備,它的數據類型是audio_hw_device_t,是由HAL規定的一個音頻接口設備所應具有的屬性集合
struct audio_hw_device {
    struct hw_device_t common;
     …
    int (*set_master_volume)(struct audio_hw_device *dev, float volume);
    int (*set_mode)(struct audio_hw_device *dev, audio_mode_t mode);
    int (*open_output_stream)(struct audio_hw_device *dev,
                             audio_io_handle_t handle,
                             audio_devices_t devices,
                             audio_output_flags_t flags,
                             struct audio_config *config,
}

Step1. 在openOutput中,設備outHwDev是通過查找當前系統來得到的

audio_hw_device_t*  AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices)

一種情況就是前面看到的modules爲0時,會load所有潛在設備,另一種情況就是AudioPolicyManagerBase在構造時會預加載所有audio_policy.conf中所描述的output。

Step2,調用open_output_stream打開一個audio_stream_out_t。

Step3,生成AudioStreamOut對象。這個變量沒什麼特別的,它把audio_hw_device_t和audio_stream_out_t做爲一個整體來封裝。

Step4. 既然通道已經打開,那麼由誰來往通道里放東西呢?這就是PlaybackThread。

DirectOutput 如果不需要混音
Mixer 需要混音
這兩種情況分別對應DirectOutputThread和MixerThread兩種線程

Step5,到目前爲止,我們已經成功的建立起一個音頻通道,就等着AudioTrack往裏丟數據了。

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