[轉載]Android10.0AudioFocus之如何使用(一)

前言

對於音頻焦點,不少人會感到很陌生,也很迷惑,不清楚音頻焦點到底處理什麼的,怎麼用。有人說要播放音樂,必須先申請焦點,只有拿到焦點後才能播放音樂,可也有人說我不申請音頻焦點也能播放音樂,所以,今天咱們就來講說到底什麼是音頻焦點。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

相關文章
相關標籤/搜索