如何检测 Chrome/Safari/Firefox 是否阻止了视频的自动播放?

How to detect if Chrome/Safari/Firefox prevented autoplay for video?

背景

自 Chrome 版本 66 起,如果用户之前没有访问过我的网站,则本应在我的网站上自动播放的视频可能无法播放。

<video src="..." autoplay></video>

问题

如何检测视频自动播放是否被禁用?我该怎么办?

autoplay 属性

根据网络标准规范,autoplay 属性应该只是一个提示 浏览器应该如何处理媒体元素。 W3 of WHATWG 网络规范都没有提及何时阻止媒体自动播放,这意味着每个浏览器可能有不同的实现。

自动播放政策

每个浏览器实施的自动播放政策现在决定是否允许视频自动播放。

  • Chrome 使用他们称为媒体的东西 参与指数,您可以阅读更多相关信息 here and their autoplay policy here

  • Safari 开发者制作了 post on webkit.org 关于这个。

  • Firefox 似乎将其交由用户选择是否允许 (link)。

最佳实践

检测自动播放是否被禁用

您可以在 videoaudio 元素上使用 play() 方法来开始播放您的媒体,而不是在您的元素上使用 autoplayplay() 方法 returns 现代浏览器中的承诺(全部根据规范)。如果 promise 被拒绝,则可能表示您网站上的当前浏览器已禁用自动播放。

can-autoplay 是一个专门用于检测视频和音频元素的自动播放功能的库。

如果自动播放被禁用

好处是,当您知道自动播放已禁用时,您可以在某些浏览器中将视频静音并再次尝试 play() 方法,同时在 UI 中显示一些内容说视频正在静音播放。

var video = document.querySelector('video');
var promise = video.play();

if (promise !== undefined) {
  promise.then(_ => {
    // Autoplay started!
  }).catch(error => {
    // Autoplay not allowed!
    // Mute video and try to play again
    video.muted = true;
    video.play();

    // Show something in the UI that the video is muted
  });
}
<video src="https://www.w3schools.com/tags/movie.ogg" controls></video>

对我来说最好的解决方案是:

function _callback_onAutoplayBlocked() {
    // do something, for example "show big play button"
}

function isSafari() {
    var chr = window.navigator.userAgent.toLowerCase().indexOf("chrome") > -1;
    var sfri = window.navigator.userAgent.toLowerCase().indexOf("safari") > -1;
    return !chr && sfri;
}

function _checkAutoPlay(p) {
    var s = window['Promise'] ? window['Promise'].toString() : '';

    if (s.indexOf('function Promise()') !== -1 || s.indexOf('function ZoneAwarePromise()') !== -1) {
        p.catch(function(error) {
            console.error("_checkAutoPlay, error:", error)
            if(error.name == "NotAllowedError") { // For Chrome/Firefox
                console.error("_checkAutoPlay: error.name:", "NotAllowedError")
                _callback_onAutoplayBlocked();
            } else if (error.name == "AbortError" && isSafari()) {  // Only for Safari
                console.error("_checkAutoPlay: AbortError (Safari)")
                _callback_onAutoplayBlocked();
            } else {
                console.error("_checkAutoPlay: happened something else ", error);
                // throw error; // happened something else
            }
        }).then(function(){
            console.log("_checkAutoPlay: then");
            // Auto-play started
        });
    } else {
        console.error("_checkAutoplay: promise could not work in your browser ", p);
    }
}

var video1 = document.getElementById('video1');
_checkAutoPlay(video1.play());