Android之路

导航

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不会被回收,引起内存泄露问题。

    

posted on 2019-07-29 15:23  Android之路  阅读(912)  评论(0编辑  收藏  举报