简化浏览器中的音频

在过去的几年里,随着最新的 HTML5 标准不断得到实施,浏览器的功能得到了巨大的提升。我们现在可以在画布上渲染高级图形,使用 WebSockets 实时通信,访问本地文件系统,创建离线应用等等。然而,音频领域却落后了。

HTML5 音频 元素非常适合一些特定用途(例如播放音乐),但当您需要低延迟、精确播放时,它就不那么有效了。

在过去的一年里,为浏览器开发了一种新的音频标准,它使开发人员可以直接访问音频数据。 Web Audio API 允许进行高精度和高性能的音频播放,以及 HTML5 音频元素无法实现的许多高级功能。但是,支持仍然有限,并且 API 比 HTML5 音频复杂得多。

介绍 howler.js

高性能音频最明显的用例是游戏,但大多数开发人员不得不使用 HTML5 音频并辅以 Flash 回退来获得浏览器兼容性。我的公司,GoldFire Studios,专门为开放网络开发游戏,我们着手寻找一个能够提供游戏所需音频支持的音频库,而无需依赖过时的技术。不幸的是,我们没有找到任何合适的库,因此我们自己编写了一个库并将其开源:howler.js

Howler.js 默认使用 Web Audio API,并使用 HTML5 音频作为回退。该库极大地简化了 API,并自动处理所有棘手的问题。这是一个创建音频精灵(类似于 CSS 精灵,但使用音频文件)并播放其中一个声音的简单示例

var sound = new Howl({
  urls: ['sounds.mp3', 'sounds.ogg'],
  sprite: {
    blast: [0, 2000],
    laser: [3000, 700],
    winner: [5000, 9000]
  }
});

// shoot the laser!
sound.play('laser');

使用特性检测

在最基本的层面上,这是通过特性检测来实现的。以下代码片段检测 Web Audio API 是否可用,如果可用则创建音频上下文。目前对 Web Audio API 的支持包括 Chrome 10+、Safari 6+ 和 iOS 6+。它也正在 Firefox、Opera 和大多数其他移动浏览器中进行开发。

var ctx = null,
  usingWebAudio = true;
if (typeof AudioContext !== 'undefined') {
  ctx = new AudioContext();
} else if (typeof webkitAudioContext !== 'undefined') {
  ctx = new webkitAudioContext();
} else {
  usingWebAudio = false;
}

不同编解码器的音频支持在不同浏览器中也有所不同,因此我们使用 canPlayType 方法检测从您提供的源数组中哪个格式最适合使用

var audioTest = new Audio();
var codecs = {
  mp3: !!audioTest.canPlayType('audio/mpeg;').replace(/^no$/,''),
  ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,''),
  wav: !!audioTest.canPlayType('audio/wav; codecs="1"').replace(/^no$/,''),
  m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/,''),
  webm: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,'')
};

简化操作

howler.js 的这两个关键组件允许库自动选择最佳的播放方法和要加载和播放的源文件。然后,库会抽象出这两个不同的 API,并将以下内容(一个简化的 Web Audio API 示例,不包含所有额外的回退支持和额外功能)

// create gain node
var gainNode, bufferSource;
gainNode = ctx.createGain();
gainNode.gain.value = volume;
loadBuffer('sound.wav');

var loadBuffer = function(url) {
  // load the buffer from the URL
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer';
  xhr.onload = function() {
    // decode the buffer into an audio source
    ctx.decodeAudioData(xhr.response, function(buffer) {
      if (buffer) {
        bufferSource = ctx.createBufferSource();
        bufferSource.buffer = buffer;
        bufferSource.connect(gainNode);
        bufferSource.start(0);
      }
    });
  };
  xhr.send();
};

(注意:某些旧的 已弃用的名称createGainNodenoteOn,如果您在网络上的其他示例中看到它们)

转换为以下内容

var sound = new Howl({
  urls: ['sound.wav'],
  autoplay: true
});

需要注意的是,Web Audio API 和 HTML5 音频都不是解决所有问题的完美方案。与任何事物一样,选择合适的工具来完成相应的工作非常重要。例如,您不希望使用 Web Audio API 加载大型背景音乐文件,因为您必须等待整个数据源加载完毕才能播放。HTML5 音频能够在下载开始后非常快地播放,这就是 howler.js 也实现了一个覆盖功能,允许您在应用中混合和匹配这两个 API 的原因。

