Safari webkitAudioContext.createBuffer API 引发 NotSupportedError 异常

Safari webkitAudioContext.createBuffer API raises NotSupportedError exception

我正在使用 JavaScript 网络音频 API、AudioContext 来播放音频。它适用于其他主要浏览器,但 MacOS 上的 Safari 在调用 webkitAudioContext.createBuffer API 时会引发 NotSupportedError 异常。我从那里发现了这个问题,, also indicated that there was such issue with Safari at the end of page. So, I debugged the "Working example https://o.lgm.cl/example.html (16-bit LSB)”,并在 Safari 中遇到了同样的问题。

由于我还是 Whosebug 的新手,所以我无法对那个问题添加评论,询问他们是如何解决这个问题的。那么,有人可以帮忙吗?非常感谢!

编辑:

运行 Safari JavaScript 控制台中的这两行代码将重现问题:

var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); 
var myAudioBuffer = audioCtx.createBuffer(1, 48000, 16000); 

> NotSupportedError: The operation is not supported.

您遇到的错误几乎是意料之中的。 Web Audio 规范规定,如果 sampleRate 超出支持范围,则必须抛出 NotSupportedError。但它也表示支持的最低采样率应至少为 8000 Hz。

https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer

Safari 的网络音频实现仅支持 22050 Hz 及更高频率的 AudioBuffers。因此,我建议创建一个 32000 Hz 的 AudioBuffer,因为 32 是 16 的倍数,这使得下一步更容易推理。

填充缓冲区时,您需要通过自己插入缺失值来补偿较大的采样率。我认为基本的线性插值应该工作得相当好。但您也可以使用 OfflineAudioContext 对 AudioBuffer 重新采样。

在理想情况下(例如 Firefox、Chrome 或 Opera),您可以像这样对 AudioBuffer 重新采样:

// Let's assume you have an AudioBuffer called audioBuffer of 1 second at 16 kHz.
const offlineAudioContext = new OfflineAudioContext(
    { length: 32000, sampleRate: 32000 }
);
const audioBufferSourceNode = new AudioBufferSourceNode(
    offlineAudioContext,
    { buffer: audioBuffer }
);

audioBufferSourceNode.start(0);
audioBufferSourceNode.connect(offlineAudioContext.destination);

const resampledAudioBuffer = await offlineAudioContext.startRendering();

变量 resampledAudioBuffer 现在将引用 32 kHz 的重采样 AudioBuffer。

但是 Safari 中 Web 音频 API 的实现已经过时且存在错误。不仅不支持创建小于22050Hz的AudioBuffer,也不支持创建小于44100Hz的OfflineAudioContext

但是,对于您的用例,您所需要的只是将数据重新采样两倍。从 16 kHz 到 32 kHz 或从 44100 Hz 到 88200 Hz 重新采样在理论上是相同的。

因此,您可以创建一个 44100 Hz 的 AudioBuffer 并用实际为 16 kHz 的数据填充它。然后将该缓冲区重新采样到 88200 Hz。生成的数据将成为 32 kHz 的原始数据。

这一切都非常复杂,但不幸的是,我不知道在 Safari 中有任何其他方法可以做到这一点。

为了避免使用 Safari 仍然需要的过时语法,我建议使用 polyfill。我是 standardized-audio-context 的作者,这就是我推荐它的原因,但它不是唯一的。