Audio 输出通道有很多,Speaker、headset、bluetooth A2DP等。通话或播放音乐等使用Audio输出过程中,可能发生Audio输出通道的切换。比如,插入有线耳机播放音乐时,声音是从耳机发出的;而此时拔出耳机,Audio输出通道会发生切换。如果音乐播放器不做处理,Audio输出是被切换到扬声器的,声音直接从Speaker发出。我们在编写程序时,要捕获并按照需求来处理这样的事,本文就是讲解如何处理的。
Android中可以通过android.media.AudioManager查询当前Audio输出的情况,并且在Audio输出发生变化时,捕获并处理这种变化。
一、Audio输出状态查询与控制
android.media.AudioManager提供的下列方法可以用来查询当前Audio输出的状态:
另外还有一些设置这些Audio输出的setXYZ()方法,这些方法在一般使用Audio输出的应用程序不要直接调用,他们由系统来管理,实现Audio输出通道的自动切换。除非,界面提供给用户切换的菜单或按钮,而用户选择了却换,比如要直接选择扬声器发声,可直接调用setSpeakerphoneOn()。
二、Audio输出通道切换的事件的捕获与处理
因为耳机插拔、蓝牙耳机的断开,Audio输出通路会自动切换。此时正在播放Audio的程序要获得通知,知道这一事件的发生。Android中是通过广播ACTION_AUDIO_BECOMING_NOISY这个Intent通知的。
处理广播的较好的方式,是动态注册/注销自己所关心的广播。下面代码演示了,开始播放时注册广播的Receiver;停止播放时注销广播的Receiver。对Audio输出通道切换的处理是暂停当前的播放,不直接从新的通道里发出声来。
- private class NoisyAudioStreamReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
- // Pause the playback
- }
- }
- }
- private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- private void startPlayback() {
- registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
- }
- private void stopPlayback() {
- unregisterReceiver(myNoisyAudioStreamReceiver);
- }
三、Audio输出通道切换的典型场景—— 用耳机听音乐时,拔出耳机
听耳机听音乐时,耳机别拔出的时序图如下:
图中:
小结
Audio 输出通道切换时,要根据具体需求来做相应的处理。
PS:以上摘自 http://blog.csdn.net/thl789/article/details/7423523
下面为个人整理
从用户移除蓝牙耳机到音乐暂停流程跟踪
首先,在Android源码 AudioService.java 中当用户移除带有音频连接的蓝牙耳机时会调用下面方法
private void makeA2dpDeviceUnavailableNow(String address) {
//此处会发送ACTION_AUDIO_BECOMING_NOISY 广播,音乐播放器会接收这个广播,对当前正在播放的音乐进一步处理
//Intent noisyIntent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
//mContext.sendBroadcast(noisyIntent);
Log.d(TAG, "makeA2dpDeviceUnavailableNow");
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_UNAVAILABLE,
address);
mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
}
然后, Music模块中的MediaButtonIntentReceiver.java会接收ACTION_AUDIO_BECOMING_NOISY 广播,并处理
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) {
//接收ACTION_AUDIO_BECOMING_NOISY广播并启动Service(MediaPlaybackService),最后由MediaPlaybackService处理
Intent i = new Intent(context, MediaPlaybackService.class);
i.setAction(MediaPlaybackService.SERVICECMD);
i.putExtra(MediaPlaybackService.CMDNAME, MediaPlaybackService.CMDPAUSE);
context.startService(i);
}
.........
}
上面代码中可以看到 下面这两行
i.setAction(MediaPlaybackService.SERVICECMD);
i.putExtra(MediaPlaybackService.CMDNAME, MediaPlaybackService.CMDPAUSE);
最后, 在MediaPlaybackService 又接收
Action( MediaPlaybackService.SERVICECMD),即“com.android.music.musicservicecommand”
MediaPlaybackService.CMDPAUSE 即 "pause"
receiver 判断如下
else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
Editor ed = mPreferences.edit();
ed.putBoolean("pausedbytransientlossoffocus", false);
ed.commit();
MusicLogUtils.i(TAG, "pause state saved to shared preference!!");
pause();
mPausedByTransientLossOfFocus = false;
}
将音乐暂停