|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const SafariAudioRecordingWorklet = ` |
|
|
class AudioProcessingWorklet extends AudioWorkletProcessor { |
|
|
// Safari seems to work better with smaller buffer sizes |
|
|
// and more frequent updates |
|
|
buffer = new Int16Array(1024); |
|
|
bufferWriteIndex = 0; |
|
|
lastProcessTime = 0; |
|
|
sampleRate = 0; |
|
|
|
|
|
constructor(options) { |
|
|
super(); |
|
|
console.log('Safari AudioProcessingWorklet constructed with options:', options); |
|
|
this.sampleRate = options.processorOptions?.sampleRate || sampleRate; |
|
|
console.log('Using sample rate:', this.sampleRate); |
|
|
} |
|
|
|
|
|
process(inputs) { |
|
|
// Log processing details periodically |
|
|
const now = currentTime; |
|
|
if (now - this.lastProcessTime > 1) { |
|
|
console.log('Safari AudioProcessingWorklet processing:', { |
|
|
inputChannels: inputs[0]?.length, |
|
|
inputSamples: inputs[0]?.[0]?.length, |
|
|
bufferWriteIndex: this.bufferWriteIndex, |
|
|
time: now |
|
|
}); |
|
|
this.lastProcessTime = now; |
|
|
} |
|
|
|
|
|
if (!inputs[0]?.length) { |
|
|
console.warn('No input channels available'); |
|
|
return true; |
|
|
} |
|
|
|
|
|
const channel0 = inputs[0][0]; |
|
|
if (!channel0?.length) { |
|
|
console.warn('Empty input channel'); |
|
|
return true; |
|
|
} |
|
|
|
|
|
this.processChunk(channel0); |
|
|
return true; |
|
|
} |
|
|
|
|
|
sendAndClearBuffer() { |
|
|
if (this.bufferWriteIndex > 0) { |
|
|
this.port.postMessage({ |
|
|
event: "chunk", |
|
|
data: { |
|
|
int16arrayBuffer: this.buffer.slice(0, this.bufferWriteIndex).buffer, |
|
|
}, |
|
|
}); |
|
|
this.bufferWriteIndex = 0; |
|
|
} |
|
|
} |
|
|
|
|
|
processChunk(float32Array) { |
|
|
// Safari can sometimes send empty arrays or undefined |
|
|
if (!float32Array?.length) { |
|
|
return; |
|
|
} |
|
|
|
|
|
const l = float32Array.length; |
|
|
for (let i = 0; i < l; i++) { |
|
|
// Convert float32 -1 to 1 to int16 -32768 to 32767 |
|
|
// Add some additional gain for Safari which tends to be quieter |
|
|
const int16Value = Math.max(-32768, Math.min(32767, float32Array[i] * 32768 * 1.5)); |
|
|
this.buffer[this.bufferWriteIndex++] = int16Value; |
|
|
|
|
|
if (this.bufferWriteIndex >= this.buffer.length) { |
|
|
this.sendAndClearBuffer(); |
|
|
} |
|
|
} |
|
|
|
|
|
// Make sure to send any remaining data |
|
|
if (this.bufferWriteIndex > 0) { |
|
|
this.sendAndClearBuffer(); |
|
|
} |
|
|
} |
|
|
} |
|
|
`; |
|
|
|
|
|
export default SafariAudioRecordingWorklet; |