對於音頻焦點,不少人會感到很陌生,也很迷惑,不清楚音頻焦點到底處理什麼的,怎麼用。有人說要播放音樂,必須先申請焦點,只有拿到焦點後才能播放音樂,可也有人說我不申請音頻焦點也能播放音樂,所以,今天咱們就來講說到底什麼是音頻焦點。android
AudioFocus機制實在Android2.2引入的,當初是爲了協調各應用之間競爭Audio資源的問題,舉個簡單例子QQ音樂要播放音樂,優酷要播放視頻。對於手機上的這兩個應用,若是視頻和音樂同時播放,效果可想而知,那麼他們之間怎麼實現互斥播放的呢,固然實現的方式不少,廣播 binder的進程間通訊等,但你以爲QQ音樂會告訴優酷你接下個人廣播,或者優酷告訴QQ音樂你bind下我,若是在加入一個網易雲音樂,愛奇藝視頻,顯然是不能夠的,谷歌爸爸顯然又不可能讓你們胡鬧下去,由於好的用戶體驗仍是很重要的嘛,所以這個時候AudioFocus就出現了。
谷歌爸爸說我來制定一套遊戲規則,你們遵照規則就能夠愉快的一塊兒玩耍了,但既然只是規則,那麼就有遵照遊戲規則的好孩子以及不遵照遊戲規則的好孩子。
遵不遵照遊戲規則都是能夠一塊兒玩耍的,這就回到了咱們開始說的問題。有人說要播放音樂,必須先申請焦點,只有拿到焦點後才能播放音樂(遵照遊戲規則的好孩子),可也有人說我不申請音頻焦點也能播放音樂(不遵照遊戲規則的好孩子)
說到這我想這回對音頻焦點都有了一個初步的認時,既然是規則,顯然是個弱管理。也就是說若是你想播放,無論拿不拿獲得音頻焦點,都是能夠播放的。影響的只是體驗效果,不是播放問題。這個必定要搞懂。
廢話連篇的說了好多,那麼如何使用呢?過期的使用方法就不說了,咱們只說最新的關於AudioFocus的Api。app
package com.example.myapplication; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.media.AudioAttributes; import android.media.AudioFocusRequest; import android.media.AudioManager; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import androidx.annotation.NonNull; public class MainActivity extends Activity { private AudioManager mAudioManager; private AudioFocusRequest mFocusRequest; private AudioManager.OnAudioFocusChangeListener mListener; private AudioAttributes mAttribute; @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mListener = new AudioManager.OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: // TBD 繼續播放 break; case AudioManager.AUDIOFOCUS_LOSS: // TBD 中止播放 break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: // TBD 暫停播放 break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // TBD 混音播放 break; default: break; } } }; //android 版本 5.0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mAttribute = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); } //android 版本 8.0 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) .setWillPauseWhenDucked(true) .setAcceptsDelayedFocusGain(true) .setOnAudioFocusChangeListener(mListener, mHandler) .setAudioAttributes(mAttribute) .build(); } } private void requestAudioFocus() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { int ret = mAudioManager.requestAudioFocus(mFocusRequest); if (ret == AudioManager.AUDIOFOCUS_REQUEST_FAILED) { // TBD 焦點申請失敗 不執行播放 } else if (ret == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // TBD 焦點申請成功 執行播放 } else if (ret == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { // TBD 焦點申請delay 不執行播放(這種時候通常電話中,咱們播放音樂會有這種狀態,若是ret是delay,那麼若是能夠播放的時候會收到對應AUDIOFOCUS_GAIN的callback) } } } private void abandonAudioFocus() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { mAudioManager.abandonAudioFocusRequest(mFocusRequest); } } }
以上就是App使用AudioFocus的一個簡單demo,那麼咱們在使用的時候申請一個什麼類型的焦點呢?有幾個值的含義是必定要明確的:
AUDIOFOCUS_GAIN:長時間獲取焦點,通常用於音視頻。
AUDIOFOCUS_GAIN_TRANSIENT:短暫得到,通常用於電話,語音助理等
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:混音,通常用於導航
AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:(android後加的)與AUDIOFOCUS_GAIN_TRANSIENT相似,表示一個短暫的獲取焦點,通常用於語音識別什麼的,不多用。
既然提到了電話這裏先吐槽下谷歌作的音頻焦點,那是真的爛,所以纔會有那麼多的廠商來定製音頻焦點這塊,原本一個requestAudioFocus就能夠了,但發現電話時好像不該該被其餘應用搶去焦點,那可咋整,哦,加個接口吧,因而乎 public void requestAudioFocusForCall(int streamType, int durationHint) 來了,requestAudioFocus(AudioFocusRequest requset)被更新來更新去, requestAudioFocusForCall(int streamType, int durationHint) 貌似出了以後發現不是很好在就一直沒有更新過,requestAudioFocusForCall優先級最高,也不須要返回值,方法執行成功與否也不知道,對應abandonAudioFocusForCall()也是簡單粗暴。其實我的以爲requestAudioFocusForCall(int streamType, int durationHint)這個durationHint基本能夠寫死AUDIOFOCUS_GAIN_TRANSIENT,這樣豈不更簡單粗暴。
說的有點跑題,綜上,根據這些值含義,咱們基本知道了咱們要申請什麼樣的音頻焦點,下一篇說一下申請每一種音頻焦點對應的listener會給的callback都有哪些,以及從源碼角度來分析整個音頻焦點的原理。ide
其實音頻焦點要說的還有不少,包括Car上的Audio,從下篇開始,咱們就從源碼角度一點一點分析其原理。
歸根結底音頻焦點自己是一種弱管理,只是規則的制訂,至因而否遵照是應用自身行爲,就像紅綠燈,若是你非要闖紅燈,非要逆行,音頻焦點自己控制不了交通,最終依賴車輛自身行爲。就是這個道理。
但願這篇文章,對於新接觸Android音頻焦點的朋友有一點點的幫助。
————————————————ui