0

マイク入力に対してリアルタイム処理 (ダウンサンプリングを含む) を行いたいのですが、重要なことに、入力サンプルを保存したいと考えています。

コードを本番環境にデプロイした後、受信した録音の一部にグリッチがあり、一部は他のものよりもはるかに多いことに気付きました。グリッチとは、録音にゼロ値のサンプルのランダムな期間が含まれていることを意味します。この問題は 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それまでの間、廃止されたものを使用して別の実装を行い、パフォーマンスが向上するかどうかを確認しようとしています。

4

2 に答える 2

0

既に報告されている Chrome のバグに遭遇したと思います。私が正しく思い出せば、可聴音を生成しない AudioContext があるときにトリガーされます。その場合、Chrome は最適化を適用します。つまり、実際の物理オーディオ デバイスを使用する代わりに、内部クロックからコンテキストを実行します。

上記のすべてが当てはまる場合、オーディオ出力に小さな信号を送信して、そのデバイスからコンテキストを実行し続けることで回避できます。

const constantSourceNode = new ConstantSourceNode(audioContext);

// 0.0001 is an arbitrary value
// maybe it needs to be bigger
// maybe a smaller value works as well
constantSourceNode.offset.value = 0.0001;

constantSourceNode.connect(audioContext.destination);
constantSourceNode.start();
于 2021-03-23T21:29:29.923 に答える