媒体和 Web Audio API 的自动播放指南

在页面加载时立即自动开始播放音频(或带有音频轨道的视频)可能会让用户感到意外。虽然媒体自动播放很有用,但应谨慎使用,仅在需要时使用。为了让用户控制这一点,浏览器通常提供各种形式的自动播放阻止。在本指南中,我们将介绍各种媒体和 Web Audio API 中的自动播放功能,包括如何使用自动播放以及如何与浏览器合作以优雅地处理自动播放阻止的简要概述。

当源媒体没有音频轨,或者音频轨被静音时,自动播放阻止不会应用于<video>元素。带有活动音频轨道的媒体被认为是可听见的,自动播放阻止适用于它们。不可听见的媒体不受自动播放阻止的影响。

自动播放和自动播放阻止

术语自动播放指的是任何导致媒体开始播放而不需用户明确请求播放开始的功能。这包括使用 HTML 属性自动播放媒体,以及使用 JavaScript 代码在处理用户输入之外的上下文中开始播放。

这意味着以下两种情况都被认为是自动播放行为,因此会受到浏览器自动播放阻止策略的影响

html
<audio src="/music.mp3" autoplay></audio>

js
audioElement.play();

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

从用户的角度来看,一个网页或应用程序在没有警告的情况下突然开始发出噪音,可能会让人感到刺耳、不方便或令人反感。因此,浏览器通常只允许在特定情况下成功自动播放。

自动播放可用性

一般来说,您可以假设只有在满足以下至少一个条件的情况下,才允许媒体自动播放

  • 音频被静音或其音量设置为 0
  • 用户与网站进行了交互(例如,点击、轻触、按下按键等)
  • 如果网站已被列入允许列表;这可能是自动发生的,如果浏览器确定用户经常与媒体互动,或者通过偏好设置或其他用户界面功能手动进行
  • 如果使用自动播放权限策略<iframe>及其文档授予自动播放支持。

否则,播放可能会被阻止。导致阻止的确切情况以及网站被列入允许列表的具体方式因浏览器而异,但以上是良好的参考指南。

有关详细信息,请参阅Google ChromeWebKit的自动播放策略。

注意:换句话说,如果在尚未进行任何用户交互的选项卡中以编程方式启动任何包含音频的媒体的播放,则通常会阻止其播放。浏览器还可能选择在其他情况下进行阻止。

媒体元素的自动播放

现在我们已经了解了自动播放是什么以及什么可以阻止自动播放,接下来我们将看看您的网站或应用程序如何在页面加载时自动播放媒体,如何检测自动播放失败以及在浏览器拒绝自动播放时应对的技巧。

autoplay 属性

自动播放内容最简单的方法是向您的<audio><video>元素添加autoplay属性,这会将元素上的autoplay属性设置为true。当autoplaytrue时,媒体将在满足以下条件后尽快自动开始播放

  • 页面被允许使用自动播放功能
  • 元素在页面加载期间已创建
  • 已经接收了足够的媒体以开始播放并持续播放到媒体结束,假设网络性能或带宽没有发生戏剧性的变化。

示例:autoplay 属性

使用autoplay属性的<audio>元素可能看起来像这样

html
<audio id="musicplayer" autoplay>
  <source src="/music/chapter1.mp3" />
</audio>

示例 2:检测是否允许自动播放

如果自动播放对您的应用程序很重要,您可能需要根据是否允许自动播放、是否不允许自动播放或是否只支持不可听见的内容来定制行为。例如,如果您的应用程序需要自动播放视频,并且您知道页面只允许自动播放不可听见的内容,您可以将其静音或提供没有音频轨道的视频。类似地,如果您知道完全不允许自动播放,您可能需要为视频提供默认图像(使用poster属性),或者选择推迟加载视频直到请求它。

Navigator.getAutoplayPolicy()方法可用于检查文档中某类媒体功能(即所有媒体元素或所有音频上下文)的自动播放策略,或检查特定媒体元素或音频上下文是否可以自动播放。

