AudioFocus的機(jī)制(音頻資源搶占)

Android是多任務(wù)系統(tǒng),Audio系統(tǒng)是競爭資源,Android2.2之前,沒有內(nèi)建的機(jī)制來解決多個程序競爭Audio的問題,2.2引入了稱作AudioFocus的機(jī)制來管理對Audio資源的競爭的管理與協(xié)調(diào)。
未解決以上問題,可以使用AudioFocus的機(jī)制,即是在使用AudioStream之前,需要申請AudioFocus,在獲得AudioFocus之后才可以使用相應(yīng)的AudioStream;如果有別的程序競爭你正在使用的AudioStream,你的程序需要在收到通知之后做停止播放或者降低聲音的處理。

注意

!!如果不做音頻焦點(diǎn)監(jiān)聽操作,會出現(xiàn)多個音頻同時播放的問題,所有應(yīng)用都應(yīng)當(dāng)遵守音頻焦點(diǎn)使用規(guī)則,獲取到焦點(diǎn)的應(yīng)用才去播放音頻,未獲取到或者丟失焦點(diǎn)應(yīng)當(dāng)暫停播放!!(其實(shí)Android沒有強(qiáng)制每個App必須去遵守AudioFocus的使用規(guī)范,可能會出現(xiàn)有幾個App同時發(fā)出聲音的情況。但是大多數(shù)App都需要自動去那樣做,需要的時候請求,用完的時候釋放,這樣才能保證有良好的使用體驗(yàn)。)

在項目中播放音頻一般都是在service中處理播放的邏輯,直接在onCreate中請求AudioFocus,監(jiān)聽播放狀態(tài),銷毀服務(wù)時記得移除監(jiān)聽

@Override
public void onCreate() {
    audioManager = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
    mListener = new MyOnAudioFocusChangeListener();
    // 請求AudioFocus,注冊監(jiān)聽
    int result = audioManager.requestAudioFocus(mListener,
                AudioManager.STREAM_MUSIC,
                AUDIOFOCUS_GAIN); 
    if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    //能打印出這句話標(biāo)識已監(jiān)聽成功
            Log.e("MyOnAudioFocus", "requestAudioFocus successfully.");
    } else {
            Log.e("MyOnAudioFocus", "requestAudioFocus failed.");
    }
            //...此處省略其他代碼
}

@Override
public void onDestory(){
    //...此處省略其他代碼
    //移除監(jiān)聽
    audioManager.abandonAudioFocus(mListener);
}

具體的對監(jiān)聽的結(jié)果進(jìn)行相應(yīng)的處理,只需要實(shí)現(xiàn)相應(yīng)的類即可,監(jiān)聽的狀態(tài)有如下四種

AUDIOFOCUS_GAIN:當(dāng)前應(yīng)用獲得了Audio Focus;
AUDIOFOCUS_LOSS:當(dāng)前應(yīng)用失去了Audio Focus,并將會持續(xù)很長的時間。這里因?yàn)榭赡軙5艉荛L時間,所以不僅僅要停止Audio的播放,最好直接釋放掉Media資源。而因?yàn)橥V共シ臕udio的時間會很長,如果程序因?yàn)檫@個原因而失去AudioFocus,最好不要讓它再次自動獲得AudioFocus而繼續(xù)播放,不然突然冒出來的聲音會讓用戶感覺莫名其妙,感受很不好。這里直接放棄AudioFocus,當(dāng)然也不用再偵聽遠(yuǎn)程播放控制【如下面代碼的處理】。要再次播放,除非用戶再在界面上點(diǎn)擊開始播放,才重新初始化Media,進(jìn)行播放。
AUDIOFOCUS_LOSS_TRANSIENT:當(dāng)前應(yīng)用暫時失去Audio Focus,并會很快再次獲得。必須停止Audio的播放,但是因?yàn)榭赡軙芸煸俅潍@得AudioFocus,這里可以不釋放Media資源;
AUDIO重點(diǎn)內(nèi)容FOCUS_LOSS_TRANSIENT_CAN_DUCK:當(dāng)前應(yīng)用暫時失去AudioFocus,但是可以繼續(xù)播放,不過要在降低音量。
在項目中我對 AUDIOFOCUS_LOSS_TRANSIENT AUDIOFOCUS_LOSS_TRANSIENT這兩種情況作了相同的處理,都是進(jìn)行了播放的暫停。isUserPauseAudio這是一個我自己定義的標(biāo)志位,用來記錄是否是用戶手動的暫停音樂的播放,如果是用戶手動的暫停音樂的播放,那么即使獲取到了AudioFocus也不會進(jìn)行相應(yīng)的操作,這一點(diǎn)很重要。

private class MyOnAudioFocusChangeListener implements AudioManager.OnAudioFocusChangeListener {
        @Override
        public void onAudioFocusChange(int focusChange) {
            //監(jiān)聽系統(tǒng)播放狀態(tài)的改變
            //Log.e("MyOnAudioFocus", "focusChange=" + focusChange);
                case AUDIOFOCUS_REQUEST_GRANTED:
                  //重新得到焦點(diǎn)
                    break;
                case AUDIOFOCUS_REQUEST_FAILED:
                    //申請焦點(diǎn)失敗
                    break;
                case AUDIOFOCUS_LOSS_TRANSIENT://短時間失去焦點(diǎn)
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                 //暫時失去AudioFocus,但是可以繼續(xù)播放,不過要在降低音量。
                    break;
                case AUDIOFOCUS_LOSS:
                    //失去焦點(diǎn)并將會持續(xù)很長的時間這里因?yàn)榭赡軙5艉荛L時間,所以不僅僅要停止Audio的播放,最好直接釋放掉Media資源。而因?yàn)橥V共シ臕udio的時間會很長,如果程序因?yàn)檫@個原因而失去AudioFocus,最好不要讓它再次自動獲得AudioFocus而繼續(xù)播放,不然突然冒出來的聲音會讓用戶感覺莫名其妙,感受很不好。這里直接放棄AudioFocus,當(dāng)然也不用再偵聽遠(yuǎn)程播放控制【如下面代碼的處理】。要再次播放,除非用戶再在界面上點(diǎn)擊開始播放,才重新初始化Media,進(jìn)行播放。
                    break;
        }
    }

另:當(dāng)系統(tǒng)鬧鈴響起或者收到手機(jī)來電時,會收到AUDIOFOCUS_LOSS_TRANSIENT的回調(diào),短時間失去焦點(diǎn),但是鬧鈴響時,app可以搶占音頻資源,繼續(xù)播放自己的聲音,鬧鈴會靜音;但是手機(jī)來電時,無法搶占音頻資源,無法被靜音,且未接聽之前無法播放音頻

最后分析一下QQ微信語音消息以及撥打語音電話的時候AudioFocus的變化情況,以及相應(yīng)的處理方式。

操作 狀態(tài) 處理方式
錄制語音消息/播放語音消息 AUDIOFOCUS_LOSS_TRANSIENT 暫停播放,錄制/播放結(jié)束后,會重新獲取AudioFocus,繼續(xù)播放
被動接收QQ/微信電話 AUDIOFOCUS_LOSS_TRANSIENT 同上
主動撥打QQ/微信電話 & 使用第三方的播放器聽歌(酷狗、QQ音樂等) AUDIOFOCUS_LOSS 停止播放,撥打電話后,不能再獲取到焦點(diǎn),不再繼續(xù)播放

一些參數(shù):

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容