Web Autoplay 的限制

Photo by Markus Spiske on Unsplash
Photo by Markus Spiske on Unsplash

現在網頁上充斥著各式類型的資訊,有圖片、影音等等,今天要筆記一下在網頁上,關於影音自動播放的一些限制。

以日常大家最常使用的 facebook(?)作為舉例,你可能會注意到 facebook 的 Timeline 上有各式各樣的資訊,其中在影片的部分預設都是無聲音的,回想一下以前在無名小站,有些部落格一進去,馬上就有音樂播放,好聽的音樂大家會覺得很悅耳,但每個人的喜好不同,你播放的音樂不一定是別人喜歡的,某種程度上或許會給別人帶來一些困擾。

Autoplay Policy

那麼,影音在 Web 上,預設到底可不可以讓聲音自動播放呢?在早期瀏覽器是允許這個行為的,但現在是不允許的,但在一些條件下,還是可以自動播放的:

  • 靜音允許自動播放(Muted autoplay is always allowed)
  • 使用者與瀏覽器有所互動(例如:click, touch 事件)
  • 頂部 frame 可以將自動播放權限委託給他們的 iframe,允許自動播放聲音

以影片播放來舉例:

<video
id="video"
controls="controls"
preload="none"
poster="http://media.w3.org/2010/05/sintel/poster.png"
>
<source src="http://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4" />
</video>

若是透過 JavaScript 來操控這個 Video 來讓他自動播放:

const [video] = document.getElementById('video');
video.play();

會得到如下的錯誤:

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

意思是,如果使用者和瀏覽器沒有互動的話,play() 會失敗;如果想要解決這個問題可以根據上面的方式,在 video 上加入 muted 的 tag,這樣 JavaScript 就可以成功執行 play() 方法。

<video
id="video"
controls="controls"
preload="none"
poster="http://media.w3.org/2010/05/sintel/poster.png"
muted
>
<source src="http://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4" />
</video>

play() 方法是非同步的

當你呼叫 play() 方法時,可能會遇到以下的錯誤:

  1. Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().
  2. Uncaught (in promise) DOMException: The play() request was interrupted by a new load request.

這是因為 play() 方法是非同步的,當你呼叫 play() 方法後,隨著呼叫 pause() 方法,這時候 meida 還沒完全載入完全,所以會造成錯誤。

在 Chrome 50 版本後的 audiovideo 都是回傳都是一個 Promise,確保 media 完全載入後,再執行其他的動作,推薦的方式如下:

// Show loading animation.
const videoPromise = video.play();
if (videoPromise !== undefined) {
playPromise.then(() => {
// Automatic playback started!
// Show playing UI.
})
.catch(error => {
// Auto-play was prevented
// Show paused UI.
});
}

Reference