Android音頻焦點詳解(上)

轉載請註明出處:http://blog.csdn.net/wangjihuanghun/article/details/54957459


2017年開年第一篇博客,很早就想總結一下Android音頻的相關知識。
今天我們先來看一下音頻焦點的相關內容,分爲上下篇,上篇主要介紹音頻焦點在媒體類應用中的使用,下篇進行源碼分析,我們學習源碼不僅僅是爲了更深入的瞭解,更主要的目的是學習Android的設計架構,爲我們在平時開發過程中提供一些優秀的設計思想。

一 焦點在Android應用中的作用

我們的手機裏經常會安裝一些媒體類的應用,例如網易雲音樂,QQ音樂,愛奇藝視頻,優酷視頻等等,你有沒有想過,當我們聽QQ音樂的歌曲時,切換到網易雲音樂播放歌曲,或者打開愛奇藝觀看視頻時,QQ音樂播放的歌曲就會暫停,這是爲什麼呢?又是如何實現的呢?如果不暫停會是什麼效果呢?
以上這些疑問都可以用音頻焦點來解釋,在下面的內容中你將找到答案。

二 焦點講解

衆所周知Android是一個開放的系統,爲了協調各媒體應用之間的關係,Android增加了音頻焦點管理機制,各應用開發者應儘量遵循該機制進行開發。
我們通過一個例子來講解Android的焦點機制。
新建一個Activity,在其中增加一個播放暫停按鈕,來控制音樂播放。
看一下部分關鍵代碼,全部代碼在文末會給出

    private void initData() {
        //1 初始化AudioManager對象
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        //2 申請焦點
        mAudioManager.requestAudioFocus(mAudioFocusChange, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        AssetFileDescriptor fileDescriptor;
        try {
            //3 獲取音頻文件,我從網上下載的歌曲,放到了assets目錄下
            fileDescriptor = this.getAssets().openFd("littlelucky.mp3");
            //4 實例化MediaPlayer對象
            mMediaPlayer = new MediaPlayer();
            //5 設置播放流類型
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            //6 設置播放源,有多個參數可以選擇,具體參考相關文檔,本文旨在介紹音頻焦點
            mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
                    fileDescriptor.getStartOffset(),
                    fileDescriptor.getLength());
            //7 設置循環播放
            mMediaPlayer.setLooping(true);
            //8 準備監聽
            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    //9 準備完成後自動播放
                    mMediaPlayer.start();
                }
            });
            //10 異步準備
            mMediaPlayer.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

涉及到的MediaPlayer播放音樂流程請自行查詢相關文檔,不在本文介紹範圍
我們重點看一下第2步 申請焦點
通過AudioManager對象調用requestAudioFocus方法,有三個參數
OnAudioFocusChangeListener l,int streamType,int durationHint
1 焦點變化的監聽器

private AudioManager.OnAudioFocusChangeListener mAudioFocusChange = new AudioManager.OnAudioFocusChangeListener() {
        @Override
        public void onAudioFocusChange(int focusChange) {
            switch (focusChange){
                case AudioManager.AUDIOFOCUS_LOSS:
                    //長時間丟失焦點,當其他應用申請的焦點爲AUDIOFOCUS_GAIN時,
                    //會觸發此回調事件,例如播放QQ音樂,網易雲音樂等
                    //通常需要暫停音樂播放,若沒有暫停播放就會出現和其他音樂同時輸出聲音
                    Log.d(TAG, "AUDIOFOCUS_LOSS");
                    stop();
                    //釋放焦點,該方法可根據需要來決定是否調用
                    //若焦點釋放掉之後,將不會再自動獲得
                    mAudioManager.abandonAudioFocus(mAudioFocusChange);
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                    //短暫性丟失焦點,當其他應用申請AUDIOFOCUS_GAIN_TRANSIENT或AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE時,
                    //會觸發此回調事件,例如播放短視頻,撥打電話等。
                    //通常需要暫停音樂播放
                    stop();
                    Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT");
                    break;
                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                    //短暫性丟失焦點並作降音處理
                    Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
                    break;
                case AudioManager.AUDIOFOCUS_GAIN:
                    //當其他應用申請焦點之後又釋放焦點會觸發此回調
                    //可重新播放音樂
                    Log.d(TAG, "AUDIOFOCUS_GAIN");
                    start();
                    break;
            }
        }
    };

2 streamType音源類型,在AudioManager中定義

/** 通話 */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** 系統聲音 */
public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
/** 鈴聲 */
public static final int STREAM_RING = AudioSystem.STREAM_RING;
/** 音樂 */
public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
/** 鬧鈴聲 */
public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
/** 通知音 */
public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
/** @hide 藍牙電話 */
public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
/** @hide 強制的系統聲音 */
public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
/** DTMF撥號音 */
public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
/** @hide 文本識別音 */
public static final int STREAM_TTS = AudioSystem.STREAM_TTS;

3 durationHint 獲得焦點的時間長短
在AudioManager中定義了四種類型

AUDIOFOCUS_GAIN //長時間獲得焦點
AUDIOFOCUS_GAIN_TRANSIENT //短暫性獲得焦點,用完應立即釋放
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK //短暫性獲得焦點並降音,可混音播放
AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE //短暫性獲得焦點,錄音或者語音識別

我們可根據自己的應用的使用場景來合理的配置每個參數,並在焦點變化監聽器來做相應的處理。
調試代碼已上傳github,歡迎訪問

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章