/** * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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;