iblog icon indicating copy to clipboard operation
iblog copied to clipboard

chrome 66自动播放策略改变

Open gnipbao opened this issue 6 years ago • 18 comments

ba44d518-eb46-4ce8-8a65-6abae68a8840

背景

Web浏览器正在朝着更严格的自动播放策略发展,以便改善用户体验,最大限度地降低安装广告拦截器的积极性并减少昂贵和/或受限网络上的数据消耗。这些更改旨在为用户提供更大的播放控制权,并使开发商获得合法用例。

新的特性

Chrome的自动播放政策很简单:

  • 静音自动播放总是允许的。
  • 在下列情况下允许使用声音自动播放:
    • 用户已经与域进行了交互(点击,tap等)。
    • 在桌面上,用户的媒体参与指数阈值(MEI)已被越过,这意味着用户以前播放带有声音的视频。
    • 在移动设备上,用户已将该网站添加到主屏幕。
    • 顶部框架可以将自动播放权限授予其iframe以允许自动播放声音。

媒体参与指数(Media Engagement Index)(MEI)

MEI衡量个人在网站上消费媒体的倾向。Chrome 目前的方法是访问每个来源的重要媒体播放事件的比率:

  • 媒体消耗(音频/视频)必须大于7秒。
  • 音频必须存在并取消静音。
  • 视频选项卡处于活动状态。
  • 视频大小(以像素为单位)必须大于200x140。

因此,Chrome会计算媒体参与度分数,该分数在定期播放媒体的网站上最高。足够高时,媒体播放只允许在桌面上自动播放。MEI是谷歌自动播放策略的一部分。它是一个算法,参考了媒体内容的持续时间、浏览器标签页是否活动、活动标签页视频的大小这一系列元素。不过也正因此,开发者难以在所有的网页上都测试这一算法的效果。

用户的MEI位于chrome://media-engagement/内部页面 media-engagement

开发者开关

作为开发者,您可能需要在本地更改Chrome浏览器自动播放政策行为,以根据用户的参与情况测试您的网站。

  • 您可以决定通过将Chrome标志“自动播放策略”设置为“无需用户手势”来完全禁用自动播放策略 chrome://flags/#autoplay-policy。这样您就可以测试您的网站,就好像用户与您的网站保持紧密联系一样,并且始终允许播放自动播放。
  • 您也可以决定禁止使用MEI以及默认情况下全新MEI获得播放自动播放的网站是否允许新用户使用,从而决定禁止播放自动播放。这可以用两个来完成 内部开关用chrome.exe --disable-features=PreloadMediaEngagementData,AutoplayIgnoreWebAudio, MediaEngagementBypassAutoplayPolicies

Iframe 委托授权

一个功能政策使开发人员可以选择性地启用和禁用的各种浏览器的功能和API。一旦来源获得了自动播放权限,它就可以将该权限委托给具有自动播放功能的跨源iframe 。默认情况下,同源iframe可以使用自动播放。

<! - 允许自动播放。- > 
<iframe src = "https://cross-origin.com/myvideo.html" allow = "autoplay" /> 
<! - 允许自动播放和全屏播放。- > 
<iframe src = "https://cross-origin.com/myvideo.html" allow = "autoplay; fullscreen" />

当禁用自动播放的功能策略时,play()不带用户手势的调用将拒绝带有NotAllowedErrorDOMException 的promise。自动播放属性也将被忽略。

示例场景:

示例1:每次用户在他们的笔记本电脑上访问www.iqiyi.com时,他们都会观看电视节目或电影。由于其媒体参与度较高,因此可以自动播放。

示例2:www.iqiyi.com同时具有文字和视频内容。大多数用户偶尔会去该网站获取文字内容并观看视频。用户的媒体参与度较低,因此如果用户直接从社交媒体页面或搜索导航,则不允许自动播放。

示例3:news.iqiyi.com同时具有文字和视频内容。大多数人通过主页进入网站,然后点击新闻报道。由于用户与域名互动,新闻文章页面上的自动播放将被允许。但是,应该注意确保用户不会对自动播放内容感到意外。

示例4: 在爱奇艺泡泡页面将iframe与电影预告片一起嵌入其评论中。用户与域进行交互以访问特定的网站,因此允许自动播放。但是,泡泡需要将该特权显式委托给iframe以便内容自动播放。

Chrome企业政策

Chrome企业策略可以改变这种新的自动播放行为,以用于例如信息亭或无人值守系统。查看 配置策略和设置帮助页面,了解如何设置这些新的与自动播放相关的企业策略:

  • 该“AutoplayAllowed”策略控制自动播放是否允许。
  • 该“AutoplayWhitelist”政策,允许您指定的URL模式的白名单,其中自动播放将始终启用。

开发人员最佳实践

视频元素

  • 永远不要假设视频会播放,并且在视频不是真正播放时不要显示暂停按钮。
  • 关注播放函数返回的Promise。
var promise = document.querySelector('video').play();
if (promise !== undefined) {
  promise.then(_ => {
    // Autoplay started!
  }).catch(error => {
    // Autoplay was prevented.
    // Show a "Play" button so that user can start playback.
  });
}
  • 使用静音自动播放
