1. 程式人生 > >Chrome 聲音自動播放抱錯問題【play() failed】

Chrome 聲音自動播放抱錯問題【play() failed】

Chrome下呼叫play後抱錯:DOMException: play() failed because the user didn't interact with the document first.

聲音無法自動播放這個在IOS/Android上面一直是個慣例,桌面版的Safari在2017年的11版本也宣佈禁掉帶有聲音的多媒體自動播放功能,緊接著在2018年4月份釋出的Chrome 66也正式關掉了聲音自動播放,也就是說

<audio autopaly></audio> <video autoplay></video>

在桌面版瀏覽器也將失效。

最開始移動端瀏覽器是完全禁止音視訊自動播放的,考慮到了手機的頻寬以及對電池的消耗。但是後來又改了,因為瀏覽器廠商發現網頁開發人員可能會使用GIF動態圖代替視訊實現自動播放,正如IOS文件所說,使用GIF的頻寬流量是Video(h264)格式的12倍,而播放效能消耗是2倍,所以這樣對使用者反而是不利的。又或者是使用Canvas進行hack,如Android Chrome文件提到。因此瀏覽器廠商放開了對多媒體自動播放的限制,只要具備以下條件就能自動播放:

(1)沒音訊軌道,或者設定了muted屬性

(2)在視圖裡面是可見的,要插入到DOM裡面並且不是display: none或者visibility: hidden的,沒有滑出可視區域。

換句話說,只要你不開聲音擾民,且對使用者可見,就讓你自動播放,不需要你去使用GIF的方法進行hack.桌面版的瀏覽器在近期也使用了這個策略

對於網頁開發人員來說,應當如何有效地規避這個風險呢?

Chrome的文件給了一個最佳實踐:先把音視訊加一個muted的屬性就可以自動播放,然後再顯示一個聲音被關掉的按鈕,提示使用者點一下開啟聲音。對於視訊來說,確實可以這樣處理,而對於音訊來說,很多人是監聽頁面點選事件,只要點一次了就開始播放聲音,一般就是播放個背景音樂。但是如果對於有多個聲音資源的頁面來說如何自動播放多個聲音呢?

首先,如果使用者還沒進行互動就呼叫播放聲音的API,Chrome會這麼提示:

DOMException: play() failed because the user didn't interact with the document first.

Safari會這麼提示:

NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.

Chrome報錯提示最為友善,意思是說,使用者還沒有互動,不能調play。使用者的互動包括哪些呢?包括使用者觸發的touchend, click, doubleclick或者是 keydown事件,在這些事件裡面就能調play.

所以上面提到很多人是監聽整個頁面的點選事件進行播放,不管點的哪裡,只要點了就行,包括觸控下滑。這種方法只適用於一個聲音資源,不適用多個聲音,多個聲音應該怎麼破呢?這裡並不是說要和瀏覽器對著幹,“逆天而行”,我們的目的還是為了提升使用者體驗,因為有些場景如果能自動播放確實比較好,如一些答題的場景,需要聽聲音進行答題,如果使用者在答題的過程中能依次自動播放相應題目的聲音,確實比較方便。同時也是討論聲音播放的技術實現。

原生播放視訊應該就只能使用video標籤,而原生播放音訊除了使用audio標籤之外,還有另外一個API叫AudioContext,它是能夠用來控制聲音播放並帶了很多豐富的操控介面。調audio.play必須在點選事件裡面響應,而使用AudioContext的區別在於只要使用者點過頁面任何一個地方之後就都能播放了。所以可以用AudioContext取代audio標籤播放聲音。

對於移動端開發可考慮用原生AudioContext,使用參考:https://juejin.im/post/5af7129bf265da0b8262df4c

對於瀏覽器pc網頁可以不用這麼麻煩,設定了muted屬性就可以繞過去,解決方案就是預設先加上muted標籤,要播放的時候先關掉靜音,再呼叫play方法播放就可以。