轉載:android audio flinger

https://blog.csdn.net/innost/article/details/6142812函數

https://blog.csdn.net/zyuanyun/article/details/60890534oop

 

AndioFlinger 做爲 Android 的音頻系統引擎,重任之一是負責輸入輸出流設備的管理及音頻流數據的處理傳輸,這是由回放線程(PlaybackThread 及其派生的子類)和錄製線程(RecordThread)進行的,咱們簡單看看回放線程和錄製線程類關係:.net

 

 

ThreadBase:PlaybackThread 和 RecordThread 的基類
RecordThread:錄製線程類,由 ThreadBase 派生
PlaybackThread:回放線程基類,同由 ThreadBase 派生
MixerThread:混音回放線程類,由 PlaybackThread 派生,負責處理標識爲 AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_FAST、AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音頻流,MixerThread 能夠把多個音軌的數據混音後再輸出
DirectOutputThread:直輸回放線程類,由 PlaybackThread 派生,負責處理標識爲 AUDIO_OUTPUT_FLAG_DIRECT 的音頻流,這種音頻流數據不須要軟件混音,直接輸出到音頻設備便可
DuplicatingThread:複製回放線程類,由 MixerThread 派生,負責複製音頻流數據到其餘輸出設備,使用場景如主聲卡設備、藍牙耳機設備、USB 聲卡設備同時輸出
OffloadThread:硬解回放線程類,由 DirectOutputThread 派生,負責處理標識爲 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音頻流,這種音頻流未經軟件解碼的(通常是 MP三、AAC 等格式的數據),須要輸出到硬件解碼器,由硬件解碼器解碼成 PCM 數據
PlaybackThread 中有個極爲重要的函數 threadLoop(),當 PlaybackThread 被強引用時,threadLoop() 會真正運行起來進入循環主體,處理音頻流數據相關事務

線程

1.threadLoop() 循環的條件是 exitPending() 返回 false,若是想要 PlaybackThread 結束循環,則能夠調用 requestExit() 來請求退出;
2.processConfigEvents_l() :處理配置事件;當有配置改變的事件發生時,須要調用 sendConfigEvent_l() 來通知 PlaybackThread,這樣 PlaybackThread 才能及時處理配置事件;常見的配置事件是切換音頻通路;
檢查此時此刻是否符合 standby 條件,好比當前並無 ACTIVE 狀態的 Track(mActiveTracks.size() = 0),那麼調用 threadLoop_standby() 關閉音頻硬件設備以節省能耗;
3.prepareTracks_l(): 準備音頻流和混音器,該函數很是複雜,這裏不詳細分析了,僅列一下流程要點:
遍歷 mActiveTracks,逐個處理 mActiveTracks 上的 Track,檢查該 Track 是否爲 ACTIVE 狀態;
若是 Track 設置是 ACTIVE 狀態,則再檢查該 Track 的數據是否準備就緒了;
根據音頻流的音量值、格式、聲道數、音軌的採樣率、硬件設備的採樣率,配置好混音器參數;
若是 Track 的狀態是 PAUSED 或 STOPPED,則把該 Track 添加到 tracksToRemove 向量中;
4.threadLoop_mix():讀取全部置了 ACTIVE 狀態的音頻流數據,混音器開始處理這些數據;
5.threadLoop_write(): 把混音器處理後的數據寫到輸出流設備;
6.threadLoop_removeTracks(): 把 tracksToRemove 上的全部 Track 從 mActiveTracks 中移除出來;這樣下一次循環時就不會處理這些 Track 了。
這裏說說 PlaybackThread 與輸出流設備的關係:PlaybackThread 實例與輸出流設備是一一對應的,比方說 OffloadThread 只會將音頻數據輸出到 compress_offload 設備中,MixerThread(with FastMixer) 只會將音頻數據輸出到 low_latency 設備中。3d

從 Audio HAL 中,咱們一般看到以下 4 種輸出流設備,分別對應着不一樣的播放場景:blog

primary_out:主輸出流設備,用於鈴聲類聲音輸出,對應着標識爲 AUDIO_OUTPUT_FLAG_PRIMARY 的音頻流和一個 MixerThread 回放線程實例
low_latency:低延遲輸出流設備,用於按鍵音、遊戲背景音等對時延要求高的聲音輸出,對應着標識爲 AUDIO_OUTPUT_FLAG_FAST 的音頻流和一個 MixerThread 回放線程實例
deep_buffer:音樂音軌輸出流設備,用於音樂等對時延要求不高的聲音輸出,對應着標識爲 AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音頻流和一個 MixerThread 回放線程實例
compress_offload:硬解輸出流設備,用於須要硬件解碼的數據輸出,對應着標識爲 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音頻流和一個 OffloadThread 回放線程實例
其中 primary_out 設備是必須聲明支持的,並且系統啓動時就已經打開 primary_out 設備並建立好對應的 MixerThread 實例。其餘類型的輸出流設備並不是必須聲明支持的,主要是看硬件上有無這個能力。遊戲

可能有人產生這樣的疑問:既然 primary_out 設備一直保持打開,那麼能耗豈不是很大?這裏闡釋一個概念:輸出流設備屬於邏輯設備,並非硬件設備。因此即便輸出流設備一直保持打開,只要硬件設備不工做,那麼就不會影響能耗。那麼硬件設備何時纔會打開呢?答案是 PlaybackThread 將音頻數據寫入到輸出流設備時。事件

下圖簡單描述 AudioTrack、PlaybackThread、輸出流設備三者的對應關係:
事務

 

咱們能夠這麼說:輸出流設備決定了它對應的 PlaybackThread 是什麼類型。怎麼理解呢?意思是說:只有支持了該類型的輸出流設備,那麼該類型的 PlaybackThread 纔有可能被建立。舉個例子:只有硬件上具有硬件解碼器,系統才創建 compress_offload 設備,而後播放 mp3 格式的音樂文件時,纔會建立 OffloadThread 把數據輸出到 compress_offload 設備上;反之,若是硬件上並不具有硬件解碼器,系統則不該該創建 compress_offload 設備,那麼播放 mp3 格式的音樂文件時,經過 MixerThread 把數據輸出到其餘輸出流設備上。rem

那麼有無可能出現這種狀況:底層並不支持 compress_offload 設備,但恰恰有個標識爲 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音頻流送到 AudioFlinger 了呢?這是不可能的。系統啓動時,會檢查並保存輸入輸出流設備的支持信息;播放器在播放 mp3 文件時,首先看 compress_offload 設備是否支持了,若是支持,那麼不進行軟件解碼,直接把數據標識爲 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;若是不支持,那麼先進行軟件解碼,而後把解碼好的數據標識爲 AUDIO_OUTPUT_FLAG_DEEP_BUFFER,前提是 deep_buffer 設備是支持了的;若是 deep_buffer 設備也不支持,那麼把數據標識爲 AUDIO_OUTPUT_FLAG_PRIMARY。

系統啓動時,就已經打開 primary_out、low_latency、deep_buffer 這三種輸出流設備,並建立對應的 MixerThread 了;而此時 DirectOutputThread 與 OffloadThread 不會被建立,直到標識爲 AUDIO_OUTPUT_FLAG_DIRECT/AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音頻流須要輸出時,纔開始建立 DirectOutputThread/OffloadThread 和打開 direct_out/compress_offload 設備。

 openOUtput:

 

new AudioTrack:

start:

write:

pause:

相關文章
相關標籤/搜索