下面的示例展示了如何传递mediaelement字符串以获取文档中所有媒体元素的自动播放策略(传递audiocontext以获取音频上下文的策略)。代码假设video是使用<video>标签或HTMLVideoElementHTMLVideoElement媒体元素,并且它默认配置为带音频自动播放。如果自动播放只允许不可听见的内容,我们将静音音频;如果自动播放被禁止,我们将确保显示视频的占位符图像。

js
if (navigator.getAutoplayPolicy("mediaelement") === "allowed") {
  // The video element will autoplay with audio.
} else if (navigator.getAutoplayPolicy("mediaelement") === "allowed-muted") {
  // Mute audio on video
  video.muted = true;
} else if (navigator.getAutoplayPolicy("mediaelement") === "disallowed") {
  // Set a default placeholder image.
  video.poster = "http://example.com/poster_image_url";
}

测试特定元素或音频上下文的代码相同,只是您传入要测试的元素或上下文,而不是类型字符串。在这里,我们将传入我们要测试的video对象。

js
if (navigator.getAutoplayPolicy(video) === "allowed") {
  // The video element will autoplay with audio.
} else if (navigator.getAutoplayPolicy(video) === "allowed-muted") {
  // Mute audio on video
  video.muted = true;
} else if (navigator.getAutoplayPolicy(video) === "disallowed") {
  // Set a default placeholder image.
  video.poster = "http://example.com/poster_image_url";
}

某类媒体的自动播放策略可能会因用户与网站、页面或特定元素的交互而改变。类似地,在某些浏览器上,特定元素的策略可能会改变,即使类型的策略没有改变(例如,在用户触摸特定元素即可允许该元素自动播放的浏览器上)。

由于无法在自动播放策略改变时(无论是类型还是元素)收到通知,因此我们通常建议在页面加载时使用类型检查策略。

示例 3:检测自动播放失败作为回退

自动播放成功或失败不会触发任何特定事件(或其他通知),因此不支持Navigator.getAutoplayPolicy()的浏览器无法轻松确定是否支持自动播放,也无法在触发或未触发自动播放时做出反应。

一种方法是监听play事件的首次实例,该事件在媒体元素被暂停恢复播放时以及自动播放时触发。这意味着play事件第一次被触发时,您就知道您的媒体在页面打开后第一次被启动,

考虑以下用于媒体元素的 HTML 代码

html
<video src="myvideo.mp4" id="video" autoplay></video>

在这里,我们有一个<video>元素,它的autoplay属性被设置,并且设置了play事件处理程序;该事件由名为handleFirstPlay()的函数处理,该函数接收play事件作为输入。

handleFirstPlay()看起来像这样

js
const video = document.getElementById("video");
video.addEventListener("play", handleFirstPlay, false);

let hasPlayed = false;
function handleFirstPlay(event) {
  if (!hasPlayed) {
    hasPlayed = true;

    // Remove listener so this only gets called once.
    const vid = event.target;
    vid.removeEventListener("play", handleFirstPlay);

    // Start whatever you need to do after first playback has started
  }
}

Event对象的target中获取视频元素的引用后,我们使用它来移除事件监听器。这将阻止任何未来的play事件传递到处理程序。这可能会发生在视频被用户暂停和恢复,或者当文档处于后台选项卡时由浏览器自动暂停和恢复时。

此时,您的网站或应用可以开始执行任何依赖于视频启动的操作。

play() 方法

"自动播放" 一词也指脚本尝试在处理用户输入事件之外的上下文中触发包含音频的媒体播放的情况。这是通过调用媒体元素的 play() 方法来实现的。

注意: 强烈建议您尽可能使用autoplay属性,因为对自动播放首选项的支持在autoplay属性上比其他自动播放媒体的方式更为广泛。它还允许浏览器负责启动播放,使其能够优化播放的时机。

示例:播放视频

这个简单的示例播放文档中找到的第一个 <video> 元素。play() 不会让播放开始,除非文档有权自动播放媒体。

