マイク入力に対してリアルタイム処理 (ダウンサンプリングを含む) を行いたいのですが、重要なことに、入力サンプルを保存したいと考えています。
コードを本番環境にデプロイした後、受信した録音の一部にグリッチがあり、一部は他のものよりもはるかに多いことに気付きました。グリッチとは、録音にゼロ値のサンプルのランダムな期間が含まれていることを意味します。この問題は Android デバイスで発生します。
幸いなことに、問題を一貫して再現できるデバイス (OnePlus 6) を手に入れました。AudioWorklet を最小限に取り除いた後でも、まだ不具合が見られました。これは、テスト用の AudioWorklet クラスが通信部分を取り除いた状態です。
class TestWorklet extends AudioWorkletProcessor {
constructor(options) {
super(options);
// Allocate the buffer once in the beginning
this.recordingBuffer = new Float32Array(sampleRate * 20); // store max 20 sec audio
this.recordingBufferOffset = 0;
}
process(inputs, outputs) {
const input = inputs[0];
const output = outputs[0];
// Copy samples to the recording buffer
if (this.recordingBufferOffset < this.recordingBuffer.length - input[0].length) {
this.recordingBuffer.set(input[0], this.recordingBufferOffset);
this.recordingBufferOffset += input[0].length;
}
// Copy input to the output
for (let channel = 0; channel < input.length; ++channel) {
output[channel].set(input[channel]);
}
return true;
}
}
registerProcessor('TestWorklet', TestWorklet);
完全を期すために、これが AudioWorklet を接続する方法です
import TestWorklet from './testWorklet';
start = async () => {
let stream;
let audioCtx;
if (navigator.mediaDevices) {
try {
stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: false
});
} catch (e) { }
}
if (!stream) {
return false;
}
try {
audioCtx = new AudioContext();
} catch (e) {
return false;
}
await audioCtx.audioWorklet.addModule(TestWorklet);
const audioSource = audioCtx.createMediaStreamSource(stream);
const worklet = new AudioWorkletNode(audioCtx, "TestWorklet", {
channelCount: 1,
channelCountMode: "explicit",
channelInterpretation: "discrete"
});
audioSource.connect(worklet);
await audioCtx.resume();
return true;
}
興味深いのは、それほど強力でない Android デバイスでは、これらの不具合がゼロにならないことです。少なくとも私は気づいていません。
誰もこの問題の経験がありますか? おそらく、最適ではないパラメータでワークレットを初期化していますか?
ScriptProcessorNode
それまでの間、廃止されたものを使用して別の実装を行い、パフォーマンスが向上するかどうかを確認しようとしています。