<video id="video" muted autoplay>
<button id="unmuteButton"></button>

<script>
  unmuteButton.addEventListener('click', function() {
    video.muted = false;
  });
</script>

各大视频网站自动开播对比矩阵图(非播放页)

站点 处理方式
微博 静音开播
优酷 开播暂停
腾讯 部分静音开播部分暂停
爱奇艺 静音开播 部分暂停
B站 暂未处理

以上情况截止本文发表前部分页面统计不代表全部。

音频元素

原生播放音频除了使用audio标签之外,还有另外一个API叫AudioContext,AudioContext接口表示由音频模块连接而成的音频处理图,每个模块对应一个AudioNode。AudioContext可以控制它所包含的节点的创建,以及音频处理、解码操作的执行。做任何事情之前都要先创建AudioContext对象,因为一切都发生在这个环境之中。

AudioContext播放声音
  1. 先请求音频文件,放到ArrayBuffer里面,然后用AudioContext的API进行decode解码,解码完了再让它去play。
function request (url) {
    return new Promise (resolve => {
        let xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        // set response Type arraybuffer
        xhr.responseType = 'arraybuffer';
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status === 200) {
                resolve(xhr.response);
            }
        };
        xhr.send();
    });
}
  1. 实例化AudioContext
// Safari是使用webkit前缀
let context = new (window.AudioContext || window.webkitAudioContext)();
  1. 解码播放
function play (context, decodeBuffer) {
    let source = context.createBufferSource();
    source.buffer = decodeBuffer;
    source.connect(context.destination);
    // 从0s开始播放
    source.start(0);
}
// 请求音频数据
let audioMedia = await request(url);
// 进行decode和play
context.decodeAudioData(audioMedia, decode => play(context, decode));

关于音频播放的可以参阅这篇文章讲的比较详细,这里不再讨论。

AudioContext创建时机
  • 页面加载时创建 那么resume()在用户与页面进行交互之后(例如,用户单击按钮),您必须在某个时间进行调用。
// Existing code unchanged.
window.onload = function() {
  var context = new AudioContext();
  // Setup all nodes
  ...
}

// One-liner to resume playback when user interacted with the page.
document.querySelector('button').addEventListener('click', function() {
  context.resume().then(() => {
    console.log('Playback resumed successfully');
  });
});
  • 在用户与该页面进行交互时创建。
document.querySelector('button').addEventListener('click', function() {
  var context = new AudioContext();
  // Setup all nodes
  ...
});

参考资料

  • https://developers.google.com/web/updates/2017/09/autoplay-policy-changes

  • https://developers.google.com/web/updates/2016/07/autoplay

  • https://github.com/WICG/feature-policy/blob/gh-pages/features.md

  • https://wicg.github.io/feature-policy/

  • https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API/Using_Web_Audio_API

  • https://segmentfault.com/a/1190000003115198

gnipbao avatar May 22 '18 10:05 gnipbao

是不是网站媒体参与指数够高就可以自动播放?这个指标有地方可以查吗

fancyboynet avatar Aug 07 '18 06:08 fancyboynet

@fancyboynet 可以的 chrome浏览器自带chrome://media-engagement/

gnipbao avatar Aug 07 '18 10:08 gnipbao

@gnipbao 谢谢,我看爱奇艺和优酷都会自动播放,不知道为什么

fancyboynet avatar Aug 07 '18 10:08 fancyboynet

@fancyboynet 就是chrome的一种策略要不静音开播 ,要不提高MEI指数目前也只有这两种方法。

gnipbao avatar Aug 07 '18 10:08 gnipbao

@gnipbao 谢谢,不过MEI不知道是什么规则,我的iqiyi.com的scroe值才0.10,也可以带音播

fancyboynet avatar Aug 08 '18 01:08 fancyboynet

@fancyboynet 下面4条满足即可带音开播


  • 媒体消耗(音频/视频)必须大于7秒。(这个指的历史消费>7s)
  • 音频必须存在并取消静音。
  • 视频选项卡处于活动状态。
  • 视频大小必须大于200px*140px。

gnipbao avatar Aug 08 '18 02:08 gnipbao

视频选项卡处于活动状态。 视频选项卡是指什么。

发现youku iqiyi 就算还是0.1都还是能够自动播放

ourfeel avatar Nov 14 '18 06:11 ourfeel

@ourfeel 先回答下你的问题 首先视频选项卡是指的tab页中的video,视频处于活跃就是你切到了该tab或者点击过该tab。优酷和爱奇艺的score值不能决定是不是自动开播。但是这个值越高自然是越能开播的。是否能开播决定与chrome内部一个阀值。对于播放器我们的处理其实比较简单可参考下面代码实现。


/**     
 * 1. 静音自动播放总是允许的。
 * 2. 普通自动开播决定与媒体阀值不可控。
 * 3. 根据上述两条指定策略模拟自动开播 这是非标准的。
 */
