如何在 javascript 中对从麦克风实时录制的音频进行下采样?

How to downsample audio recorded from mic realtime in javascript?

我正在使用以下 javascript 来录制音频并将其发送到 websocket 服务器:

const recordAudio = () =>
    new Promise(async resolve => {

        const constraints = {
            audio: {
                sampleSize: 16,
                channelCount: 1,
                sampleRate: 8000
            },
            video: false
        };

        var mediaRecorder;
        const stream = await navigator.mediaDevices.getUserMedia(constraints);

        var options = {
            audioBitsPerSecond: 128000,
            mimeType: 'audio/webm;codecs=pcm'
        };
        mediaRecorder = new MediaRecorder(stream, options);
        var track = stream.getAudioTracks()[0];
        var constraints2 = track.getConstraints();
        var settings = track.getSettings();


        const audioChunks = [];

        mediaRecorder.addEventListener("dataavailable", event => {
            audioChunks.push(event.data);
            webSocket.send(event.data);
        });

        const start = () => mediaRecorder.start(30);

        const stop = () =>
            new Promise(resolve => {
                mediaRecorder.addEventListener("stop", () => {
                    const audioBlob = new Blob(audioChunks);
                    const audioUrl = URL.createObjectURL(audioBlob);


        const audio = new Audio(audioUrl);
                const play = () => audio.play();
                resolve({
                    audioBlob,
                    audioUrl,
                    play
                });
            });

            mediaRecorder.stop();
        });

    resolve({
        start,
        stop
    });
});

这是针对实时 STT 的,websocket 服务器拒绝发送任何响应。我通过调试检查 sampleRate 没有更改为 8Khz.Upon 研究,我发现这是 chrome 和 firefox 上的一个已知错误。我找到了一些其他资源,例如 Whosebug1 and IBM_STT,但我不知道如何使其适应我的代码。 上面有用的资源是指缓冲区,但我的代码中只有 mediaStream(stream) 和 event.data(blob) 。 我是 javascript 和音频 Api 的新手,所以如果我做错了什么请原谅我。

如果这有帮助,我有一个等效的代码 python 可以将数据从麦克风发送到有效的 websocket 服务器。使用的库 = Pyaudio。代码:

 p = pyaudio.PyAudio()
 stream = p.open(format="pyaudio.paInt16",
                        channels=1,
                        rate= 8000,
                        input=True,
                        frames_per_buffer=10)

 print("* recording, please speak")

 packet_size = int((30/1000)*8000)  # normally 240 packets or 480 bytes

 frames = []

        #while True:
 for i in range(0, 1000):
     packet = stream.read(packet_size)
     ws.send(packet, binary=True)

要进行实时下采样,请按照以下步骤操作:

  1. 首先使用这个获取流实例:

    const stream = await navigator.mediaDevices.getUserMedia(constraints);
    
  2. 从此流创建媒体流源。

    var input = audioContext.createMediaStreamSource(stream);
    
  3. 创建脚本处理器以便您可以使用缓冲区。我将创建一个脚本处理器,它一次从流中连续获取 4096 个样本,具有 1 个输入通道和 1 个输出通道。

    var scriptNode = audioContext.createScriptProcessor(4096, 1, 1);
    
  4. 将您的输入连接到 scriptNode。您可以根据需要将脚本节点连接到目的地。

        input.connect(scriptNode);
        scriptNode.connect(audioContext.destination);
    
  5. 现在在 scriptProcessor 中有一个函数 onaudioprocess,你可以用 4096 个样本做任何你想做的事情。 var downsample 将包含(1/采样率)个数据包。 floatTo16BitPCM 会将其转换为您需要的格式,因为原始数据为 32 位浮点格式。

       var inputBuffer = audioProcessingEvent.inputBuffer;
        // The output buffer contains the samples that will be modified and played
        var outputBuffer = audioProcessingEvent.outputBuffer;
    
        // Loop through the output channels (in this case there is only one)
        for (var channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
            var inputData = inputBuffer.getChannelData(channel);
            var outputData = outputBuffer.getChannelData(channel);
    
    
    
            var downsampled = downsample(inputData);
            var sixteenBitBuffer = floatTo16BitPCM(downsampled);
          }
    
  6. 您的 sixteenBitBuffer 将包含您需要的数据。

    下采样和 floatTo16BitPCM 的函数在这个 link 的 Watson API 中有解释:IBM Watson Speech to Text Api

您不需要 MediaRecorder 实例。 Watson API 是开源的,您可以寻找一种更好的简化方法来了解他们如何为他们的用例实施它。您应该能够从他们的代码中抢救重要功能。