多音頻播放的并發(fā)策略

2024-02-16 13:53 更新

音頻打斷策略

多音頻并發(fā),即多個音頻流同時播放。此場景下,如果系統(tǒng)不加管控,會造成多個音頻流混音播放,容易讓用戶感到嘈雜,造成不好的用戶體驗。為了解決這個問題,系統(tǒng)預設了音頻打斷策略,對多音頻播放的并發(fā)進行管控,只有持有音頻焦點的音頻流才可以正常播放,避免多個音頻流無序并發(fā)播放的現(xiàn)象出現(xiàn)。

當應用開始播放音頻時,系統(tǒng)首先為相應的音頻流申請音頻焦點,獲得焦點的音頻流可以播放;若焦點申請被拒絕,則不能播放。在音頻流播放的過程中,若被其他音頻流打斷,則會失去音頻焦點。當音頻流失去音頻焦點時,只能暫停播放。在應用播放音頻的過程中,這些動作均由系統(tǒng)自行完成,無需應用主動觸發(fā)。但為了維持應用和系統(tǒng)的狀態(tài)一致性,保證良好的用戶體驗,推薦應用監(jiān)聽音頻打斷事件,并在收到音頻打斷事件(InterruptEvent)時做出相應處理。

為滿足應用對多音頻并發(fā)策略的不同需求,音頻打斷策略預設了兩種焦點模式,針對同一應用創(chuàng)建的多個音頻流,應用可通過設置焦點模式,選擇由應用自主管控或由系統(tǒng)統(tǒng)一管控。

音頻打斷策略決定了應該對音頻流采取何種操作,如暫停播放、繼續(xù)播放、降低音量播放、恢復音量播放等,這些操作可能由系統(tǒng)或應用來執(zhí)行。音頻打斷策略預置了兩種打斷類型,用于區(qū)分音頻打斷事件(InterruptEvent)的執(zhí)行者。

焦點模式

音頻打斷策略預設了兩種焦點模式(InterruptMode):

  • 共享焦點模式(SHARE_MODE):由同一應用創(chuàng)建的多個音頻流,共享一個音頻焦點。這些音頻流之間的并發(fā)規(guī)則由應用自主決定,音頻打斷策略不會介入。當其他應用創(chuàng)建的音頻流與該應用的音頻流并發(fā)播放時,才會觸發(fā)音頻打斷策略的管控。
  • 獨立焦點模式(INDEPENDENT_MODE):應用創(chuàng)建的每一個音頻流均會獨立擁有一個音頻焦點,當多個音頻流并發(fā)播放時,會觸發(fā)音頻打斷策略的管控。

應用可以按需選擇合適的焦點模式,在創(chuàng)建音頻流時,系統(tǒng)默認采用共享焦點模式,應用可主動設置所需的模式。

設置焦點模式的方法:

打斷類型

音頻打斷策略(包括兩種焦點模式)決定了應該對各個音頻流采取何種操作,如暫停播放、繼續(xù)播放、降低音量播放、恢復音量播放等。而針對這些操作的執(zhí)行過程,根據(jù)執(zhí)行者的不同,可以分為兩種打斷類型(InterruptForceType):

  • 強制打斷類型(INTERRUPT_FORCE):由系統(tǒng)進行操作,強制打斷音頻播放。
  • 共享打斷類型(INTERRUPT_SHARE):由應用進行操作,可以選擇打斷或忽略。

對于音頻打斷策略的執(zhí)行,系統(tǒng)默認采用強制打斷類型(INTERRUPT_FORCE),應用無法更改。但對于一些策略(如繼續(xù)播放等),系統(tǒng)無法強制執(zhí)行,所以這兩種打斷類型均可能出現(xiàn)。應用可根據(jù)音頻打斷事件(InterruptEvent)的成員變量forceType的值,獲取該事件采用的打斷類型。

在應用播放音頻的過程中,系統(tǒng)自動為音頻流執(zhí)行申請焦點、持有焦點、釋放焦點等動作,當發(fā)生音頻打斷事件時,系統(tǒng)強制對音頻流執(zhí)行暫停、停止、降低音量、恢復音量等操作,并向應用發(fā)送音頻打斷事件(InterruptEvent)回調(diào)。由于系統(tǒng)會強制改變音頻流狀態(tài),為了維持應用和系統(tǒng)的狀態(tài)一致性,保證良好的用戶體驗,推薦應用監(jiān)聽音頻打斷事件,并在收到音頻打斷事件(InterruptEvent)時做出相應處理。

對于一些系統(tǒng)無法強制執(zhí)行的操作(例如音頻流繼續(xù)播放的場景),會向應用發(fā)送包含了共享打斷類型的音頻打斷事件,由應用自行執(zhí)行相應操作,此時應用可以選擇執(zhí)行或忽略,系統(tǒng)不會干涉。

監(jiān)聽音頻打斷事件

在應用播放音頻時,推薦應用監(jiān)聽音頻打斷事件,當音頻打斷事件發(fā)生時,系統(tǒng)會根據(jù)預設策略,對音頻流做出相應的操作,并針對狀態(tài)發(fā)生改變的音頻流,向所屬的應用發(fā)送音頻打斷事件。

應用收到音頻打斷事件后,需根據(jù)其內(nèi)容提示,做出相應的處理,避免出現(xiàn)應用狀態(tài)與預期效果不一致的問題。

