Dado que una llamada a AudioWorkletProcessor.process es síncrona según https://developer.mozilla.org/en-US/docs/Web/API/AudioWorkletProcessor/process , ¿qué sucede cuando una ejecución tarda demasiado tiempo, más de 1 segundo, ¿por ejemplo? ¿Se omitirán algunas muestras de audio en una próxima llamada? ¿O las muestras estarían en cola en algún lugar? No pude encontrar una documentación sobre esto.
Un AudioContext en tiempo real suele estar ajustado a un determinado dispositivo de salida de audio físico. Por lo tanto, el currentTime de un AudioContext está controlado por el reloj de hardware de ese dispositivo de salida de audio.
Si el AudioContext de alguna manera no entrega las muestras a tiempo, el resultado será el silencio. Por lo general, eso se puede escuchar como un clic si de repente hay un poco de silencio donde no debería estar. Las muestras que tardaron demasiado en renderizarse se utilizarán para el próximo cuanto de renderizado si es que están listas para entonces.
Sin embargo, hay una diferencia en la forma en que los navegadores avanzan el tiempo currentTime en caso de que algunas muestras no se puedan entregar a tiempo. Firefox parece no contar las muestras perdidas, mientras que Chrome avanza en el tiempo contando todas las muestras que el hardware de audio escupe, incluidas aquellas que no se pudieron procesar a tiempo.
Para probar esto, creé un AudioWorkletProcessor que se puede pausar o bloquear desde el hilo principal.
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); Este BlockableProcessor espera recibir un SharedArrayBuffer que utiliza para verificar si debe bloquear la función process() o no. Y también lo usa para comunicar el tiempo currentTime al hilo principal.
Se puede usar así:
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); Se puede bloquear configurando el primer valor de SharedArrayBuffer en 0.
Atomics.store(int32Array, 0, 0);Y así mismo se puede volver a desbloquear poniéndolo a 1 de nuevo.
Atomics.store(int32Array, 0, 1); También es posible leer el AudioWorkletProcessor currentTime el subproceso principal.
Atomics.load(int32Array, 1);Con esta configuración, pude ver que Chrome (v95) y Firefox (v93) detienen la progresión del tiempo en el subproceso principal y en el worklet en caso de que el procesador esté bloqueado.
Cuando se desbloquea, Firefox continúa donde se detuvo y Chrome continúa donde debería estar si todo hubiera ido como se esperaba.