華爲手環耳機模式適配

前言

最近接到一個需求,須要在播放聲音時適配華爲藍牙手環,這個手環不一樣於其餘手環,將手環主機從腕帶上取出時,就變成了藍牙耳機,能夠接聽電話。如圖所示: java

這裏爲了便於理解,定義兩個概念:

  • 手環模式:未將主機從腕帶上取出狀態
  • 耳機模式:將主機從腕帶上取出狀態

定位問題

遇到的問題

手環模式下,手機鏈接手環藍牙後,聲音由聽筒播放。less

爲何會從聽筒中播放?

從手機設置界面觀察到,該手環的音頻選項在處於手環模式和耳機模式時有不一樣的狀態,當處於手環模式時,通話音頻處於開啓狀態,媒體音頻處於關閉狀態,如圖: 異步

手環模式
當處於耳機模式時,通話音頻和媒體音頻均爲開啓狀態
耳機模式
由此咱們能夠獲得一個重要的線索,若是系統設置能夠判斷出音頻狀態,咱們也能夠經過代碼判斷當前藍牙設備的通話音頻和媒體音頻的狀態。

接下來咱們看代碼,在原有的實現中,當有藍牙設備鏈接時,會收到鏈接的廣播,而後咱們經過以下代碼設置將聲音經過藍牙耳機播放spa

private void chooseBluetooth() {
        audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        audioManager.startBluetoothSco();      // 打開 SCO 類型藍牙鏈路
        audioManager.setBluetoothScoOn(true);  // 打開 SCO 類型藍牙鏈路
        audioManager.setSpeakerphoneOn(false); // 關閉揚聲器
 }
複製代碼

audioManagerAudioManager 對象,這裏簡單介紹一下 audioManager.startBluetoothSco(); 這行代碼的意思是打開 SCO 類型藍牙鏈路。在藍牙通訊中,共有兩種通訊鏈路:code

  1. 同步鏈路 (Synchronous Connection Oriented)
  2. 異步鏈路 (Asynchronous Connectionless)

同步鏈路 (SCO) 鏈接爲對稱鏈接,利用保留時隙傳送數據包。鏈接創建後,主設備和從設備能夠不被選中就發送SCO數據包。SCO數據包既能夠傳送話音,也能夠傳送數據,但在傳送數據時,只用於重發被損壞的那部分的數據。主要用來傳輸對時間要求很高的數據通訊cdn

異步鏈路(ACL)就是定向發送數據包,它既支持對稱鏈接,也支持不對稱鏈接(既能夠一對一,也能夠一對多)。主設備負責控制鏈路帶寬,並決定微微網中的每一個從設備能夠佔用多少帶寬和鏈接的對稱性。從設備只有被選中時才能傳送數據。ACL鏈路也支持接收主設備發給微微網中全部從設備的廣播消息。對象

那麼爲何在手環模式下聲音會從聽筒中播放?這裏作出一個猜測,在手環模式下,Android 系統並無主動打開媒體音頻,當咱們的程序執行 audioManager.startBluetoothSco(); 時執行失敗,致使沒法打開藍牙鏈路,以後咱們又設置了 audioManager.setSpeakerphoneOn(false); 關閉揚聲器,聲音天然就從聽筒中播放。blog

解決方案

大體思路就是在調用 chooseBluetooth() 以前判斷系統是否打開了媒體音頻,若是打開了則進行藍牙播放,不然依然使用揚聲器播放,具體判斷代碼以下:get

boolean isA2dpOn = audioManager.isBluetoothA2dpOn();
複製代碼

參考文獻

相關文章
相關標籤/搜索