監(jiān)聽音頻打斷事件的方法:

為了帶給用戶更好的體驗,針對不同的音頻打斷事件內(nèi)容,應用需要做出相應的處理操作。此處以使用AudioRenderer開發(fā)音頻播放功能為例,展示推薦應用采取的處理方法,提供偽代碼供開發(fā)者參考(若使用AVPlayer開發(fā)音頻播放功能,處理方法類似),具體的代碼實現(xiàn),開發(fā)者可結(jié)合實際情況編寫,處理方法也可自行調(diào)整。
  1. let isPlay; // 是否正在播放,實際開發(fā)中,對應與音頻播放狀態(tài)相關的模塊
  2. let isDucked; //是否降低音量,實際開發(fā)中,對應與音頻音量相關的模塊
  3. let started; // 標識符,記錄“開始播放(start)”操作是否成功
  4. async function onAudioInterrupt(){
  5. // 此處以使用AudioRenderer開發(fā)音頻播放功能舉例,變量audioRenderer即為播放時創(chuàng)建的AudioRenderer實例。
  6. audioRenderer.on('audioInterrupt', async(interruptEvent) => {
  7. // 在發(fā)生音頻打斷事件時,audioRenderer收到interruptEvent回調(diào),此處根據(jù)其內(nèi)容做相應處理
  8. // 先讀取interruptEvent.forceType的類型,判斷系統(tǒng)是否已強制執(zhí)行相應操作
  9. // 再讀取interruptEvent.hintType的類型,做出相應的處理
  10. if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_FORCE) {
  11. // 強制打斷類型(INTERRUPT_FORCE):音頻相關處理已由系統(tǒng)執(zhí)行,應用需更新自身狀態(tài),做相應調(diào)整
  12. switch (interruptEvent.hintType) {
  13. case audio.InterruptHint.INTERRUPT_HINT_PAUSE:
  14. // 此分支表示系統(tǒng)已將音頻流暫停(臨時失去焦點),為保持狀態(tài)一致,應用需切換至音頻暫停狀態(tài)
  15. // 臨時失去焦點:待其他音頻流釋放音頻焦點后,本音頻流會收到resume對應的音頻打斷事件,到時可自行繼續(xù)播放
  16. isPlay = false; // 此句為簡化處理,代表應用切換至音頻暫停狀態(tài)的若干操作
  17. break;
  18. case audio.InterruptHint.INTERRUPT_HINT_STOP:
  19. // 此分支表示系統(tǒng)已將音頻流停止(永久失去焦點),為保持狀態(tài)一致,應用需切換至音頻暫停狀態(tài)
  20. // 永久失去焦點:后續(xù)不會再收到任何音頻打斷事件,若想恢復播放,需要用戶主動觸發(fā)。
  21. isPlay = false; // 此句為簡化處理,代表應用切換至音頻暫停狀態(tài)的若干操作
  22. break;
  23. case audio.InterruptHint.INTERRUPT_HINT_DUCK:
  24. // 此分支表示系統(tǒng)已將音頻音量降低(默認降到正常音量的20%),為保持狀態(tài)一致,應用需切換至降低音量播放狀態(tài)
  25. // 若應用不接受降低音量播放,可在此處選擇其他處理方式,如主動暫停等
  26. isDucked = true; // 此句為簡化處理,代表應用切換至降低音量播放狀態(tài)的若干操作
  27. break;
  28. case audio.InterruptHint.INTERRUPT_HINT_UNDUCK:
  29. // 此分支表示系統(tǒng)已將音頻音量恢復正常,為保持狀態(tài)一致,應用需切換至正常音量播放狀態(tài)
  30. isDucked = false; // 此句為簡化處理,代表應用切換至正常音量播放狀態(tài)的若干操作
  31. break;
  32. default:
  33. break;
  34. }
  35. } else if (interruptEvent.forceType === audio.InterruptForceType.INTERRUPT_SHARE) {
  36. // 共享打斷類型(INTERRUPT_SHARE):應用可自主選擇執(zhí)行相關操作或忽略音頻打斷事件
  37. switch (interruptEvent.hintType) {
  38. case audio.InterruptHint.INTERRUPT_HINT_RESUME:
  39. // 此分支表示臨時失去焦點后被暫停的音頻流此時可以繼續(xù)播放,建議應用繼續(xù)播放,切換至音頻播放狀態(tài)
  40. // 若應用此時不想繼續(xù)播放,可以忽略此音頻打斷事件,不進行處理即可
  41. // 繼續(xù)播放,此處主動執(zhí)行start(),以標識符變量started記錄start()的執(zhí)行結(jié)果
  42. await audioRenderer.start().then(async function () {
  43. started = true; // start()執(zhí)行成功
  44. }).catch((err) => {
  45. started = false; // start()執(zhí)行失敗
  46. });
  47. // 若start()執(zhí)行成功,則切換至音頻播放狀態(tài)
  48. if (started) {
  49. isPlay = true; // 此句為簡化處理,代表應用切換至音頻播放狀態(tài)的若干操作
  50. } else {
  51. // 音頻繼續(xù)播放執(zhí)行失敗
  52. }
  53. break;
  54. default:
  55. break;
  56. }
  57. }
  58. });
  59. }
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號