多媒體音頻焦點(diǎn)
意義
多個(gè)音源可以同時(shí)向同一個(gè)輸出流進(jìn)行播放音頻,如果沒有音頻焦點(diǎn)管控,就會出現(xiàn)多個(gè)音源同時(shí)播放的現(xiàn)象,給用戶帶來不便;而Android為了避免多個(gè)音源同時(shí)播放,就引入了音頻焦點(diǎn)的概念,所有音頻應(yīng)用都統(tǒng)一按照音頻焦點(diǎn)的規(guī)定執(zhí)行,就可以避免該現(xiàn)象發(fā)生。
當(dāng)應(yīng)用需要播放音頻時(shí),需要主動申請音頻焦點(diǎn),獲取音頻焦點(diǎn)后,再進(jìn)行播放操作;同時(shí)在播放過程中,也可能存在其他音源請求焦點(diǎn),此時(shí)當(dāng)前應(yīng)用就會收到音頻焦點(diǎn)的丟失,當(dāng)前應(yīng)用應(yīng)暫停播放或者降低音量,方便用戶聽其他音源。
規(guī)范
準(zhǔn)則
- 在播放之前通過調(diào)用
requestAudioFocus
,確認(rèn)返回的結(jié)果是否為AUDIOFOCUS_REQUEST_GRANTED
- 在其他應(yīng)用獲取到焦點(diǎn)時(shí),停止或暫停播放,或降低音量
- 播放停止后,主動釋放焦點(diǎn)
版本處理
- 從
Android 2.2
開始,應(yīng)用通過調(diào)用requestAudioFocus()
和abandonAudioFocus()
來管理音頻焦點(diǎn)。應(yīng)用還必須為這兩個(gè)調(diào)用注冊AudioManager.OnAudioFocusChangeListener
,以便接收回調(diào)并管理自己的音量。- 對于以
Android 5.0
及更高版本為目標(biāo)平臺的應(yīng)用,音頻應(yīng)用應(yīng)使用AudioAttributes
來描述應(yīng)用正在播放的音頻類型。例如,播放語音的應(yīng)用應(yīng)指定CONTENT_TYPE_SPEECH
。- 面向
Android 8.0
或更高版本的應(yīng)用應(yīng)使用requestAudioFocus()
方法,該方法會接受AudioFocusRequest
參數(shù)。AudioFocusRequest
包含有關(guān)應(yīng)用的音頻上下文和功能的信息。系統(tǒng)使用這些信息來自動管理音頻焦點(diǎn)的得到和失去。
使用
請求焦點(diǎn)
申請焦點(diǎn)時(shí),需要明確焦點(diǎn)類型:
-
AudioManager.AUDIOFOCUS_GAIN
:表示應(yīng)用程序需要長時(shí)間獲得音頻焦點(diǎn),通常用于播放音樂或其他持續(xù)性的音頻播放。應(yīng)用程序在獲得焦點(diǎn)后可以持續(xù)播放音頻,直到明確放棄焦點(diǎn)或其他應(yīng)用程序請求焦點(diǎn)。 -
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
:表示應(yīng)用程序需要短暫地獲得音頻焦點(diǎn),通常用于播放短暫的音效或提示音。應(yīng)用程序在獲得焦點(diǎn)后可以播放音頻,但在完成后應(yīng)立即釋放焦點(diǎn),以便其他應(yīng)用程序可以繼續(xù)使用焦點(diǎn)。 -
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
:表示應(yīng)用程序需要短暫地獲得音頻焦點(diǎn),并且希望其他應(yīng)用程序不要同時(shí)播放音頻。這種焦點(diǎn)類型用于應(yīng)用程序需要短時(shí)間內(nèi)獨(dú)占音頻焦點(diǎn)的情況,例如語音識別應(yīng)用。 -
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
:表示應(yīng)用程序需要短暫地獲得音頻焦點(diǎn),但愿意降低音頻的音量以便與其他應(yīng)用程序共享焦點(diǎn)。通常用于類似通知聲音或?qū)Ш教崾镜那闆r
獲取音頻焦點(diǎn)結(jié)果,有以下類型:
-
AudioManager.AUDIOFOCUS_REQUEST_GRANTED
:表示應(yīng)用程序成功獲取了音頻焦點(diǎn)。這意味著應(yīng)用程序現(xiàn)在可以在其他應(yīng)用程序不需要音頻焦點(diǎn)時(shí)播放音頻。 -
AudioManager.AUDIOFOCUS_REQUEST_FAILED
:表示應(yīng)用程序請求音頻焦點(diǎn)失敗。這可能是因?yàn)槠渌麘?yīng)用程序已經(jīng)擁有了音頻焦點(diǎn),或者系統(tǒng)無法滿足應(yīng)用程序的請求。 -
AudioManager.AUDIOFOCUS_REQUEST_DELAYED
:表示應(yīng)用程序的音頻焦點(diǎn)請求被暫時(shí)延遲。當(dāng)其他應(yīng)用程序釋放音頻焦點(diǎn)時(shí),系統(tǒng)會嘗試重新分配焦點(diǎn)給應(yīng)用程序。
版本處理
在Android8.0
之前,需要通過AudioFocusRequest
,以及實(shí)現(xiàn)AudioManager.OnAudioFocusChangeListener
接口進(jìn)行監(jiān)聽音頻焦點(diǎn)變化
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int state) {
switchFocus(state);
}
};
int requestAudioFocusResult = audioManager.requestAudioFocus(onAudioFocusChangeListener,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (requestAudioFocusResult == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
//請求焦點(diǎn)失敗
} else if (requestAudioFocusResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
//請求焦點(diǎn)成功
}
public void switchFocus(int focus) {
switch (focus) {
case AudioManager.AUDIOFOCUS_GAIN:
break;
case AudioManager.AUDIOFOCUS_LOSS:
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
break;
}
}
在Android8.0
之后,需要通過AudioFocusRequest
,AudioAttributes
,以及實(shí)現(xiàn)AudioManager.OnAudioFocusChangeListener
接口進(jìn)行監(jiān)聽音頻焦點(diǎn)變化
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
AudioManager.OnAudioFocusChangeListener onAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int state) {
switchFocus(state);
}
};
AudioAttributes attributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
AudioFocusRequest audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(attributes)
.setAcceptsDelayedFocusGain(true)
.setOnAudioFocusChangeListener(onAudioFocusChangeListener)
.setWillPauseWhenDucked(false)
.build();
int requestAudioFocusResult = audioManager.requestAudioFocus(audioFocusRequest);
if (requestAudioFocusResult == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
//請求焦點(diǎn)失敗
} else if (requestAudioFocusResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
//請求焦點(diǎn)成功
} else if (requestAudioFocusResult == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
//延時(shí)焦點(diǎn)
}
延遲獲取焦點(diǎn)
如上面所述,我們發(fā)現(xiàn)在Android 8.0之前,請求音頻焦點(diǎn)的時(shí)候,只會返回兩種結(jié)果,要么請求成功(AUDIOFOCUS_REQUEST_GRANTED
),要么請求失敗(AUDIOFOCUS_REQUEST_FAILED
)。
而從Android 8.0開始,還有一種結(jié)果,延遲成功請求(AUDIOFOCUS_REQUEST_DELAYED
),這個(gè)也是成功的請求,但是這個(gè)請求具有延遲性;
方法 setAcceptsDelayedFocusGain(true)
可讓您的應(yīng)用異步處理焦點(diǎn)請求。設(shè)置此標(biāo)記后,在焦點(diǎn)鎖定時(shí)發(fā)出的請求會返回 AUDIOFOCUS_REQUEST_DELAYED
。當(dāng)鎖定音頻焦點(diǎn)的情況不再存在時(shí)(例如當(dāng)通話結(jié)束時(shí)),系統(tǒng)會批準(zhǔn)待處理的焦點(diǎn)請求,通過注冊AudioFocusChangeListener
監(jiān)聽的 onAudioFocusChange()
來通知您的應(yīng)用。
自動降低音量
在 Android 8.0(API 級別 26)中,當(dāng)其他應(yīng)用使用 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
請求焦點(diǎn)時(shí),系統(tǒng)可以在不調(diào)用應(yīng)用的 onAudioFocusChange()
回調(diào)的情況下降低和恢復(fù)音量。
在某些情境下,可能不需要降低音量而是直接暫停,這是可以通過setWillPauseWhenDucked(true)
方法取消系統(tǒng)的默認(rèn)行為,然后通過OnAudioFocusChangeListener
的onAudioFocusChange
回調(diào)中監(jiān)聽音頻焦點(diǎn)變化
AudioAttributes
用來描述該應(yīng)用使用情況,通過Builder模式進(jìn)行構(gòu)建
Usage
(用途):(必須)用于描述音頻的使用場景,持續(xù)時(shí)間,例如AudioAttributes.USAGE_MEDIA
用于媒體播放,AudioAttributes.USAGE_VOICE_COMMUNICATION
用于語音通信等。ContentType
(內(nèi)容類型):用于描述音頻的內(nèi)容類型,例如AudioAttributes.CONTENT_TYPE_MUSIC
用于音樂,AudioAttributes.CONTENT_TYPE_SPEECH
用于語音等。Flags
(標(biāo)志):用于指定一些特定的標(biāo)志,例如AudioAttributes.FLAG_AUDIBILITY_ENFORCED
表示強(qiáng)制性可聽性,AudioAttributes.FLAG_HW_AV_SYNC
表示硬件音視頻同步等。Legacy Stream Type
(傳統(tǒng)流類型):用于與舊版API
兼容,將AudioAttributes
映射到舊版的音頻流類型,例如AudioAttributes.STREAM_MUSIC
AudioFocusRequest
用來請求獲取焦點(diǎn)的詳細(xì)信息和參數(shù)
Builder()
:參數(shù)代表請求焦點(diǎn)級別持續(xù)時(shí)間。setAudioAttributes
:用于描述音頻焦點(diǎn)請求的屬性setAcceptsDelayedFocusGain
:延遲音頻焦點(diǎn)獲取是指應(yīng)用程序在請求音頻焦點(diǎn)時(shí),如果焦點(diǎn)當(dāng)前不可用,是否愿意等待一段時(shí)間,直到焦點(diǎn)可用為止;參數(shù)默認(rèn)為true,表示應(yīng)用程序愿意等待焦點(diǎn)可用。如果將參數(shù)設(shè)置為false
,則表示應(yīng)用程序不接受延遲焦點(diǎn)獲取,如果焦點(diǎn)當(dāng)前不可用,則請求會立即返回失敗。setWillPauseWhenDucked
:用于設(shè)置當(dāng)應(yīng)用程序的音頻焦點(diǎn)被降低時(shí)是否暫停音頻播放。當(dāng)應(yīng)用程序的音頻焦點(diǎn)被其他應(yīng)用程序請求并且獲得時(shí),系統(tǒng)可能會降低應(yīng)用程序的音量以便讓焦點(diǎn)持有者能夠播放音頻。參數(shù)默認(rèn)值為true
,表示應(yīng)用程序在焦點(diǎn)被降低時(shí)會暫停音頻播放。如果將參數(shù)設(shè)置為false
,則表示應(yīng)用程序在焦點(diǎn)降低時(shí)不會暫停音頻播放,而是繼續(xù)以降低的音量播放。setOnAudioFocusChangeListener
:用于設(shè)置監(jiān)聽音頻焦點(diǎn)變化的回調(diào)接口;當(dāng)應(yīng)用程序請求音頻焦點(diǎn)并且焦點(diǎn)狀態(tài)發(fā)生變化時(shí),系統(tǒng)會調(diào)用注冊的AudioFocusChangeListener
接口的回調(diào)方法,通知應(yīng)用程序焦點(diǎn)狀態(tài)的變化
onAudioFocusChangeListener
AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int state) {
switch (focus) {
// 重新獲取音頻焦點(diǎn)
// 恢復(fù)播放
case AudioManager.AUDIOFOCUS_GAIN:
break;
// 永久丟失焦點(diǎn)
// 此時(shí)應(yīng)該停止播放,釋放資源
case AudioManager.AUDIOFOCUS_LOSS:
break;
// 短暫丟失焦點(diǎn)
// 但是很快就會重新獲得,在此狀態(tài)應(yīng)該暫停所有音頻播放
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
break;
// 瞬間丟失焦點(diǎn)
// 暫時(shí)失去焦點(diǎn),但是允許持續(xù)播放音頻(以很小的聲音),不需要完全停止播放
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
break;
}
}
};
釋放焦點(diǎn)
在Android8.0之前通過以下方法釋放焦點(diǎn),參數(shù)為之前申請焦點(diǎn)創(chuàng)建的監(jiān)聽OnAudioFocusChangeListener
。
audioManager.abandonAudioFocus(onAudioFocusChangeListener);
在Android8.0之后則通過如下方法釋放,參數(shù)為之前申請焦點(diǎn)時(shí)創(chuàng)建的AudioFocusRequest
。文章來源:http://www.zghlxwxcb.cn/news/detail-643622.html
audioManager.abandonAudioFocusRequest(audioFocusRequest);
注意主動abandon焦點(diǎn)的時(shí)候是不會回調(diào)監(jiān)聽的文章來源地址http://www.zghlxwxcb.cn/news/detail-643622.html
到了這里,關(guān)于多媒體音頻焦點(diǎn)淺析的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!