1

AudioWorkletProcessor.process由于根据https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkletProcessor/process的调用是同步的,如果执行时间过长(例如超过 1 秒)会发生什么情况?在下一次通话中会跳过一些音频样本吗?或者样品会在某个地方排队吗?我找不到这方面的文档。

4

1 回答 1

3

实时AudioContext性通常与某个物理音频输出设备紧密相关。因此currentTime,anAudioContext的 由该音频输出设备的硬件时钟驱动。

如果AudioContext不知何故未能及时交付样品,结果将是沉默。通常,如果在不应该出现的地方突然出现一点沉默,则可以听到咔哒声。渲染时间过长的样本将被用于下一个渲染量子,如果它们恰好在那时准备好的话。

currentTime但是,在某些示例无法及时交付的情况下,浏览器的推进方式会有所不同。Firefox 似乎不会计算任何错过的样本,而 Chrome 会按时间计算音频硬件吐出的所有样本,包括那些无法及时呈现的样本。

为了测试这一点,我创建了一个AudioWorkletProcessor可以在主线程中暂停或阻塞的。

class BlockableProcessor extends AudioWorkletProcessor {
    constructor () {
        super();

        this.int32Array = null;
        this.port.onmessage = ({ data }) => this.int32Array = data;
    }

    process() {
        if (this.int32Array !== null) {
            while (Atomics.load(this.int32Array, 0) === 0) {
                Atomics.store(this.int32Array, 1, currentTime);
            }

            Atomics.store(this.int32Array, 1, currentTime);
        }

        return true;
    }
}

registerProcessor('blockable-processor', BlockableProcessor);

BlockableProcessor期望接收SharedArrayBuffer它用来检查它是否应该阻止该process()功能。它还使用它currentTime与主线程进行通信。

它可以这样使用:

const audioWorkletNode = new AudioWorkletNode(
    audioContext,
    'blockable-processor'
);
const sharedArrayBuffer = new SharedArrayBuffer(8);
const int32Array = new Int32Array(sharedArrayBuffer);

Atomics.store(int32Array, 0, 1);
Atomics.store(int32Array, 1, 0);

audioWorkletNode.port.postMessage(int32Array);
audioWorkletNode.connect(audioContext.destination);

可以通过将 的第一个值设置SharedArrayBuffer为 0 来阻止它。

Atomics.store(int32Array, 0, 0);

同样,它可以通过再次设置为 1 再次解除阻塞。

Atomics.store(int32Array, 0, 1);

也可以从主线程中读取currentTime写入的内容。AudioWorkletProcessor

Atomics.load(int32Array, 1);

使用此设置,我可以看到 Chrome (v95) 和 Firefox (v93) 都停止了主线程和工作集中的时间进程,以防处理器被阻塞。

当它被解锁时,Firefox 会继续它停止的地方,而 Chrome 会继续它应该在的地方,如果一切都按预期进行的话。

于 2021-10-27T00:06:18.890 回答