Android 控制Audio输出通道切换

简介

Audio通道有很多,Speaker、buletooth、headset等。在通话或者音乐播放的过程中,我们可能会发生Audio通道切换的情况。比如,插入有限耳机时,音频从耳机发出;拔出耳机的时候,Audio通道也会发生切换。如果我们不做对应的调整,那么可能会发生情况有,插入耳机时,音频从speaker中发出。因此我们要监听Audio通道变化,做对应的调整。

正文

Android中可以通过android.media.AudioManager查询当前的Audio输出的情况,并且在Audio输出发生变化时,捕获并处理这种变化。

需要的AudioManager的接口

public void startBluetoothSco()
public void stopBluetoothSco()
public boolean isBluetoothScoOn()
public void setBluetoothScoOn(boolean on)
public boolean isBluetoothA2dpOn()
public void startBluetoothScoVirtualCall()
public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)

Audio输出状态查询及控制

  • **isBluetoothScoOn() **: 检查A2DPAudio是否通过蓝牙耳机;
  • isSpeakerphoneOn():检查扬声器是否打开;
  • isWiredHeadsetOn():检查线控耳机是否连着;

Audio输出通道切换的事件的捕获与处理

这里是通过监听广播来捕获audio通道切换,如下代码:

IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);

private AudioManager audioManager;

    @Override
    public void onReceive(Context context, Intent intent) {
        audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        String action = intent.getAction();
        if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
            int state = intent.getIntExtra("state", 0);
            if (state == 0) {   // 耳机拔出
                Constants.changeToSpeaker(MicroContext.getApplication());
            } else if (state == 1) {    // 耳机插入
                Constants.changeToReceiver(MicroContext.getApplication());
            }
        } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
            int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
                    BluetoothHeadset.STATE_DISCONNECTED);
            updateBluetoothIndication(state);
        } else if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(action)) {
            Constants.changeToSpeaker(MicroContext.getApplication());
        }
    }

    public void updateBluetoothIndication(int bluetoothHeadsetState) {
        if (bluetoothHeadsetState == BluetoothProfile.STATE_CONNECTED) {
            Log.i(TAG, "BluetoothProfile.STATE_CONNECTED");
            if (audioManager == null) {
                return;
            } else {
                Constants.changeToHeadset(MicroContext.getApplication());
            }
        } else if (bluetoothHeadsetState == BluetoothProfile.STATE_DISCONNECTING) {
            if (audioManager == null) {
                return;
            } else {
                Constants.changeToSpeaker(MicroContext.getApplication());
            }
        } else {
            Log.i(TAG, "BluetoothProfile.OTHER");
        }
    }

/**
     * 音频外放
     */
    public static void changeToSpeaker(Context context) {
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        //注意此处,蓝牙未断开时使用MODE_IN_COMMUNICATION而不是MODE_NORMAL
        audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        audioManager.stopBluetoothSco();
        audioManager.setBluetoothScoOn(false);
        audioManager.setSpeakerphoneOn(true);
    }

    /**
     * 切换到蓝牙音箱
     */
    public static void changeToHeadset(Context context) {
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        audioManager.startBluetoothSco();
        audioManager.setBluetoothScoOn(true);
        audioManager.setSpeakerphoneOn(false);
    }

    /**
     * 切换到听筒
     */
    public static void changeToReceiver(Context context) {
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        audioManager.setSpeakerphoneOn(false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        } else {
            audioManager.setMode(AudioManager.MODE_IN_CALL);
        }
    }

有线耳机的插拔,Android中是通过广播ACTION_HEADSET_PLUG这个Intent通知的。当intent的"state"为1时,判断耳机插入,intent的"state"为0时,则判断耳机拔出。

蓝牙耳机的连接与断开,Android中时通过广播BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED这个Intent通知的,通过state的获取来判断蓝牙耳机是否连接,从而改变Audio通道

int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
                    BluetoothHeadset.STATE_DISCONNECTED);


public void updateBluetoothIndication(int bluetoothHeadsetState) {
        if (bluetoothHeadsetState == BluetoothProfile.STATE_CONNECTED) {
            Log.i(TAG, "BluetoothProfile.STATE_CONNECTED");
            if (audioManager == null) {
                return;
            } else {
                Constants.changeToHeadset(MicroContext.getApplication());
            }
        } else if (bluetoothHeadsetState == BluetoothProfile.STATE_DISCONNECTING) {
            if (audioManager == null) {
                return;
            } else {
                Constants.changeToSpeaker(MicroContext.getApplication());
            }
        } else {
            Log.i(TAG, "BluetoothProfile.OTHER");
        }
    }

耳机插拔、蓝牙耳机的断开,Audio输出通路也会自动切换,此时正在播放Audio的程序要获得通知,知道这一事件的发生。Android中是通过广播ACTION_AUDIO_BECOMING_NOISY这个Intent通知的。

小结

Audio 输出通道切换时,要根据具体需求来做相应的处理。

你可能感兴趣的:(Android 控制Audio输出通道切换)