美文网首页
Android 音视频焦点 处理

Android 音视频焦点 处理

作者: Luke_单车 | 来源:发表于2022-12-06 12:16 被阅读0次

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

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

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

    3. 行为恰当的音频应用应根据以下一般准则来管理音频焦点:

    • 在即将开始播放之前调用 requestAudioFocus(),并验证调用是否返回 [AUDIOFOCUS_REQUEST_GRANTED](https://developer.android.google.cn/reference/android/media/AudioManager#AUDIOFOCUS_REQUEST_GRANTED)。如果按照本指南中的说明设计应用,则应在媒体会话的 onPlay() 回调中调用 requestAudioFocus()
    • 在其他应用获得音频焦点时,停止或暂停播放,或降低音量。
    • 播放停止后,放弃音频焦点。

    运行的 Android 版本不同,音频焦点的处理方式也会不同:

    • 从 Android 2.2(API 级别 8)开始,应用通过调用 [requestAudioFocus()](https://developer.android.google.cn/reference/android/media/AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener,%20int,%20int))[abandonAudioFocus()](https://developer.android.google.cn/reference/android/media/AudioManager#abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener)) 来管理音频焦点。应用还必须为这两个调用注册 [AudioManager.OnAudioFocusChangeListener](https://developer.android.google.cn/reference/android/media/AudioManager.OnAudioFocusChangeListener),以便接收回调并管理自己的音量。
    • 对于以 Android 5.0(API 级别 21)及更高版本为目标平台的应用,音频应用应使用 [AudioAttributes](https://developer.android.google.cn/reference/android/media/AudioAttributes) 来描述应用正在播放的音频类型。例如,播放语音的应用应指定 [CONTENT_TYPE_SPEECH](https://developer.android.google.cn/reference/android/media/AudioAttributes#CONTENT_TYPE_SPEECH)
    • 面向 Android 8.0(API 级别 26)或更高版本的应用应使用 [requestAudioFocus()](https://developer.android.google.cn/reference/android/media/AudioManager#requestAudioFocus(android.media.AudioFocusRequest)) 方法,该方法会接受 [AudioFocusRequest](https://developer.android.google.cn/reference/android/media/AudioFocusRequest) 参数。AudioFocusRequest 包含有关应用的音频上下文和功能的信息。系统使用这些信息来自动管理音频焦点的得到和失去。
      处理音频焦点一些规则
      以下是官方建议的处理音频焦点应该遵循的一些规则:
    1. 在开始播放之前,调用requestAudioFocus()方法,并检查返回值是否是AUDIOFOCUS_REQUEST_GRANTED,若成功获取,则开始播放。
      当App失去音频焦点时,根据失去的焦点类型,应该暂停播放,或者将音量调低。
      当播放结束时,释放音频焦点。
    2. 音频焦点如何处理
    • 处理音频焦点都是通过AudioManager这个类,如下是获得该类实例的方法:
      AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
      下面介绍音频焦点处理相关的一些方法(不同的Android版本处理音频焦点的方式略有差别,以下内容基于Android 4.4)
    requestAudioFocus():申请音频焦点
    abandonAudioFocus(): 释放音频焦点
    AudioManager.OnAudioFocusChangeListener接口,提供了onAudioFocusChange()方法来监听音频焦点变化
    
    • 5.1 requestAudioFocus
      参数:
      AudioManager.OnAudioFocusChangeListener
      用于监听音频焦点变化,从而可以进行适当的操作,例如暂停播放等。
      streamType
      申请音频焦点处理的音频类型,例如,当播放音乐时,可以传入STREAM_MUSIC;当播放铃声时,可以传入STREAM_RING。表中列出了所有的可选值:durationHint
      可选值有以下五个:
      (1) AUDIOFOCUS_GAIN: 此参数表示希望申请一个永久的音频焦点,并且希望上一个持有音频焦点的App停止播放;例如在需要播放音乐时。
      (2) AUDIOFOCUS_GAIN_TRANSIENT:表示申请一个短暂的音频焦点,并且马上就会被释放,此时希望上一个持有音频焦点的App暂停播放。例如播放一个提醒声音。
      (3) AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:效果同AUDIOFOCUS_GAIN_TRANSIENT,只是希望上一个持有焦点的App减小其播放声音(但仍可以播放),此时会混音播放。例如导航播报。
      (4) AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 表示申请一个短暂的音频焦点,并且会希望系统不要播放任何突然的声音(例如通知,提醒等),例如用户在录音。
      返回值:AUDIOFOCUS_REQUEST_GRANTED或者AUDIOFOCUS_REQUEST_FAILED
    • 5.2 abandonAudioFocus(OnAudioFocusChangeListener l)
      5.2.1 播放完成后,请调用 abandonAudioFocus()
        audioManager.abandonAudioFocus(afChangeListener)
    

    5.2.2 这会通知系统您不再需要焦点,并注销关联的 OnAudioFocusChangeListener。如果您请求的是暂时性焦点,则会通知已暂停或降低音量的应用它可以继续播放或恢复其音量。

    • 5.3 AudioManager.OnAudioFocusChangeListener
      当音频焦点发生变化时,可以在OnAudioFocusChangeListener的onAudioFocusChange(int focusChange)方法中监听到,下面详细说明该方法。
      onAudioFocusChange(int focusChange)
    • 参数:focusChange可以表明当前音频焦点发生的是何种变化,需要根据该参数状态做出正确的响应。
      分为获得和丢失两种情况:
      获得:AUDIOFOCUS_GAIN
    • 5.3.1 表示获得音频焦点,此时应该开始播放,丢失音频焦点,这时分为以下两种情况:
    • 5.3.2 短暂的丢失:
      如果focusChange的值是AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK或者 AUDIOFOCUS_LOSS_TRANSIENT时,你的App需要降低播放音量 或者暂停播放(但是需要记录当前的播放状态,以便后续恢复播放)。
      在短暂丢失焦点期间,你的App应该持续关注音频焦点的变化,当再次获得焦点时,恢复播放。
    • 5.3.3 永久的丢失
      若值为AUDIOFOCUS_LOSS,你的App应该立即停止播放,并且当再次获得音频焦点时,也不会恢复播放,只有当用户主动播放时,再开始播放
    1. 构建 AudioFocusRequest来请求和放弃音频焦点:
        audioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
        playbackAttributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_GAME)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build();
        focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
                .setAudioAttributes(playbackAttributes)
                .setAcceptsDelayedFocusGain(true)
                .setOnAudioFocusChangeListener(afChangeListener, handler)
                .build();
        mediaPlayer = new MediaPlayer();
        final Object focusLock = new Object();
    
        boolean playbackDelayed = false;
        boolean playbackNowAuthorized = false;
    
        // ...
        int res = audioManager.requestAudioFocus(focusRequest);
        synchronized(focusLock) {
            if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
                playbackNowAuthorized = false;
            } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
                playbackNowAuthorized = true;
                playbackNow();
            } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
               playbackDelayed = true;
               playbackNowAuthorized = false;
            }
        }
    
        // ...
        @Override
        public void onAudioFocusChange(int focusChange) {
            switch (focusChange) {
                case AudioManager.AUDIOFOCUS_GAIN:
                    if (playbackDelayed || resumeOnFocusGain) {
                        synchronized(focusLock) {
                            playbackDelayed = false;
                            resumeOnFocusGain = false;
                        }
                        playbackNow();
                    }
                    break;
                case AudioManager.AUDIOFOCUS_LOSS:
                    synchronized(focusLock) {
                        resumeOnFocusGain = false;
                        playbackDelayed = false;
                    }
                    pausePlayback();
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    synchronized(focusLock) {
                        resumeOnFocusGain = true;
                        playbackDelayed = false;
                    }
                    pausePlayback();
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    // ... pausing or ducking depends on your app
                    break;
                }
            }
        }
    

    参考 Android 开发者-文档-指南-管理音频焦点

    相关文章

      网友评论

          本文标题:Android 音视频焦点 处理

          本文链接:https://www.haomeiwen.com/subject/uzabfdtx.html