Android中的音频管理类AudioManager
Android多媒体开发中,可能经常会遇到这种问题:音乐在(或者后台播放)播放的过程中,系统收到短信或者用户点开了其他音频输出应用(例如视频),发现有两个声音同时在播放?相信进行多媒体开发的人员早期都遇到过这种bug,本文就以此为例,简单介绍下Android中的音频管理。
从Android2.2开始,平台为应用提供了一个协商它们如何使用设备音频输出的途径,这个机制叫做音频焦点,由AudioManager管理。你可以在应用中注册焦点监听器来监听音频焦点的变化,从而作出对应的处理逻辑。
一、先介绍一下Android系统提供的API:
/**
* Interface definition for a callback to be invoked when the audio focus of the system is
* updated.
*/
public interface OnAudioFocusChangeListener { public void onAudioFocusChange(int focusChange); }
参数focusChange告诉你音频焦点如何发生了变化,它可以是以下几种值(它们都是定义在AudioManager中的常量):
AUDIOFOCUS_GAIN:你已获得了音频焦点;
AUDIOFOCUS_GAIN_TRANSIENT:临时性的获取音频焦点;
AUDIOFOCUS_LOSS:你已经丢失了音频焦点比较长的时间了,你必须停止所有的音频播放,因为预料到你可能很长时间也不能再获音频焦点,所以这里是清理你的资源的好地方。比如,你必须释放MediaPlayer;
AUDIOFOCUS_LOSS_TRANSIENT:你临时性的丢掉了音频焦点,很快就会重新获得。你必须停止所有的音频播放,但是可以保留你的资源,因为你可能很快就能重新获得焦点。
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:你临时性的丢掉了音频焦点,但是你被允许继续以低音量播放,而不是完全停止。
那么,针对本文开头提出的问题,具体解决步骤:
(1)在应用中创建焦点监听器:
private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { //针对focusChanage的值作不同的处理,例如:失去焦点时暂停播放;重新获取焦点后继续播放等. } };
(2)播放多媒体前,获取焦点:
if (mAudioManager == null) { mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); } mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
(3)退出界面时放弃焦点:
mAudioManager.abandonAudioFocus(mAudioFocusListener);
注: 如果第三方播放器也使用了这个机制的话,当你的应用获取声音焦点之后,第三方播放器失去焦点,做了暂停处理,即会停止播放。这样就不会出现两个播放器同时播放音乐的情况了。而如果第三方播放器没有经过处理,不管有没有焦点都一直播放,那就没有办法了(我们无法处理第三方)。原文参考:http://blog.csdn.net/shuaicike/article/details/39930823
二、场景处理:
1、自己的app播放音乐时,来电导致音乐暂停;电话挂断后,声音突然响起,针对这种情况,可以按照如下思路处理:
在监听到获取焦点后,设置mMediaPlayer.setVolume(0, 0),然后逐渐增大音量(设置步长+0.01)至系统音量mMediaPlayer.setVolume(1, 1)。例如:
mCurrentVolume += .01f; sendEmptyMessageDelayed(mCurrentVolume , 10); //即1s以后恢复至系统音量.
2、播放音视频时对于电话状态的监听:
PhoneStateListener phoneStateListener = new PhoneStateListener(){ @Override public void onCallStateChanged(int state, String incomingNumber) { // TODO Auto-generated method stub } };
参数state包含三种状态:
TelephonyManager.CALL_STATE_RINGING:来电响铃
TelephonyManager.CALL_STATE_OFFHOOK:电话接通
TelephonyManager.CALL_STATE_IDLE:电话挂断
(1)注册事件:
TelephonyManager mTelephonyManager = TelephonyManager.from(this); mTelephonyManager.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
(2)注销事件:
mTelephonyManager.listen(mPhoneListener, PhoneStateListener.LISTEN_NONE);
注意:由于PhoneStateListener中创建一个Handler,因此若未注销,可能导致Activity或Service不会被回收,引起内存泄露问题。