js
document.querySelector("video").play();

示例:处理 play() 失败

当您使用 play() 方法启动媒体时,检测自动播放媒体失败要容易得多。play() 返回一个 Promise,当媒体成功开始播放时,该 Promise 会被解决,当播放无法开始时(例如,如果自动播放被拒绝)会被拒绝。当自动播放失败时,您可能需要提供一种方式让用户手动告诉浏览器询问用户是否允许播放媒体。

您可以使用类似以下代码来完成工作

js
let startPlayPromise = videoElem.play();

if (startPlayPromise !== undefined) {
  startPlayPromise
    .then(() => {
      // Start whatever you need to do only after playback
      // has begun.
    })
    .catch((error) => {
      if (error.name === "NotAllowedError") {
        showPlayButton(videoElem);
      } else {
        // Handle a load or playback error
      }
    });
}

我们首先对play()结果进行操作,确保它不是undefined。我们检查这一点,因为在早期版本的 HTML 规范中,play()没有返回值。最近添加了返回 Promise 以允许您确定操作的成功或失败。检查undefined可以防止此代码在旧版本的 Web 浏览器上出现错误。

如果play()返回的 Promise 在没有错误的情况下被解决,则运行then()子句,并且可以在自动播放开始时开始执行任何需要执行的操作。

然后,我们向 Promise 添加一个 catch() 处理程序。这会查看错误的 name,以查看它是否为NotAllowedError。这表示播放由于权限问题而失败,例如自动播放被拒绝。如果是这种情况,我们应该提供一个用户界面,让用户手动启动播放;这里由函数showPlayButton()处理。

任何其他错误都将根据需要处理。

如果您想在第一次与页面交互后开始播放视频,可以使用 setInterval() 来实现这一点

js
let playAttempt = setInterval(() => {
  videoElem
    .play()
    .then(() => {
      clearInterval(playAttempt);
    })
    .catch((error) => {
      console.log("Unable to play the video, User has not interacted yet.");
    });
}, 3000);

使用 Web Audio API 自动播放

Web Audio API 中,网站或应用可以使用连接到 AudioContext 的源节点上的start()方法开始播放音频。在处理用户输入事件之外的上下文中执行此操作受自动播放规则的约束。

自动播放权限策略

除了上面描述的浏览器端对自动播放功能的管理和控制之外,Web 服务器还可以表达其允许自动播放功能的意愿。 HTTP Permissions-Policy 标头的 autoplay 指令用于控制哪些域(如果有)可以用来自动播放媒体。默认情况下,autoplay Permissions Policy 设置为self,表示允许自动播放,因为它们与文档托管在同一个域上。

您还可以指定一个空的允许列表(())来完全禁用自动播放,*来允许所有域的自动播放,或者一个或多个可以自动播放媒体的特定来源。这些来源之间用空格隔开。

注意: 指定的 Permissions Policy 适用于文档及其内部嵌套的每个 <iframe>,除非这些框架包含一个 allow,它为该框架及其内部嵌套的框架设置一个新的 Permissions Policy。

当在<iframe>上使用 allow 属性为该框架及其嵌套的框架指定 Permissions Policy 时,您还可以指定值'src' 来仅允许从与框架的 src 属性指定的域相同的域自动播放媒体。

示例:仅允许从文档域自动播放

要使用 Permissions-Policy 标头仅允许从文档的 来源 自动播放媒体

http
Permissions-Policy: autoplay=(self)

要对 <iframe> 做同样的事情

html
<iframe src="mediaplayer.html" allow="autoplay"> </iframe>

示例:允许自动播放和全屏模式

如果无论域如何都允许全屏访问,则将 Fullscreen API 权限添加到前面的示例会导致以下类似的Permissions-Policy 标头;也可以根据需要添加域限制。

http
Permissions-Policy: autoplay=(self), fullscreen=(self)

使用<iframe>元素的allow属性授予的相同权限如下所示

html
<iframe src="mediaplayer.html" allow="autoplay; fullscreen"> </iframe>

