田海立
2012-04-03
Android是多任务系统,Audio系统是竞争资源。Android2.2之前,没有内建的机制来解决多个程序竞争Audio的问题,2.2引入了称作AudioFocus的机制来管理对Audio资源的竞争的管理与协调。本文主要讲解AudioFocus的使用。
按照AudioFocus的机制,在使用Audio之前,需要申请AudioFocus,在获得AudioFocus之后才可以使用Audio;如果有别的程序竞争你正在使用的Audio,你的程序需要在收到通知之后做停止播放或者降低声音的处理。值得指出的是,这种机制是需要合作完成的,需要所有使用Audio资源的程序都按照这种机制来做,而如果有程序在它失去AudioFocus的时候仍然在使用Audio,AudioFocus拿它也没办法。而这一点对于开放系统的Android来说很致命的:用户可能安装没遵守这种机制的程序,或者版本太老还没引入这种机制的程序,这最终会导致很差的用户体验。
对于手机方案公司来说,要做的能做的事情就是教育和培训团队成员以保证自己内建的程序遵守机制没问题,这包括了Android原生的程序、自己开发的程序,以及适配第三方的程序。
一、AudioFocus的申请与释放
下面看与AudioFocus的相关的类:
获取/放弃AudioFocus的方法都在android.media.AudioManager中,获取AudioFocus用requestAudioFocus()
;用完之后,放弃AudioFocus,用abandonAudioFocus()
。
其中,参数:
AUDIOFOCUS_GAIN
指示申请得到的Audio Focus不知道会持续多久,一般是长期占有;AUDIOFOCUS_GAIN_TRANSIENT
指示要申请的AudioFocus是暂时性的,会很快用完释放的;返回值,可能是:
二、AudioFocus被抢占与重新获得
由上节中知道,申请/释放AudioFocus时传入了AudioManager.OnAudioFocusChangeListener这个参数,其onAudioFocusChange()方法是Audio Focus被抢占与再次获得通知的地方。所以,每个要使用AudioFocus的程序都要小心实现这个函数,保证AudioFocus实现的一致性。
onAudioFocusChange()方法的focusChange参数指示了该AudioFocus的竞争者对AudioFocus的拥有情况,取值如下:
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
:暂时失去AudioFocus,但是可以继续播放,不过要在降低音量。下面是onAudioFocusChange()方法处理的代码片段:
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT // Pause playback } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { am.unregisterMediaButtonEventReceiver(RemoteControlReceiver); am.abandonAudioFocus(afChangeListener); // Stop playback } else if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { // Lower the volume } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Resume playback or Raise it back to normal } } };
三、典型的应用AudioFocus的场景
下面的时序图描述了AudioFocus被抢占与再次获取的典型场景:
Audio Focus被抢占与再次获取的时序图
注意:为了描述简单,此图中除了两个竞争Audio Focus的App之外,只用AudioManager表征了Android的AudioFocus机制中内部参与的对象,实际AudioManager只是外部的表象,内部参与的对象很多,回调函数也并非简单的直接由AudioManager调用,其中还包含了复杂的IPC机制。
图中:
abandonAudioFocus()
归还AudioFocus [Step#6];
小结
Audio Focus机制要参与各方充分理解并统一遵照施行,有没有遵照者或者实现有误的程序存在就可能打破这一机制,带来糟糕的用户体验。在保证Built-in程序没问题的前提下,如果进入AndroidMarket之前的程序都严格执行了AudioFocus相关的测试,应该也没问题。
使用Audio的程序要做到:
abandonAudioFocus()
归还AudioFocus。
问题点以及进一步的探讨
【更新2012-04-05】
1. AudioFocus中虽然把AudioStream作为参数,但是AudioFocus的内部裁决机制并未针对AudioStream做什么特别的处理。AudioFocus的处理针对所有的申请者来说的,除了它自身内部作为Alert的申请者有点特殊外,其它一律平等。所以文中,去掉AudioStream的描述。
2. 阅读AudioFocus内部实现机制后,对一些描述更加明确化。