音频焦点 Android Audio Focus 进阶
旧焦点处理
示例调用链:
- requestAudioFocus() → propagateFocusLossFromGain_syncAf() → handleFocusLossFromGain()。
- 系统事件(如来电)→ 强制焦点变化 → handleFocusLossFromGain()。
函数
propagateFocusLossFromGain_syncAf 焦点持有者发生的焦点丢失通知
主要功能:
• 当新的音频焦点请求到来时,通知当前所有焦点持有者可能发生的焦点丢失• 根据新的焦点增益类型决定哪些现有焦点持有者需要永久放弃焦点
• 清理那些需要永久放弃焦点的持有者
关键处理逻辑:
• 遍历当前焦点栈中的所有持有者,通知它们新的焦点变化• 对于多音频焦点模式,同样处理额外的焦点持有者列表
• 收集所有需要永久放弃焦点的持有者并移除它们
参数作用:
• focusGain: 新请求的焦点增益类型(如AUDIOFOCUS_GAIN等)• fr: 新的焦点请求者对象
• forceDuck: 是否强制应用ducking效果(降低音量而非完全停止)
多音频焦点支持:
• 当启用多音频焦点(mMultiAudioFocusEnabled)时,会额外处理mMultiAudioFocusList中的焦点持有者
/*** 当新的焦点请求到来时,传播相关的焦点丢失通知到当前焦点栈中的各个持有者。* 同时会移除那些收到永久性焦点丢失的栈条目。* * @param focusGain 新的焦点增益类型,将被添加到栈顶* @param fr 新的焦点请求者* @param forceDuck 是否强制应用 ducking 效果*/
@GuardedBy("mAudioFocusLock")
private void propagateFocusLossFromGain_syncAf(int focusGain, final FocusRequester fr,boolean forceDuck) {if (DEBUG) {Log.i(TAG, "propagateFocusLossFromGain_syncAf gain:" + focusGain);}// 创建一个列表来存储需要移除的客户端IDfinal List<String> clientsToRemove = new LinkedList<String>();// 遍历音频焦点栈,通知所有条目关于新的外部焦点增益if (!mFocusStack.empty()) {for (FocusRequester focusLoser : mFocusStack) {if (DEBUG) {Log.i(TAG, "propagateFocusLossFromGain_syncAf checking client:"+ focusLoser.getClientId());}// 处理焦点丢失,并判断是否是永久性丢失final boolean isDefinitiveLoss =focusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);if (isDefinitiveLoss) {// 如果是永久性丢失,则添加到移除列表clientsToRemove.add(focusLoser.getClientId());}}} else if (DEBUG) {Log.i(TAG, "propagateFocusLossFromGain_syncAf empty stack");}// 如果启用了多音频焦点且列表不为空,同样处理这些焦点持有者if (mMultiAudioFocusEnabled && !mMultiAudioFocusList.isEmpty()) {for (FocusRequester multifocusLoser : mMultiAudioFocusList) {final boolean isDefinitiveLoss =multifocusLoser.handleFocusLossFromGain(focusGain, fr, forceDuck);if (isDefinitiveLoss) {clientsToRemove.add(multifocusLoser.getClientId());}