示例:允许来自特定来源的自动播放

Permissions-Policy 标头允许从文档(或<iframe>)自己的域和https://example.media播放媒体,如下所示

http
Permissions-Policy: autoplay=(self "https://example.media")

可以编写一个 <iframe> 来指定应该将此自动播放策略应用于自身,以及任何子框架的编写方式

html
<iframe
  width="300"
  height="200"
  src="mediaplayer.html"
  allow="autoplay 'src' https://example.media">
</iframe>

示例:禁用自动播放

autoplay Permissions Policy 设置为()/none将完全禁用文档或<iframe>及其所有嵌套框架的自动播放。HTTP 标头为

http
Permissions-Policy: autoplay=()

使用<iframe>allow属性

html
<iframe src="mediaplayer.html" allow="autoplay 'none'"> </iframe>

最佳实践

这里提供了一些技巧和推荐的最佳实践,帮助您充分利用自动播放功能。

使用媒体控件处理自动播放失败

自动播放的一个常见用例是自动开始播放与文章、广告或页面主要功能的预览相关的视频片段。要自动播放这样的视频,您有两个选择:不要有音频轨道,或者有音频轨道,但配置 <video> 元素默认情况下静音,如下所示

html
<video
  src="/videos/awesomevid.webm"
  controls
  autoplay
  playsinline
  muted></video>

此视频元素被配置为包含用户控件(通常是播放/暂停、在视频时间线上拖动、音量控制和静音);此外,由于包含了 muted 属性,以及 Safari 中自动播放所需的 playsinline 属性,因此视频将自动播放,但音频静音。但是,用户可以选择通过单击控件中的取消静音按钮重新启用音频。

浏览器配置选项

浏览器可能具有控制自动播放工作方式或处理自动播放阻止方式的首选项。这里列出了任何可能对您作为 Web 开发人员特别重要或意义重大的首选项。这些包括可能有助于测试或调试的任何首选项,以及您需要做好准备处理的任何可能以您需要的方式设置的首选项。

Firefox

media.allowed-to-play.enabled

一个布尔值首选项,指定是否将非标准HTMLMediaElement.allowedToPlay属性公开给网络。目前默认情况下为false(除了在 nightly 版本中,默认情况下为true)。如果为false,则allowedToPlay属性将缺失于HTMLMediaElement接口中,因此不会出现在 <audio><video> 元素中。

media.autoplay.allow-extension-background-pages

这个布尔值首选项,如果为true,允许浏览器扩展的后台脚本自动播放音频媒体。将此值设置为false将禁用此功能。默认值为true

media.autoplay.allow-muted

一个布尔值首选项,如果为true(默认值),允许当前静音的音频媒体自动播放。如果将其更改为false,即使静音,也不能播放带有音频轨道的媒体。

media.autoplay.block-webaudio

一个布尔值首选项,指示是否将自动播放阻止应用于 Web Audio API。如果为false,则 Web 音频始终允许自动播放。如果为true,则音频上下文只能在页面被 Sticky 激活 后播放。默认设置为true

media.autoplay.default

一个整型首选项,指定默认情况下是否允许(0)、阻止(1)或提示使用(2)每个域的自动播放支持配置。默认值为0

media.autoplay.enabled.user-gestures-needed(仅限 nightly 版本)

一个布尔值首选项,控制是否允许检测用户手势来覆盖media.autoplay.default的设置。如果media.autoplay.default设置为0(默认情况下允许自动播放),则此首选项为true,如果页面已被用户手势激活,则无论如何都允许自动播放带有音频轨道的媒体,并且不可听的媒体不受任何限制。

media.block-autoplay-until-in-foreground

一个布尔值首选项,指示是否在后台选项卡上启动时阻止媒体播放。默认值true表示,即使在其他情况下可用,自动播放也不会在选项卡被带到前台之前进行。这可以防止选项卡开始播放声音,而用户无法在所有选项卡和窗口中找到该选项卡的令人分心的情况。

另请参阅