前提

需要页面自动播放一段报警声音,将audio标签的autoplay属性设置为true,发现自动播放失败,并出现如下报错:

Uncaught (in promise) DOMException: play() failed because the user didn’t interact with the document first.

为什么要禁止自动播放音频与视频

网页加载完成后立即播放音频(或带有音频轨道的视频)可能会意外地打扰到用户。尽管自动播放媒体文件是一个很实用的功能,但是我们也应该谨慎地使用它,保证只有在它被需要的时候才使用。为了让用户拥有控制权,通常浏览器会提供各种方式禁用自动播放音频功能。在这篇文章中,我们将介绍各种媒体和Web Audio APIs的自动播放功能,包括关于如何使用自动播放功能、如何优雅的处理阻止自动播放功能的一些简短的介绍。

Autoplay 功能

据新政策,媒体内容将在满足以下至少一个的条件下自动播放:

  • 音频被静音或其音量设置为 0
  • 用户和网页已有交互行为(包括点击、触摸、按下某个键等等)
  • 网站已被列入白名单;如果浏览器确定用户经常与媒体互动,这可能会自动发生,也可能通过首选项或其他用户界面功能手动发生
  • 自动播放策略应用到”>或者其文档上

否则,播放可能会被阻止。导致播放被阻塞的确切情况以及将网站列入白名单的具体方法因浏览器而异,但最好是遵循以上的原则。

详情,请参阅Google Chrome和WebKit的自动播放政策。

解决方案

考虑到音频上可能还会有其他操作,选择第二种方案。如何知道自动播放失败了呢?其实自动播放失败时不会触发任何事件,也没有抛出异常或回调。那么便不能依赖autoplay。而是使用play函数模拟自动播放,play函数执行时会返回一个promise,可以根据promise来判断当前的播放是成功了还是失败了,并且在失败后做出相应的提示。

// 页面加载事件中执行 this.playWarn()// 提示音弹窗,需要用户手动点一次才可以让浏览器播放音频applyPlayConfirm() {const audio = document.querySelector("audio");this.$confirm("请开启本次报警声音提醒", "提示", {type: "info",showClose: false,showCancelButton: false,closeOnPressEscape: false,closeOnClickModal: false,confirmButtonText: "确定",callback: () => {// 用户点击过后 即可播放audio.play();},});},// 申请播放音频,只需用户点击页面任意位置playWarn() {const audio = document.querySelector("audio");let startPlayPromise = audio.play();if (startPlayPromise !== undefined) {startPlayPromise.catch((error) => {if (error.name == "NotAllowedError") {this.applyPlayConfirm();} else {// Handle a load or playback error}}).then(() => {// Start whatever you need to do only after playback});}},

阅读:

MEI 媒体参与度索引

在以chorme为内核的浏览中,设置了MEI(Media Engagement Index)列表,该列表长度为1000,用来来衡量用户是否是该网站的“忠实用户”。当MEI排名足够高时,即可自动播放。

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

  • 媒体(音频/视频)的消耗必须大于7秒。
  • 音频必须存在且不能静音。
  • 带有视频的标签处于活动状态。(个人感觉是不能设置display: none, visibility: hidden等)
  • 视频大小(以px为单位)必须大于200×140。

由此,Chrome计算出的媒体参与度得分在定期播放媒体的网站上足够高时,允许在桌面上自动播放媒体播放。

可以在chrome://media-engagement 内部页面上找到用户的MEI 。