音频视频自动播放解决方案

8,087 阅读5分钟

音频视频自动播放解决方案

一. 使用背景

公司项目需要用到音频自动播放的功能,首先想到的就是autoplay属性。

想让内容自动播放的最简单方法是将autoplay属性添加到元素,并将autoplay属性设置为 true ,当 autoplay 的属性为 true 时,媒体元素将在发生以下情况后尽快自动开始播放:

  • 页面允许使用自动播放功能
  • 媒体元素已在页面加载期间创建
  • 假设网络性能或带宽没有显着变化,且已收到足够的媒体流并已开始播放,继续播放直至媒体结束而不会中断。

然而在实际操作的过程中,发现自动播放失败,并且出现如下的报错

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

这个问题当时困扰了我许久,一路解决的过程也是十分坎坷,所以我决定将解决方案记录下来,下面是我在解决问题的过程中找到的一些资料以及解决问题的方案。

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

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

以下网络功能和API可能会受到自动播放阻止的影响:

三. Chrome浏览器Audio标签的自动播放策略

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

  • 始终允许静音自动播放

  • 顶级框架可以将自动播放权限委派给其iframe,以允许自动播放

  • 在以下情况下,允许自动播放声音

    • 用户已与和网页已有交互行为,包括点击、触摸、按下某个键等等。(利用弹窗去引导用户点击页面按钮)
    • 在桌面版chrome上,已经超过了用户的“媒体参与度索引”阈值,这意味着该用户以前曾播放过有声视频。(“媒体参与度索引”在后面有介绍)
    • 用户已将网站添加到移动设备上的主屏幕,或者在桌面上安装了PWA

由于本人是在PC端开发的,所以只能根据上面的条件总结出一下几种解决方案:

  1. 将audio的muted属性设置为true,能够实现静音播放,但是这并不满足我的需求
  2. 使用iframe<iframe src = "xxxxx.mp3" allow = "autoplay"/>
  3. 使用audio标签,将autoplay设置为true, 当播放失败时与页面做交互(弹窗引导用户点击),来实现自动播放

四. 解决方案

考略到项目还需要在音频上实现其他的功能,使用第三种方案比较方便。

既然选择第三种方案,那么该如何检查自动播放失败了呢?事实上,自动播放失败时不会触发任何事件。也没有抛出异常或可以设置回调,甚至在媒体元素上都没有标记来告诉你自动播放是否起作用。那么我们可以换个方向,不去仅仅依赖autoplay,而是使用play方法进行播放,play方法执行时会返回一个promise,可以根据promise来判断当前的播放是成功了还是失败了,并且在失败后做出相应的解决方法

const audioElem = document.querySelector("audio");
let startPlayPromise = audioElem.play();
​
if (startPlayPromise !== undefined) {
  startPlayPromise.catch(error => {
    if (error.name === "NotAllowedError") {
      // 弹窗引导用户与页面做交互,只需要一个简单的按钮即可
      // 记得在按钮上绑定一个带有play()方法的回调函数,以element-plus的组件为例
      ElMessageBox.alert('当前正在自动播放音频', '提示', {
        confirmButtonText: '确认',
        callback: () => {
          audioElem.play();
        },
      })
    } else {
      // Handle a load or playback error
    }
  }).then(() => {
    // Start whatever you need to do only after playback
    // has begun.
  });
}
​

五. 更进一步

如果产品看到这个弹窗之后,十分的不爽,硬是要让我们在尽可能不让用户察觉到需要交互的情况下实现自动播放,那么该怎么办呢?

既然与页面做了交互之后就能正常播放了,那么我事先将交互事件绑定到document元素上,是不是就可以在用户不知情并且很自然的情况下,完成交互了呢?

// 点击
document.addEventListener('click', () => {
    document.querySelector("audio").play();
});
​
// 监听鼠标移动的事件
document.addEventListener('mousemove', () => {
    document.querySelector("audio").play();
});

六. MEI 媒体参与度索引

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

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

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

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

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