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往裏丟數據了。