前言

最近线上用户反馈了一些语音唤醒功用无法运用的问题(即无法经过语音来和运用交互),因此专门梳理了Android运用对音频焦点的处理逻辑并提出一些优化思路,下文是一次总结整理。

音频焦点出现的缘由、作用

为什么会有音频焦点的出现?两个或两个以上的 Android 运用可一同向同一输出流播映音频,体系会将一切音频流混合在一同。为了防止一切音乐运用一同播映,Android 引入了“音频焦点”的概念,一次只能有一个运用取得音频焦点。当运用需求输出音频时,它需求恳求取得音频焦点,取得焦点后,就能够播映声响了。

不过,Android体系虽然能够对音频焦点进行分配,但不能强制让上一个占有音频焦点的运用程序抛弃运用音频。即运用程序A正在前台运用语音唤醒功用的时分,运用B拨打了一个语音电话过来,这时Android体系会把音频焦点分配给运用B,但运用A的语音唤醒功用并没有被剥夺、仍然能够运用。那么运用B的语音电话功用就会受到影响。

这时就需求约定一个规矩,当运用程序失掉音频焦点的时分,就需求暂停运用音频或下降音频音量,把音频通道让给占有音频焦点的运用程序运用。假如运用违反上述规矩,不开释音频通道,或许会引发许多客诉、流失掉许多用户。

音频焦点的运用核心

Android运用经过调用requestAudioFocus()(恳求音频焦点)和abandonAudioFocus()(抛弃音频焦点)来办理音频焦点。运用还必须为这两个办法注册监听器AudioManager.OnAudioFocusChangeListener,以便接回收调并办理自己的音量。

音频焦点具体的代码运用

  AudioManageraudioManager= (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
  
  AudioManager.OnAudioFocusChangeListenerafChangeListener=
   new AudioManager.OnAudioFocusChangeListener() {
    public void onAudioFocusChange(intfocusChange) {
     if (focusChange== AudioManager.AUDIOFOCUS_LOSS) {
      //永久失掉音频焦点
      //当即中止播映
     }
     else if (focusChange== AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
      //暂时性失掉焦点
      //播映暂停
     } else if (focusChange== AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
      //暂时性失掉焦点
      //声响变低,持续播映
     } else if (focusChange== AudioManager.AUDIOFOCUS_GAIN) {
      //获取到音频焦点
      //声响康复到正常音量,开端播映
     }
    }
   };
  intresult=audioManager.requestAudioFocus(afChangeListener,
                 //运用音频流
                 AudioManager.STREAM_MUSIC,
                 AudioManager.AUDIOFOCUS_GAIN);
  if (result== AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    //音频焦点恳求成功,履行相应逻辑
  } else {
    //音频焦点恳求失败,履行相应逻辑
  }

播映完成后,抛弃音频焦点:

audioManager.abandonAudioFocus(afChangeListener);

运用中注意的点:

①为requestAudioFocus 办法传入的第3个参数:

  • 假如计划在将来一段时间内播映音频,而且希望前一个持有音频焦点的运用中止播映,则应该恳求永久性的音频焦点(AUDIOFOCUS_GAIN)。
  • 假如只希望在短时间内播映音频,而且希望前一个持有音频焦点的运用暂停播映,则应该恳求暂时性的焦点(AUDIOFOCUS_GAIN_TRANSIENT)。
  • 假如只希望在短时间内播映音频,并允许前一个持有焦点的运用在下降音量的情况下持续播映,则应该恳求“下降音量”的暂时性焦点(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)。这两个音频会混合到音频流中一同输出。

②AudioManager.OnAudioFocusChangeListener回调回来的音频焦点类型,如下:

  • AUDIOFOCUS_GAIN:获取得到音频焦点。
  • AUDIOFOCUS_LOSS:永久性失掉音频焦点,后续不会再收到AUDIOFOCUS_GAIN回调。运用应当即暂停播映,此刻其他运用会播映音频。
  • AUDIOFOCUS_LOSS_TRANSIENT:暂时性失掉音频焦点,运用应暂停播映。当抢占焦点的运用抛弃焦点时、自己的运用能够收到AUDIOFOCUS_GAIN回调。
  • AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:暂时性失掉音频焦点,运用应下降音量。当抢占焦点的运用抛弃焦点时、自己的运用能够收到AUDIOFOCUS_GAIN回调。

开发中遇到的问题&解决思路

大多数情况下,依照上述流程运用音频焦点是没有问题的。但线上有部分用户反馈无法运用语音唤醒功用(即无法经过语音来和运用交互),经过排查,发现有如下可优化的当地:

  • 问题1:不是一切运用都会将音频焦点开释,有的运用也会不开释,比如手机体系的录音机。这看似违反最上面说的音频焦点办理规矩,但录音机是有它特殊性的,不管它位于前台仍是后台,都应该拥有录音的功用。这就会导致只要不杀死录音机运用进程,它就会一直占用音频焦点,导致其他运用无法运用音频焦点。或许是其他运用把本来属于本运用的音频焦点抢占了,也会导致本运用无法运用音频焦点,比如某些运用内的语音通话功用就会抢占音频焦点。

    处理策略:当AudioManager.OnAudioFocusChangeListener监听器监听到音频焦点已失掉时(AUDIOFOCUS_LOSS、AUDIOFOCUS_LOSS_TRANSIENT),就自动经过弹窗或toast提示用户【关闭其他运用或重启手机】,以希望达到让其他运用开释音频焦点的意图。

  • 问题2:正常来说,当B运用把音频焦点开释后,A运用是能够重新获取到音频焦点的回调(AUDIOFOCUS_GAIN),但某些Android手机或许会有体系bug,即不会自动告诉A运用音频焦点现已回来了,A运用无法拿到AUDIOFOCUS_GAIN这个回调,A运用也就无法再康复播映音频。

    处理策略:增加音频功用的调用机遇。比如在切页或许做其他操作的时分,自动测验运用语音唤醒的音频功用,而不是经过AudioManager.OnAudioFocusChangeListener监听器被动地等待回调。当自动测验运用语音唤醒成功时,说明音频焦点现已回来了。

以上是Android音频焦点的运用介绍以及所遇到问题的剖析和处理。欢迎重视大众号度熊君,一同共享交流。