【Android Audio Focus 音频焦点】

介绍

Android 中的音频焦点(Audio Focus)是一种机制,用于管理应用程序之间的音频资源竞争。当多个应用程序同时请求使用音频设备时,通过音频焦点机制可以确保最终用户的体验不受影响。

两个或两个以上的 Android 应用可同时向同一输出流播放音频。系统会将所有音频流混合在一起。虽然这是一项出色的技术,但却会给用户带来很大的困扰。为了避免所有音乐应用同时播放,Android 引入了"音频焦点"的概念。 一次只能有一个应用获得音频焦点。

当您的应用需要输出音频时,它需要请求获得音频焦点,获得焦点后,就可以播放声音了。不过,在您获得音频焦点后,您可能无法将其一直持有到播放完成。其他应用可以请求焦点,从而占有您持有的音频焦点。如果发生这种情况,您的应用应暂停播放或降低音量,以便于用户听到新的音频源。

音频焦点采用合作模式。我们建议应用遵守音频焦点准则,但系统不会强制执行这些准则。如果应用想要在失去音频焦点后继续大声播放,系统无法阻止它。这是一种不好的体验,用户很可能会卸载具有这种不良行为的应用。


焦点事件

  • AUDIOFOCUS_GAIN
    说明 : 应用获得了音频焦点,可以继续播放音频。
    处理方式: 在这个状态下,应用可以正常播放音频。在失去焦点后再次获取焦点时,通常需要在这个状态下恢复播放。

  • AUDIOFOCUS_LOSS
    说明 : 【永久性失去焦点 】应用失去了音频焦点,需要停止音频播放。
    处理方式: 当收到 AUDIOFOCUS_LOSS 时,应用应该停止播放音频,并释放相关资源。这种情况通常是由于其他应用请求了长时间的音频焦点,例如开始播放长时间的音频文件。不要立即尝试重新获取焦点。

  • AUDIOFOCUS_LOSS_TRANSIENT
    说明 : 【暂时性失去焦点 】应用短暂失去了音频焦点,但可以在稍后重新获取焦点。
    处理方式: 当收到 AUDIOFOCUS_LOSS_TRANSIENT 时,应用应该暂停音频播放。这种情况通常是由于短暂的通知声、铃声等情况导致的。应用通常会在稍后重新获取焦点并恢复播放。

  • AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
    说明 : 【暂时性失去焦点 】应用短暂失去了音频焦点,但可以降低音量继续播放。稍后可以重新获取焦点。
    处理方式: 当收到 AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 时,应用可以选择降低音量而不是完全停止音频播放。这种情况通常用于在接收短暂通知时,应用可以继续以较低的音量播放。

暂时性失去焦点:

在暂时性失去音频焦点时,您应该继续监控音频焦点的变化,并准备好在重新获得焦点后恢复正常播放。当抢占焦点的应用放弃焦点时,您会收到一个回调 (AUDIOFOCUS_GAIN)。此时,您可以在此回调中,将音量恢复到正常水平或重新开始播放。

永久性失去焦点:

如果是永久性失去音频焦点 (AUDIOFOCUS_LOSS),则其他应用会播放音频。您的应用应立即暂停播放,因为它不会收到 AUDIOFOCUS_GAIN 回调。要想重新开始播放,用户必须执行明确的操作,例如在通知或应用界面中按播放传输控件。


代码示例

Android 8.0 及更高版本中的音频焦点:

从 Android 8.0(API 级别 26)开始,当您调用 requestAudioFocus() 时,必须提供 AudioFocusRequest 参数。要释放音频焦点,请调用 abandonAudioFocusRequest() 方法,该方法也接受 AudioFocusRequest 作为参数。在请求和放弃焦点时,应使用相同的 AudioFocusRequest 实例。

要创建 AudioFocusRequest,请使用 AudioFocusRequest.Builder。由于焦点请求始终必须指定请求的类型,因此此类型会包含在构建器的构造函数中。使用构建器的方法来设置请求的其他字段。

kotlin 复制代码
    audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
    focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
        setAudioAttributes(AudioAttributes.Builder().run {
            setUsage(AudioAttributes.USAGE_MEDIA)//or AudioAttributes.USAGE_GAME
            setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            build()
        })
        setAcceptsDelayedFocusGain(true)
        setOnAudioFocusChangeListener(afChangeListener, handler)
        build()
    }

    val focusLock = Any()

    var playbackDelayed = false
    var playbackNowAuthorized = false

    // ...
    val res = audioManager.requestAudioFocus(focusRequest)
    synchronized(focusLock) {
        playbackNowAuthorized = when (res) {
            AudioManager.AUDIOFOCUS_REQUEST_FAILED -> false
            AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
                playbackNow()
                true
            }
            AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> {
                playbackDelayed = true
                false
            }
            else -> false
        }
    }

	val afChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
        when (focusChange) {
            AudioManager.AUDIOFOCUS_LOSS -> {
                // Permanent loss of audio focus. Pause playback immediately
                synchronized(focusLock) {
                    resumeOnFocusGain = false
                    playbackDelayed = false
                }
                pausePlayback()
            }
            AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
                // Pause playback
                synchronized(focusLock) {
                    resumeOnFocusGain = true
                    playbackDelayed = false
                }
                pausePlayback()
            }
            AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
                // ... pausing or Lower the volume depends on your app
                
            }
            AudioManager.AUDIOFOCUS_GAIN -> {
                // Your app has been granted audio focus again
                // Raise volume to normal, restart playback if necessary
                if (playbackDelayed || resumeOnFocusGain) {
                    synchronized(focusLock) {
                        playbackDelayed = false
                        resumeOnFocusGain = false
                    }
                    playbackNow()
                }
            }
        }
    }

官方文档链接管理音频焦点

相关推荐
m0_748254669 分钟前
go官方日志库带色彩格式化
android·开发语言·golang
zhangphil9 分钟前
Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现“刮刮乐”效果,Kotlin(2)
android·kotlin
爱学测试的李木子31 分钟前
从0到1搭建 Android 自动化 python+appium 环境
android·软件测试·python·测试工具·自动化
咸芝麻鱼42 分钟前
Android Studio | 连接手机设备后,启动App时出现:Waiting For DebuggerApplication (App名)...
android·adb·智能手机·android studio
叶羽西42 分钟前
Android Studio Gradle Sync timeout
android·ide·android studio
m0_748256141 小时前
Android 关于Tencent vConsole 添加入webView 总结
android
开发者阿伟2 小时前
Android Jetpack DataBinding源码解析与实践
android·android jetpack
AirDroid_qs2 小时前
Niushop开源商城(漏洞复现)
android·网络安全·开源
Autumn.h2 小时前
niushop开源商城靶场漏洞
android
戏谑3 小时前
Android 常用布局
android·view