Как уменьшить звук, записанный с микрофона в реальном времени в JavaScript?

Я использую следующий JavaScript для записи аудио и отправки его на сервер веб-сокета:

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 не меняется на 8 кГц. При исследовании я обнаружил, что это известная ошибка как в chrome, так и в firefox. Я нашел некоторые другие ресурсы, такие как stackru1 и IBM_STT, но я понятия не имею, как адаптировать его к моему коду. Вышеупомянутые полезные ресурсы относятся к буферу, но все, что у меня есть, это mediaStream (поток) и event.data (blob) в моем коде. Я новичок в javascript и Audio 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 ответ

Решение

Для выполнения понижающей дискретизации в реальном времени выполните следующие действия:

  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. Теперь в script Processor есть функция 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 описаны в этой ссылке API Watson: IBM Watson Speech to Text Api

Вам не понадобится экземпляр MediaRecorder. Watson API с открытым исходным кодом, и вы можете найти более рациональный подход к тому, как они реализовали его для своего варианта использования. Вы должны быть в состоянии спасти важные функции из их кода.

Другие вопросы по тегам