// autoplay happens after loadstart for the browser,
this.manualAutoplay_(this.autoplay());
manualAutoplay_(type) {
    // 静音播放 返回promise
    const muted = () => {
        const previouslyMuted = this.muted();

        this.muted(true);

        const playPromise = this.play();

        if (!playPromise || !playPromise.then || !playPromise.catch) {
            return;
        }

        return playPromise.catch((e) => {
            // restore old value of muted on failure
            this.muted(previouslyMuted);
        });
    };

    let promise;

    // any 表示普通开播 muted表示静音开播 不传表示自动开播
    if (type === 'any') {
        promise = this.play();

        if (promise && promise.then && promise.catch) {
            
            promise.catch(() => {
                // 有异常尝试静音开播
                return muted();
            });
        }
    } else if (type === 'muted') {
        promise = muted();
    } else {
        promise = this.play();
    }

    if (!promise || !promise.then || !promise.catch) {
        return;
    }

    return promise.then(() => {
        // 自动开播成功事件
        this.trigger({ type: 'autoplay-success', autoplay: type });
    }).catch((e) => {
        // 自动开播失败事件
        this.trigger({ type: 'autoplay-failure', autoplay: type });
    });
}

代码详细细节可以参考video.js

gnipbao avatar Nov 18 '18 05:11 gnipbao

主要想不通的地方就是为什么斗鱼在chrome里面就可以正常播放,因为MEI分数很低也可以。

lynxerzhang avatar Oct 31 '19 06:10 lynxerzhang

@lynxerzhang 这个没必要去纠结 统一处理就行。 先正常开播 如果失败那就尝试muted再开播 一般都能正常开播 某些移动端不支持自动开播直接出播放按钮就好了。MEI这个算法官方也没有开源出来谁也不知道内部做了那些操作。

gnipbao avatar Nov 02 '19 08:11 gnipbao

@lynxerzhang 这个没必要去纠结 统一处理就行。 先正常开播 如果失败那就尝试muted再开播 一般都能正常开播 某些移动端不支持自动开播直接出播放按钮就好了。MEI这个算法官方也没有开源出来谁也不知道内部做了那些操作。

最近也遇到这个问题,但是发现的是目前优酷在MEI没有达到标准的情况下仍然可以有声自动播放。既然有厂商做到了就值得研究,因为他们提供的在我看来是更优的用户体验

AceMood avatar Mar 28 '20 03:03 AceMood

@AceMood 是的,自动开播会优化一些体验。但是目前代码成层这样的逻辑没问题 chrome内部对于流量比较大的视频网站有一些特殊处理。作为开发者目前这样其实就是ok的了,有些问题可能要咨询chrome内部开发者了。

gnipbao avatar Mar 28 '20 07:03 gnipbao

@AceMood 是的,自动开播会优化一些体验。但是目前代码成层这样的逻辑没问题 chrome内部对于流量比较大的视频网站有一些特殊处理。作为开发者目前这样其实就是ok的了,有些问题可能要咨询chrome内部开发者了。

优酷正在询问,不清楚是否有企业白名单之类的。目前的现象是v.youku.com域名可以有声自动播放。其他的可能你还有了解么?

AceMood avatar Apr 07 '20 03:04 AceMood

同样好奇,为什么斗鱼可以自动播放

dongliang1993 avatar Jun 08 '20 05:06 dongliang1993

值得一起讨论下,感觉是不是他们有什么规避手段绕开了Chrome的限制,或者就是有企业白名单这种,直接可以自动播放,目前我的处理还是按照Chrome的开发者文档来处理的,就是有报错的话,就弹出提示,让用户点一下再继续播放,或者就静音。

lynxerzhang avatar Jun 09 '20 03:06 lynxerzhang

@lynxerzhang 哈哈 作为爱奇艺主站播放器的一名开发。 我可以告诉你 我们并没有做什么奇技淫巧去绕开chrome的限制 并且对于某些二级域名流量不是很大的 其实有时候也不能自动开播的,个人感觉是chrome针对热门视频网站会有流量监控 内部有whitelist

gnipbao avatar Jun 15 '20 04:06 gnipbao

@gnipbao 哈哈, 我现在发现自动播放在Safari里面似乎有个问题,就是在Chrome中可以正常使用的自动播放处理代码在Safari里面似乎仍有问题,不知道是不是Safari因为mac系统升级又有了限制。之前是好的,在系统升级到Mojave后,自动播放报错,出现弹框,然后点击继续播放,但是还是会继续报错!再次出现弹框....,不知道你有没有遇到过。

lynxerzhang avatar Jul 13 '20 02:07 lynxerzhang

@gnipbao 哈哈, 我现在发现自动播放在Safari里面似乎有个问题,就是在Chrome中可以正常使用的自动播放处理代码在Safari里面似乎仍有问题,不知道是不是Safari因为mac系统升级又有了限制。之前是好的,在系统升级到Mojave后,自动播放报错,出现弹框,然后点击继续播放,但是还是会继续报错!再次出现弹框....,不知道你有没有遇到过。

我没有碰到你这个弹窗的问题 首先你得明确窗口是哪里发出的 是Safari 还是业务代码出的。 其次 要看一下错误来源是不是播放器media报错。

gnipbao avatar Jul 13 '20 09:07 gnipbao