前提
两个或两个以上的 Android 应用可同时向同一输出流播放音频,系统会将所有音频流混合在一起。为了避免所有音乐应用同时播放,Android 引入了“音频焦点”的概念。
一次只能有一个应用获得音频焦点。
音频焦点采用合作模式
对,合作模式,你可以准守也可以不准守。
Android建议应用遵守音频焦点准则,但系统不会强制执行这些准则。如果应用想要在失去音频焦点后继续大声播放,系统无法阻止它。
下面我们只关心Android 8.0 以后版本的焦点申请。
requestAudioFocus()的使用
// 初始化AudioManager AudioManager mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); // mAudioAttributes 配置(多媒体场景,申请的是音乐流) AudioAttributes mAudioAttributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); // 初始化AudioFocusRequest mAudioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(mAudioAttributes) .setAcceptsDelayedFocusGain(true) //设置是否允许延迟获取焦点 .setWillPauseWhenDucked(true) //设置AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK会暂停,系统不会压低声音 .setOnAudioFocusChangeListener(mFocusChangeListener) //设置焦点监听回调 .build(); // requestAudioFocusshe申请焦点 int audioStatus = mAudioManager.requestAudioFocus(mAudioFocusRequest);
申请的焦点类型
申请的焦点类型有如下几种
- AudioManager.AUDIOFOCUS_GAIN
永久获取焦点
其他应用监听OnAudioFocusChangeListener 收到的焦点状态变化是AudioManager.AUDIOFOCUS_LOSS。
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
临时获取焦点
其他应用监听OnAudioFocusChangeListener 收到的焦点状态变化是AudioManager.AUDIOFOCUS_LOSS_TRANSIENT。
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
临时获取焦点且可以被压低声音播放
其他应用监听OnAudioFocusChangeListener 收到的焦点状态变化是AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK。
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
用于指示音频焦点的临时请求,预计将持续很短的时间,在此期间,其他任何应用程序或系统组件均不应播放任何内容。 专用音频音频请求和瞬时音频焦点请求的示例包括语音备忘录记录和语音识别,在此期间,系统不应播放任何通知,并且媒体播放应已暂停。(此部分来自于谷歌翻译Android文档)
申请焦点回调的状态值
audioStatus 为焦点状态,有三种情况
- AUDIOFOCUS_REQUEST_FAILED = 0
焦点申请失败,不能播放
- AUDIOFOCUS_REQUEST_GRANTED = 1
焦点申请成功,可以播放
- AUDIOFOCUS_REQUEST_DELAYED = 2
焦点延迟获取,不可以播放。
如果有重新获取焦点,会通过onAudioFocusChange()进行回调才可以播放。
这个需要在AudioFocusRequest.Builder通过setAcceptsDelayedFocusGain(boolean)允许延迟获取焦点。
private OnAudioFocusChangeListener mFocusChangeListener = new OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(int focusChange) { Log.i(TAG, "mdeia_onAudioFocusChange:" + focusChange); try { switch (focusChange) { case AudioManager.AUDIOFOCUS_LOSS: break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: break; case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: break; case AudioManager.AUDIOFOCUS_GAIN: break; } } catch (Exception e) { e.printStackTrace(); } } };
通过onAudioFocusChange()的回调是表示重新获取或丢失焦点。
- AUDIOFOCUS_LOSS 永久丢失焦点
其他应用申请的是永久焦点,我们应用就会永久丢失焦点,然后不能发声,且需要释放资源。
如果要发声需要重新走申请流程。
- AUDIOFOCUS_LOSS_TRANSIENT
临时丢失焦点
- AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
临时丢失焦,但可以播放,且声音被压低的
- AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
临时丢失,不可以播放(具体看上面解)
- AUDIOFOCUS_GAIN
重新获取焦点或者是延迟获取焦点时的回调,可以播放
参考文章