/** * AudioWorklet Processor for low-latency audio capture * Runs in a separate audio thread for minimal latency */ class AudioProcessor extends AudioWorkletProcessor { constructor() { super(); this.bufferSize = 512; // Send audio every ~32ms at 16kHz this.buffer = []; } process(inputs, outputs, parameters) { const input = inputs[0]; if (input.length > 0) { const channelData = input[0]; // Accumulate samples for (let i = 0; i < channelData.length; i++) { this.buffer.push(channelData[i]); } // Send when we have enough while (this.buffer.length >= this.bufferSize) { const chunk = this.buffer.splice(0, this.bufferSize); this.port.postMessage({ audio: new Float32Array(chunk) }); } } return true; // Keep processor alive } } registerProcessor('audio-processor', AudioProcessor);