藍牙音樂SRC側的安卓實現
隨著電子產品的普及,越來越多的年輕人熱衷於使用藍牙技術來播放歌曲(相當多的手機品牌取消了耳機插孔),本篇文章就和大家聊聊藍牙音樂SRC端在安卓系統中的實現原理。
安卓系統參考版本:Android-9
藍牙SRC側播放藍牙音樂,音頻數據都是從安卓音頻系統發送過來的,藍牙協議棧接收到音頻數據處理再發送到SNK端進行播放,整體的流程大概如下圖所示:
紅色框圖標註的部分就是我們今天探討的內容,在對藍牙音樂SRC介紹之前,我們得簡單了解下安卓中音頻系統。安卓的audio系統播放音頻都是將數據發送到對應的輸出設備進行播放,藍牙自然也是其中一種音頻輸出設備,類似的輸出設備還有如下這些,源碼路徑:/system/media/audio/include/system/audio.h
這些音頻輸出設備通過HAL框架以一個個單獨的模塊存在於安卓系統中,音頻系統服務層 audioserver在初始化過程中通過HAL技術加載配置文件支持的模塊。這裡以藍牙a2dp為例具體分析下加載模塊的時序圖:
這樣音頻服務就和藍牙協議棧bluedroid建立聯繫,藍牙音樂播放的音頻數據就可以通過該路徑源源不斷地送入藍牙協議棧中進一步處理。
藍牙提供的音頻系統的動態連結庫為:audio.a2dp.default.so
源碼路徑:/system/bt/audio_a2dp_hw/
音頻系統初始化階段只會加載打開 audio.a2dp.default.so 獲取到a2dp模塊接口,至於打開輸出流只有在A2DP協議連接成功後才會執行。
從以上時序圖可以看到 audio.a2dp.default.so 運行在音頻服務的進程中,那其又如何與藍牙服務進程 com.android.bluetooth 交互呢?
跨進程通信有多種方式,audioserver 和 com.android.bluetooth 在藍牙音樂數據傳輸場景下通過 socket完成跨進程通信。
藍牙協議棧創建如下兩種socket與audioserver進行通信:
/data/misc/bluedroid/.a2dp_ctrl :控制socket,傳遞A2DP的控制信號/data/misc/bluedroid/.a2dp_data :數據socket,傳遞A2DP的音頻數據Bluedroid通過數據socket接收到audio發送過來的音頻數據後,根據A2DP連接時雙方協商確定的編碼方式對數據進行編碼操作,最終將編碼後的數據通過l2cap鏈路發送到SNK端。具體時序圖如下:
對音頻數據進行編碼的具體操作則在各編碼方式對應的處理函數中完成,源碼路徑參考:system/bt/stack/a2dp/a2dp_xxx_encoder.cc/a2dp_xxx_encode_frames(),xxx對應A2DP連接使用的編碼方式(SBC、AAC、aptX、LDAC等)。
數據最終在bta層 bta_av_data_path()處理函數中通過 p_scb->p_cos->data() 回調從 btif_a2dp_source_cb.tx_audio_queue 隊列中取出,數據隨後經過進一步封裝發送給SNK端,SNK再反向解碼出音頻流播放。
藍牙音樂SRC側的安卓實現大體上如此,感興趣的小夥伴歡迎私信留言一起討論,共同學習,一起進步!