浏览器中的音频已准备就绪

我经常听到有人说浏览器中的音频已损坏,并且在相当长的一段时间内将无法用于除基本音频流之外的任何用途。这与事实完全相反。当今的现代浏览器已经具备了这些工具。高质量的音频支持现已推出,Web Audio API 和 HTML5 结合起来,提供了真正的无插件、跨浏览器的音频支持。浏览器音频不再是二等公民,所以让我们停止将其视为二等公民,并继续为开放网络开发应用。

关于 James Simpson

James 是 GoldFire Studios 的首席执行官兼创始人,该公司使用 HTML5 为网络开发实时多人游戏。在过去的十多年里,自 13 岁开始开发以来,他的游戏和游戏相关产品已覆盖全球数百万用户。他经常在 Twitter 上发布关于 Javascript、HTML5、游戏开发和创业公司的推文。

更多 James Simpson 的文章……

关于 Robert Nyman [荣誉编辑]

Mozilla Hacks 的技术布道师和编辑。发表演讲和博客文章,主题包括 HTML5、JavaScript 和开放网络。Robert 是 HTML5 和开放网络的坚定支持者,自 1999 年以来一直在从事 Web 前端开发工作——在瑞典和纽约市。他还定期在 http://robertnyman.com 上发表博客文章,并且喜欢旅行和结识新朋友。

更多 Robert Nyman [荣誉编辑] 的文章……


10 条评论

  1. Alex

    如何处理 audioTest.canPlayType('audio/mpeg;') !== 'no'?

    2013年2月21日 06:44

  2. Paul Morris

    这看起来棒极了!

    只是澄清一下……如果我使用 howler.js 创建一个音频精灵,它是否可以在尚不支持 Web Audio API 的浏览器中工作?换句话说,精灵功能是否需要 Web Audio API 或者它是否也可以与 HTML5 音频一起工作?

    2013年2月21日 09:17

    1. James Simpson

      谢谢!无论使用 Web Audio API 还是 HTML5 音频,它的工作方式都相同。howlerjs.com 上有一个精灵功能的演示。

      2013年2月21日 09:25

      1. Paul Morris

        不错!我从 howlerjs.com 上的演示中看到,您在音频精灵中的声音之间有一秒钟的静音。我想您发现这是一个好的做法?

        感谢 howler.js!看来我与跨浏览器音频作斗争的日子即将结束。o/

        2013年2月21日 13:49

        1. James Simpson

          使用 Web Audio 不需要完整的一秒钟,但这有助于防止声音在 HTML5 音频的较低精度下重叠。此外,以这种方式定义精灵也更容易。

          2013年2月21日 13:50

  3. Tom Pouce

    文章中写道:“目前对 Web Audio API 的支持包括 Chrome 10+、Safari 6+ 和 iOS 6+。它也正在 Firefox、Opera 和大多数其他移动浏览器中进行开发。”
    ……然后“浏览器音频不再是二等公民”。

    只要 Web Audio API 没有包含在 Firefox 的标准版本中,在我看来,浏览器音频仍然是二等公民。

    2013年2月21日 10:23

    1. Robert Nyman [编辑]

      我们昨天在这篇博客文章中写了关于 Web Audio API,以及我们正在取得的进展。是的,这还处于早期阶段,但它确实正在发生。

      2013年2月21日 13:20

      1. James Cready

        在声称支持 Web Audio API 之前,请务必完全支持 MediaElementAudioSource就像 Safari 所做的那样)。

        2013年2月21日 14:37

        1. Robert Nyman [编辑]

          说得对!请随时将任何信息或意见贡献给 WebAudio API 的实现错误

          2013年2月21日 14:45

  4. bekam

    var ctx = null,
    usingWebAudio = true;
    if (typeof AudioContext !== 'undefined') {
    ctx = new AudioContext();
    } else if (typeof webkitAudioContext !== 'undefined') {
    ctx = new webkitAudioContext();
    } else {
    usingWebAudio = false;
    }

    它很有用..我有一些想法可以解决我的问题

    2013年2月21日 14:32

本文评论已关闭。