AudioFocus的机制(音频资源抢占)

Android是多任务系统,Audio系统是竞争资源,Android2.2之前,没有内建的机制来解决多个程序竞争Audio的问题,2.2引入了称作AudioFocus的机制来管理对Audio资源的竞争的管理与协调。
未解决以上问题,可以使用AudioFocus的机制,即是在使用AudioStream之前,需要申请AudioFocus,在获得AudioFocus之后才可以使用相应的AudioStream;如果有别的程序竞争你正在使用的AudioStream,你的程序需要在收到通知之后做停止播放或者降低声音的处理。

注意

!!如果不做音频焦点监听操作,会出现多个音频同时播放的问题,所有应用都应当遵守音频焦点使用规则,获取到焦点的应用才去播放音频,未获取到或者丢失焦点应当暂停播放!!(其实Android没有强制每个App必须去遵守AudioFocus的使用规范,可能会出现有几个App同时发出声音的情况。但是大多数App都需要自动去那样做,需要的时候请求,用完的时候释放,这样才能保证有良好的使用体验。)

在项目中播放音频一般都是在service中处理播放的逻辑,直接在onCreate中请求AudioFocus,监听播放状态,销毁服务时记得移除监听

@Override
public void onCreate() {
    audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
    mListener = new MyOnAudioFocusChangeListener();
    // 请求AudioFocus,注册监听
    int result = audioManager.requestAudioFocus(mListener,
                AudioManager.STREAM_MUSIC,
                AUDIOFOCUS_GAIN); 
    if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    //能打印出这句话标识已监听成功
            Log.e("MyOnAudioFocus", "requestAudioFocus successfully.");
    } else {
            Log.e("MyOnAudioFocus", "requestAudioFocus failed.");
    }
            //...此处省略其他代码
}

@Override
public void onDestory(){
    //...此处省略其他代码
    //移除监听
    audioManager.abandonAudioFocus(mListener);
}

具体的对监听的结果进行相应的处理,只需要实现相应的类即可,监听的状态有如下四种

AUDIOFOCUS_GAIN:当前应用获得了Audio Focus;
AUDIOFOCUS_LOSS:当前应用失去了Audio Focus,并将会持续很长的时间。这里因为可能会停掉很长时间,所以不仅仅要停止Audio的播放,最好直接释放掉Media资源。而因为停止播放Audio的时间会很长,如果程序因为这个原因而失去AudioFocus,最好不要让它再次自动获得AudioFocus而继续播放,不然突然冒出来的声音会让用户感觉莫名其妙,感受很不好。这里直接放弃AudioFocus,当然也不用再侦听远程播放控制【如下面代码的处理】。要再次播放,除非用户再在界面上点击开始播放,才重新初始化Media,进行播放。
AUDIOFOCUS_LOSS_TRANSIENT:当前应用暂时失去Audio Focus,并会很快再次获得。必须停止Audio的播放,但是因为可能会很快再次获得AudioFocus,这里可以不释放Media资源;
AUDIO重点内容FOCUS_LOSS_TRANSIENT_CAN_DUCK:当前应用暂时失去AudioFocus,但是可以继续播放,不过要在降低音量。
在项目中我对 AUDIOFOCUS_LOSS_TRANSIENT AUDIOFOCUS_LOSS_TRANSIENT这两种情况作了相同的处理,都是进行了播放的暂停。isUserPauseAudio这是一个我自己定义的标志位,用来记录是否是用户手动的暂停音乐的播放,如果是用户手动的暂停音乐的播放,那么即使获取到了AudioFocus也不会进行相应的操作,这一点很重要。

private class MyOnAudioFocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
        @Override
        public void onAudioFocusChange(int focusChange) {
            //监听系统播放状态的改变
            //Log.e("MyOnAudioFocus", "focusChange=" + focusChange);
                case AUDIOFOCUS_REQUEST_GRANTED:
                  //重新得到焦点
                    break;
                case AUDIOFOCUS_REQUEST_FAILED:
                    //申请焦点失败
                    break;
                case AUDIOFOCUS_LOSS_TRANSIENT://短时间失去焦点
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                 //暂时失去AudioFocus,但是可以继续播放,不过要在降低音量。
                    break;
                case AUDIOFOCUS_LOSS:
                    //失去焦点并将会持续很长的时间这里因为可能会停掉很长时间,所以不仅仅要停止Audio的播放,最好直接释放掉Media资源。而因为停止播放Audio的时间会很长,如果程序因为这个原因而失去AudioFocus,最好不要让它再次自动获得AudioFocus而继续播放,不然突然冒出来的声音会让用户感觉莫名其妙,感受很不好。这里直接放弃AudioFocus,当然也不用再侦听远程播放控制【如下面代码的处理】。要再次播放,除非用户再在界面上点击开始播放,才重新初始化Media,进行播放。
                    break;
        }
    }

另:当系统闹铃响起或者收到手机来电时,会收到AUDIOFOCUS_LOSS_TRANSIENT的回调,短时间失去焦点,但是闹铃响时,app可以抢占音频资源,继续播放自己的声音,闹铃会静音;但是手机来电时,无法抢占音频资源,无法被静音,且未接听之前无法播放音频

最后分析一下QQ微信语音消息以及拨打语音电话的时候AudioFocus的变化情况,以及相应的处理方式。

操作 状态 处理方式
录制语音消息/播放语音消息 AUDIOFOCUS_LOSS_TRANSIENT 暂停播放,录制/播放结束后,会重新获取AudioFocus,继续播放
被动接收QQ/微信电话 AUDIOFOCUS_LOSS_TRANSIENT 同上
主动拨打QQ/微信电话 & 使用第三方的播放器听歌(酷狗、QQ音乐等) AUDIOFOCUS_LOSS 停止播放,拨打电话后,不能再获取到焦点,不再继续播放

一些参数:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容