轉載請註明出處: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,歡迎訪問