File size: 2,897 Bytes
ec50620
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
 * 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;