Android藍牙耳機/揚聲器音頻切換

需求背景

要求某些場景已經插入耳機或連接了藍牙耳機,需要使用揚聲器播放音頻

實現調研

有線耳機的情況

排除藍牙耳機情況,使用有線耳機,切換時只需要打開/關閉揚聲器即可。這樣就可以實現在插入耳機的情況下,使用揚聲器播放。 代碼如下:

//切換爲揚聲器
AudioManager audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);    
audioManager.setMicrophoneMute(false);            
audioManager.setSpeakerphoneOn(true);//使用揚聲器外放,即使已經插入耳機    
//setVolumeControlStream(AudioManager.STREAM_MUSIC);//控制聲音的大小    
audioManager.setMode(AudioManager.STREAM_MUSIC);
//切換爲耳機
mAudioManager.setSpeakerphoneOn(false);

另外,播放音頻Android提供了兩套Api,一套爲MediaPlayer,偏上層。另一套AudioTrack偏底層。實驗發現,在使用AudioTrack時需要添加增加AUDIO_SETTING權限。所以爲了保險起見,需要加上如下權限:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"></uses-permission> 

藍牙耳機

起初認爲藍牙耳機與有線耳機效果一樣,但發現使用上述有線耳機的切換代碼,效果爲:切換至揚聲器可從揚聲器播放,關閉揚聲器後。藍牙耳機中無聲音,揚聲器也無聲音。查找資料發現,需要手動打開藍牙耳機,建立連接。代碼如下:

  • 連接藍牙耳機,關閉揚聲器
    /**
     * 關閉揚聲器
     */
    private void offSpeaker() {
        if (mAudioManager == null) {
            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        }
        Log.i("zxg", "isBluetoothSco 2:" + mAudioManager.isBluetoothScoOn());
        mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        //如果有藍牙耳機設備連接,打開Sco通道使用藍牙耳機播放音頻
        if (isBluetoothHeadsetConnected()) {
            Log.i("zxg", "need start BluetoothSco");
            mAudioManager.startBluetoothSco();
            mAudioManager.setBluetoothScoOn(true);
        }
        //關閉揚聲器
        mAudioManager.setSpeakerphoneOn(false);
    }
  • 關閉藍牙Sco通道,打開揚聲器
    /**
     * 打開揚聲器
     */
    private void speaker() {
        if (mAudioManager == null) {
            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        }
//        mAudioManager.setMicrophoneMute(false);
        //關閉Sco
        if (isBluetoothHeadsetConnected()) {
            mAudioManager.setBluetoothScoOn(false);
            mAudioManager.stopBluetoothSco();
        }
        //打開揚聲器
        mAudioManager.setSpeakerphoneOn(true);
        mAudioManager.setMode(AudioManager.STREAM_MUSIC);
        Log.i("zxg", "isBluetoothSco 1:" + mAudioManager.isBluetoothScoOn());
    }
  • 判斷是否有藍牙耳機與設備連接
    /**
     * 判斷藍牙耳機是否連接
     * @return
     */
    private boolean isBluetoothHeadsetConnected() {
        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        if (BluetoothProfile.STATE_CONNECTED == adapter.getProfileConnectionState(BluetoothProfile.HEADSET)) {
            return true;
        }
        return false;
    }
  • 註冊廣播監聽

需要注意的是,打開/關閉Sco是異步的,並不是馬上完成的,所以我們需要監聽系統廣播,收到相關廣播後繼續進行後續邏輯操作。在具體邏輯代碼中可以通過mAudioManager.isBluetoothScoOn()判斷Sco狀態,以及在廣播中更新標記位來記錄Sco狀態

    /**
     * 監聽Sco變化廣播
     */
    private void registerBluetoothBroadCast() {
        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -100);
                Log.i("zxg", "EXTRA_SCO_AUDIO_STATE:" + state);
            }
        }, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
    }
  • 添加權限

操作藍牙需要申請如下權限

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

調研結果

使用以上代碼嵌入出行司機端中,使用藍牙/有線耳機切換,播放百度TTS語音。可以實現切換效果:即在連接藍牙耳機/插入有線耳機時,可以通過揚聲器播放音頻。

參考資料

Android音頻輸出通道切換 -藍牙 外放

android插入耳機狀態使用揚聲器外放音樂

藍牙連接的sco問題

Android藍牙耳機使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章