天天看點

藍牙音樂靜音

藍牙音樂靜音

藍牙音樂靜音

大家想必對靜音功能不陌生,相關場景下該功能很實用。現在的終端裝置上有整個音頻系統的靜音,當然也有局部功能的靜音,其中的藍牙音樂也是提供靜音操作的,本期和大家簡單分享下藍牙音樂靜音在安卓系統中的實作。

藍牙音樂的音頻資料基本按照如下流程從 SRC 傳送到 SNK:

藍牙音樂靜音

藍牙音樂靜音的實作方案從上圖也就非常明了,目前的安卓系統主要是在音頻資料上報到 SNK 端的藍牙協定棧時不進行儲存,進而沒有解碼後的音頻資料送入安卓多媒體系統 AudioTrack 來實作的。

上述方案的實作主要依賴協定棧 btif_a2dp_sink.cc 中定義的全局變量 btif_a2dp_sink_cb 中的兩個基本變量:

藍牙音樂靜音

rx_focus_state 變量受藍牙服務層控制,變量含義顧名思義表示目前的藍牙音樂是否具有音頻焦點,而布爾值的 rx_flush 表示接收到的音頻資料是否儲存,其和 rx_focus_state 是一 一對應的關系:

藍牙音樂靜音

這樣藍牙服務也就間接通過 rx_flush 在函數btif_a2dp_sink_enqueue_buf()中實作了藍牙音樂靜音。

藍牙服務層中的接口為A2dpSinkStateMachine.informAudioFocusStateNative(),還需在framework層中添加接口函數才能打通應用層到藍牙服務的調用,相信大家都可以輕松實作。

藍牙音樂靜音功能遇到的問題:

靜音成功後再解除靜音,重新播放藍牙音樂往往會伴随着一聲pop音

針對該問題首先需要分析下藍牙協定棧将解碼後的音頻資料送入AudioTrack是否異常,打開宏變量 DUMP_PCM_DATA 記錄藍牙音樂音頻資料PCM流,使用PCM流檢視工具打開發現送給系統的PCM流很正常啊。

最後請教系統音頻的同僚後才了解其中的緣由,藍牙協定棧在靜音時是停止往系統AudioFlinger寫資料,AudioFlinger會檢測通道内是否有資料,這樣超過一定時間沒有資料後,AudioFlinger會關閉藍牙協定棧對應的音頻通道。然後再解除靜音系統會重新打開音頻通道,由于打開通道需要時間,但藍牙協定棧是在解除靜音後就開始往送AudioTrack中寫資料了,由于存在這樣的時序問題才會伴随着一聲pop音。

基于AudioFlinger會檢測是否有資料這一特性,理想的修複方案就是藍牙協定棧在靜音後往給AudioFlinger 寫入空資料,進而避免 AudioFlinger 檢測通道一定時間沒有送資料後關閉通道。

解決方案:SNK 端的藍牙協定棧還是正常接收音頻資料加入 btif_a2dp_sink_cb.rx_audio_queue 隊列儲存,隻需在音頻資料解碼完成的處理函數 btif_a2dp_sink_on_decode_complete()中加以判斷,如果目前處于靜音狀态,則将解碼後的資料直接memset重置為0的空資料即可。

藍牙音樂靜音的分享到這裡就結束了,感興趣的小夥伴歡迎私信留言一起讨論,共同學習,一起進步!

更多互聯互通技術,歡迎關注微信公衆号:Connectivity

藍牙音樂靜音