在语音聊天应用程序中使用蓝牙耳机作为麦克风和扬声器

Using a Bluetooth Headset as a Mic and Speaker in a Voice Chat App

我有一个语音聊天应用程序,效果很好。目前我正在尝试让应用程序支持蓝牙耳机,以防任何连接。我需要处理两种情况:

  1. 蓝牙耳机在通话开始前已连接。
  2. 蓝牙耳机在通话过程中连接到设备。

对于第一种情况,应用程序应自动开始使用耳机作为其默认 input/output 音频设备。另一方面,应用程序在耳机连接到设备后,应该从当前的 input/output 音频设备切换到蓝牙耳机。

我能够使用以下代码成功处理第一个案例:

mAudioManager.setMode(0);
mAudioManager.startBluetoothSco();
mAudioManager.setBluetoothScoOn(true);
mAudioManager.setMode(android.media.AudioManager.MODE_IN_CALL);

对于第二种情况,我创建了一个BroadcastReciever,当连接蓝牙耳机时监听如下:

mBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
            mAudioManager.setMode(0);
            mAudioManager.startBluetoothSco();
            mAudioManager.setBluetoothScoOn(true);
            mAudioManager.setMode(android.media.AudioManager.MODE_IN_CALL);
        } else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
            mAudioManager.setMode(0);
            mAudioManager.startBluetoothSco();
            mAudioManager.setBluetoothScoOn(false);
            mAudioManager.setMode(android.media.AudioManager.MODE_IN_CALL);
        }
    }
};

BroadcastReciever 能够检测到耳机 connections/disconnections,并且通话将声音定向到耳机而不是 phone 的听筒。 问题在于该应用一直使用设备的麦克风作为输入音频设备,而不是耳机。经过很长时间的检查,我意识到当 BroadcastReciever 收到耳机已连接的通知时, 我需要稍等片刻才能调用 mAudioManager.startBluetoothSco();让应用程序使用耳机的麦克风。

问题是,在知道蓝牙耳机已连接后,我应该监听什么样的事件,才能开始从耳机麦克风中捕获语音?

原来我不应该听 BluetoothDevice.ACTION_ACL_CONNECTED,而我应该考虑的是 BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGEDBroadcastReciever 应该初始化如下:

mBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
            int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, -1);
            boolean result = state == BluetoothHeadset.STATE_CONNECTED;
            mCallback.onConnected(result);
        }
    }
};