音频焦点:歌手如何知道该​​“暂停唱歌”​​(暂停播放)还是​​“立刻闭嘴”​​(立即静音)

223 阅读3分钟

让我们把Android音频焦点系统想象成一场​​“音乐酒吧的抢麦大战”​​,而你的AppB(音乐播放器)就是酒吧里的驻唱歌手🎤。当不同类型的“抢麦者”(AppA)冲上台时,系统只会对歌手喊一句​​“台下休息!”​​(AUDIOFOCUS_LOSS_TRANSIENT)。歌手如何知道该​​“暂停唱歌”​​(暂停播放)还是​​“立刻闭嘴”​​(立即静音)?下面用故事+技术拆解这个难题👇


🎭 ​​故事场景:相同的指令,不同的危机​

  1. ​普通顾客抢麦(AppA:AUDIOFOCUS_GAIN_TRANSIENT)​
    → 一位醉汉冲上台喊:“生日快乐!”(短暂提示音)
    → 系统对歌手喊:“台下休息!”
    → ​​歌手行为​​:放下麦克风⏸️,记住歌词位置(暂停播放),等醉汉说完再接着唱。
  2. ​紧急广播员抢麦(AppA:AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)​
    → 消防员冲进来喊:“火灾警报!所有人撤离!”(电话/录音)
    → 系统同样喊:“台下休息!”
    → ​​歌手行为​​:瞬间闭嘴🤐(立即静音),但手仍握着麦克风(不释放资源),等警报结束再恢复。

🔍 ​​问题核心:相同的回调,如何区分?​

系统只发AUDIOFOCUS_LOSS_TRANSIENT,但​​危机级别不同​​!解决方案是:

✅ ​​方法1:查看“抢麦者身份证”​​(Android 8.0+)

通过AudioManager.getAudioFocusInfo()获取当前焦点持有者的​​音频属性​​(AudioAttributes),判断对方身份:

java
Copy
public void onAudioFocusChange(int focusChange) {
    if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            AudioFocusInfo focusInfo = audioManager.getAudioFocusInfo();
            AudioAttributes attrs = focusInfo.getAttributes();
            
            // 场景1:对方是电话/录音(必须静音)
            if (attrs.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
                muteImmediately(); // 立即静音!🤐
            } 
            // 场景2:对方是普通提示音(暂停即可)
            else {
                pausePlayback(); // 暂停⏸️
            }
        }
    }
}

​技术原理​​:电话/录音的AudioAttributes会标记为USAGE_VOICE_COMMUNICATION,而提示音通常是USAGE_NOTIFICATION

✅ ​​方法2:监听“酒吧大环境”​​(兼容旧版Android)

若手机版本<Android 8.0,可通过​​系统状态​​间接判断:

java
Copy
private void handleTransientLoss() {
    // 检查系统是否正在通话
    if (audioManager.getMode() == AudioManager.MODE_IN_CALL) {
        muteImmediately(); // 静音!
    } 
    // 检查是否正在录音(需权限)
    else if (isSystemRecordingActive()) { 
        muteImmediately();
    } 
    else {
        pausePlayback(); // 普通暂停
    }
}

​避坑​​:静音时用setVolume(0f),暂停时用pause()+记录播放位置 。


⚙️ ​​实战增强:歌手生存指南​

​场景​​判断依据​​行动​​恢复动作​
电话/录音抢麦AudioAttributes.USAGE_VOICE_COMMUNICATION立即静音 (setVolume(0))音量恢复 (setVolume(1))
导航/提示音抢麦AudioAttributes.USAGE_NOTIFICATION暂停播放 (pause())从暂停位置继续 (resume())
未知抢麦者(兼容模式)系统通话状态/录音权限检测静音(安全策略)根据场景恢复

🚨 ​​关键陷阱:别让歌手“假死”​

  1. ​静音≠暂停​​:静音后需监听AUDIOFOCUS_GAIN回调恢复音量,但​​不要自动播放​​(用户可能已离开) 。

  2. ​资源释放​​:仅在收到AUDIOFOCUS_LOSS(永久丢失)时才释放MediaPlayer!

  3. ​Android 12+特权​​:系统会强制淡出非语音应用,但​​仍需处理回调​​(防止厂商兼容问题) 。


💡 ​​一句话总结​

当歌手听到“台下休息”(AUDIOFOCUS_LOSS_TRANSIENT)时,​​先看抢麦者是谁​​(查AudioAttributes),再看​​现场是否在救火​​(查通话/录音状态)。普通醉汉→暂停,消防员→闭嘴,完事儿后乖乖等系统喊“上台继续唱”(AUDIOFOCUS_GAIN)!

通过这种策略,你的AppB就能在“抢麦大战”中优雅生存,既遵守系统规则,又保证用户体验🎶。 (技术细节参考Android AudioFocusRequest设计文档)