轉(zhuǎn)載請注明出處:http://www.itdecent.cn/p/5d8d7b677690
2017年開年第一篇博客,很早就想總結(jié)一下Android音頻的相關(guān)知識。
今天我們先來看一下音頻焦點的相關(guān)內(nèi)容,分為上下篇,上篇主要介紹音頻焦點在媒體類應(yīng)用中的使用,下篇進(jìn)行源碼分析,我們學(xué)習(xí)源碼不僅僅是為了更深入的了解,更主要的目的是學(xué)習(xí)Android的設(shè)計架構(gòu),為我們在平時開發(fā)過程中提供一些優(yōu)秀的設(shè)計思想。
一 焦點在Android應(yīng)用中的作用
我們的手機里經(jīng)常會安裝一些媒體類的應(yīng)用,例如網(wǎng)易云音樂,QQ音樂,愛奇藝視頻,優(yōu)酷視頻等等,你有沒有想過,當(dāng)我們聽QQ音樂的歌曲時,切換到網(wǎng)易云音樂播放歌曲,或者打開愛奇藝觀看視頻時,QQ音樂播放的歌曲就會暫停,這是為什么呢?又是如何實現(xiàn)的呢?如果不暫停會是什么效果呢?
以上這些疑問都可以用音頻焦點來解釋,在下面的內(nèi)容中你將找到答案。
二 焦點講解
眾所周知Android是一個開放的系統(tǒng),為了協(xié)調(diào)各媒體應(yīng)用之間的關(guān)系,Android增加了音頻焦點管理機制,各應(yīng)用開發(fā)者應(yīng)盡量遵循該機制進(jìn)行開發(fā)。
我們通過一個例子來講解Android的焦點機制。
新建一個Activity,在其中增加一個播放暫停按鈕,來控制音樂播放。
看一下部分關(guān)鍵代碼,全部代碼在文末會給出
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 獲取音頻文件,我從網(wǎng)上下載的歌曲,放到了assets目錄下
fileDescriptor = this.getAssets().openFd("littlelucky.mp3");
//4 實例化MediaPlayer對象
mMediaPlayer = new MediaPlayer();
//5 設(shè)置播放流類型
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
//6 設(shè)置播放源,有多個參數(shù)可以選擇,具體參考相關(guān)文檔,本文旨在介紹音頻焦點
mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
fileDescriptor.getStartOffset(),
fileDescriptor.getLength());
//7 設(shè)置循環(huán)播放
mMediaPlayer.setLooping(true);
//8 準(zhǔn)備監(jiān)聽
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//9 準(zhǔn)備完成后自動播放
mMediaPlayer.start();
}
});
//10 異步準(zhǔn)備
mMediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}
涉及到的MediaPlayer播放音樂流程請自行查詢相關(guān)文檔,不在本文介紹范圍
我們重點看一下第2步 申請焦點
通過AudioManager對象調(diào)用requestAudioFocus方法,有三個參數(shù)
OnAudioFocusChangeListener l,int streamType,int durationHint
1 焦點變化的監(jiān)聽器
private AudioManager.OnAudioFocusChangeListener mAudioFocusChange = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange){
case AudioManager.AUDIOFOCUS_LOSS:
//長時間丟失焦點,當(dāng)其他應(yīng)用申請的焦點為AUDIOFOCUS_GAIN時,
//會觸發(fā)此回調(diào)事件,例如播放QQ音樂,網(wǎng)易云音樂等
//通常需要暫停音樂播放,若沒有暫停播放就會出現(xiàn)和其他音樂同時輸出聲音
Log.d(TAG, "AUDIOFOCUS_LOSS");
stop();
//釋放焦點,該方法可根據(jù)需要來決定是否調(diào)用
//若焦點釋放掉之后,將不會再自動獲得
mAudioManager.abandonAudioFocus(mAudioFocusChange);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
//短暫性丟失焦點,當(dāng)其他應(yīng)用申請AUDIOFOCUS_GAIN_TRANSIENT或AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE時,
//會觸發(fā)此回調(diào)事件,例如播放短視頻,撥打電話等。
//通常需要暫停音樂播放
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:
//當(dāng)其他應(yīng)用申請焦點之后又釋放焦點會觸發(fā)此回調(diào)
//可重新播放音樂
Log.d(TAG, "AUDIOFOCUS_GAIN");
start();
break;
}
}
};
2 streamType音源類型,在AudioManager中定義
/** 通話 */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** 系統(tǒng)聲音 */
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 藍(lán)牙電話 */
public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
/** @hide 強制的系統(tǒng)聲音 */
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 //短暫性獲得焦點,用完應(yīng)立即釋放
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK //短暫性獲得焦點并降音,可混音播放
AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE //短暫性獲得焦點,錄音或者語音識別
我們可根據(jù)自己的應(yīng)用的使用場景來合理的配置每個參數(shù),并在焦點變化監(jiān)聽器來做相應(yīng)的處理。
調(diào)試代碼已上傳github,歡迎訪問