Web Audio API 最佳实践

在编写创意代码时,没有严格的对错之分。只要你考虑了安全性、性能和可访问性,就可以适应你自己的风格。在本文中,我们将分享一些最佳实践——关于使用 Web Audio API 的指南、技巧和窍门。

加载声音/文件

使用 Web Audio API 加载声音有四种主要方式,哪种最适合你可能会让人有些困惑。

在处理文件时,你可以选择从 HTMLMediaElement(即 <audio><video> 元素)获取文件,或者获取文件并将其解码为缓冲区。这两种方式都有效,但前者更常用于处理完整长度的音轨,而后者更常用于处理较短、更像样本的声音。

媒体元素开箱即用地支持流式传输。当浏览器认为它可以在播放结束前加载文件的其余部分时,音频就会开始播放。你可以在 使用 Web Audio API 教程 中找到如何使用此功能的示例。

但是,使用缓冲区节点会给你更多的控制权。你必须请求文件并等待其加载(我们 高级文章的这一部分 展示了很好的方法),然后你就可以直接访问数据,这意味着更高的精度和更精确的控制。

如果你想处理来自用户摄像头或麦克风的音频,可以通过 Media Capture and Streams APIMediaStreamAudioSourceNode 接口进行访问。这对于 WebRTC 以及你可能想要录制或分析音频的场景很有用。

最后一种方式是生成自己的声音,这可以通过 OscillatorNode 或创建缓冲区并用自己的数据填充缓冲区来完成。有关使用振荡器和缓冲区创建声音的信息,请参阅 此处创建自己的乐器的教程

跨浏览器和旧版支持

Web Audio API 规范在不断发展,就像网络上的大多数事物一样,它在跨浏览器工作方面存在一些问题。在这里,我们将研究绕过跨浏览器问题的选项。

有一个名为 standardized-audio-context 的 npm 包,它可以在不同浏览器之间一致地创建 API 功能,填补发现的空白。它处于不断开发中,并致力于跟上当前规范。

还可以选择使用库,根据你的用例有几种选择。对于一个不错的全能型库,howler.js 是一个不错的选择。它支持跨浏览器,并提供了一个有用的功能子集。虽然它没有利用 Web Audio API 提供的全部滤镜和其他效果,但你可以做到大部分你想要做的事情。

如果你正在寻找声音创作或更基于乐器的选项,tone.js 是一个很棒的库。它提供了高级的调度功能、合成器和效果,以及建立在 Web Audio API 之上的直观的音乐抽象。

来自 BBC 的研发部门R-audio 是一个 React 组件库,旨在提供“更直观、声明式地访问 Web Audio”。如果你习惯编写 JSX,它可能值得一看。

自动播放策略

浏览器已开始实施自动播放策略,总的来说可以概括为

"从用户手势内部创建或恢复上下文"。

但这对实际意味着什么?用户手势被解释为用户发起的事件,通常是 click 事件。浏览器供应商决定不允许 Web Audio 上下文自动播放音频;相反,它们应该由用户启动。这是因为自动播放音频可能非常烦人且令人反感。但是我们该如何处理呢?

当你创建一个音频上下文(无论是离线还是在线)时,它会以一个 state 创建,该状态可以是 suspendedrunningclosed

在使用 AudioContext 时,如果你在 click 事件内部创建音频上下文,状态应自动设置为 running。这是在 click 事件内部创建上下文的示例

js
const button = document.querySelector("button");
button.addEventListener("click", () => {
  const audioCtx = new AudioContext();
  // Do something with the audio context
});

但是,如果你在用户手势之外创建上下文,其状态将设置为 suspended,并且在用户交互后需要启动它。我们可以在此处使用相同的点击事件示例,测试上下文的状态,并在其被挂起时使用 resume() 方法启动它。

js
const audioCtx = new AudioContext();
const button = document.querySelector("button");

button.addEventListener("click", () => {
  // check if context is in suspended state (autoplay policy)
  if (audioCtx.state === "suspended") {
    audioCtx.resume();
  }
});

你可能正在使用 OfflineAudioContext,在这种情况下,你可以使用 startRendering() 方法恢复挂起的音频上下文。

用户控制

如果你的网站或应用程序包含声音,你应该允许用户控制它,否则它将再次变得令人讨厌。这可以通过播放/停止和音量/静音控件来实现。使用 Web Audio API 教程将介绍如何做到这一点。

你可能会发现一些有用的控件是:用于播放/暂停的 <button> 元素,用于选择播放速度等选项的 <select> 元素,用于切换静音的 <input type="checkbox"> 元素,以及用于音量控制和输入其他数值的 <input type="range"> 元素。

所有关于表单可访问性的常见注意事项都适用。在使用 <button> 元素时,应确保它们具有清晰的 label。这将帮助屏幕阅读器和其他辅助技术理解按钮的用途。如果你有开关音频的按钮,在按钮上使用 ARIA role="switch" 属性是向辅助技术指示按钮确切用途的好方法,从而使应用程序更具可访问性。

设置 AudioParam 值

有两种方法可以操纵 AudioNode 值,它们本身就是 AudioParam 接口类型的对象。第一种方法是通过属性直接设置值。例如,如果我们想更改 GainNodegain 值,我们会这样做:

js
gainNode.gain.value = 0.5;

这将把我们的音量设置为一半。但是,如果你使用 AudioParam 的任何已定义方法来设置这些值,它们将优先于上面的属性设置。例如,如果你希望 gain 值在 2 秒后增加到 1,你可以这样做:

js
gainNode.gain.setValueAtTime(1, audioCtx.currentTime + 2);

它将覆盖之前的示例(应该如此),即使它出现在你代码的后面。

考虑到这一点,如果你的网站或应用程序需要定时和调度,最好坚持使用 AudioParam 方法来设置值。如果你确定不需要,使用 value 属性设置是可以的。