Как я могу предотвратить прерывание/перебои/глюки при использовании AudioWorklet для потоковой передачи захваченного аудио?

Мы работали над клиентом аудиочата на основе JavaScript, который запускается в браузере и отправляет образцы аудио на сервер через WebSocket. Ранее мы пытались использовать ScriptProcessorNode API веб-аудио для получения образцов значений. Это хорошо работало на наших настольных компьютерах и ноутбуках, но мы столкнулись с плохим качеством звука при передаче с портативной платформы, которую мы должны поддерживать. Мы связываем это с задокументированными проблемами производительности процессора сценариев (https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API). На КПК с размером буфера процессора сценариев 2048 звук постоянно прерывался. На следующем интервале максимального размера (4096) звук был гладким (без разрывов), но была слишком большая задержка (около двух секунд).

Наши результаты от ScriptProcessorNode побудили поэкспериментировать с Audio Worklet. К сожалению, с нашей ворлетной реализацией качество звука хуже: и обрывы, и задержки, даже на наших ноутбуках. Мне интересно, есть ли способ настроить нашу реализацию ворклета, чтобы повысить производительность, или того, что мы испытываем, следует ожидать от (является «нормальным») текущего состояния аудио-ворклетов (проблемы Chromium 796330, 813825 и 836306 кажутся актуальными).

Вот немного подробнее о том, что делает код:

  1. Создайте MediaStreamStreamSourceNode с помощью MediaStream, полученного от getUserMedia.
  2. Соедините исходный узел с реализацией нашего рабочего узла (расширяет AudioWorkletNode).
  3. Наша реализация процессора worklet (расширяет AudioWorkletProcessor) буферизует блоки, поступающие в качестве «входного» аргумента для его метода обработки.
  4. Когда буфер заполнен, используйте MessagePort, чтобы отправить содержимое буфера на узел worklet.
  5. Узел Worklet передает содержимое буфера через соединение WebSocket.

Метод процесса ниже. Переменная "samples" представляет собой Float32Array, который инициализируется размером буфера и используется повторно. Я немного поэкспериментировал с размером буфера, но, похоже, это не повлияло. Этот подход основан на рекомендациях раздела 4.1 документа AudioWorklet: будущее веб-аудио, чтобы свести к минимуму выделение памяти.

if (micKeyed == true) {

    if (inputs[0][0].length == framesPerBlock) {
        samples.set(inputs[0][0], currentBlockIndex * framesPerBlock);
        currentBlockIndex++;

        if (currentBlockIndex == lastBlockIndex) {
            // console.log('About to send buffer.');
            this.port.postMessage(samples);
            currentBlockIndex = 0;
        }
    } else {
        console.error("Got a block of unexpected length!!!");
    }
}
return true;

В настоящее время проводится тестирование на ПК с Chrome 72.0.3626.109 на CentOS 7. Наши портативные устройства — Panasonic FZ-N1 с Chrome 72.0.3626.105 на Android 6.0.1.

Спасибо за чтение и любые предложения, которые вы можете предоставить.


person StephenL    schedule 20.02.2019    source источник
comment
Спасибо за ответ @guest271314. Я не пробовал MediaSource, но выглядит интересно. Однако в нашем случае я считаю, что источник задержки и разрывов находится в конвейере захвата/передачи внутри клиента, а не в конвейере воспроизведения/приема (тот, к которому кажется применимым MediaSource). Мы слышали достаточно хорошее качество воспроизведения, когда звук захватывался и передавался клиентом, работающим на относительно мощном оборудовании. Когда мы оставляем оборудование постоянным для клиента воспроизведения, но переключаемся на менее мощное оборудование для клиента захвата, качество воспроизведения становится неприемлемым.   -  person StephenL    schedule 20.02.2019
comment
Как вы предлагаете обращаться к разрозненным аппаратным средствам в клиентском коде?   -  person guest271314    schedule 21.02.2019
comment
@guest271314: В нашем тестировании мы слышим сдвиг высоты тона, когда передающий клиент работает с портативным компьютером, а принимающий клиент — с ПК, или наоборот, якобы из-за разной частоты дискретизации (48000 выборок в секунду на ПК и 16000 выборок в секунду на портативном устройстве). . Кажется, из-за ошибки Chrome их нельзя изменить. Итак, если мы сможем заставить наше текущее решение работать во всех других отношениях, нам придется выполнить некоторую повторную выборку, чтобы учесть разные скорости. Я не знаю ни о каких других проблемах, возникающих из-за несовместимого оборудования. Вы имели в виду что-то другое? Спасибо.   -  person StephenL    schedule 21.02.2019
comment
Одним из возможных вариантов может быть создание пользовательской версии Chromium, в которой исходный код (якобы FOSS) настроен на выборку со скоростью N выборок в секунду на целевых портативных устройствах. Протестируйте конфигурацию на целевых устройствах внутри компании перед развертыванием пользовательского браузера в целом или для потенциальных пользователей конкретного приложения.   -  person guest271314    schedule 21.02.2019
comment
Например, github.com/Eloston/ungoogled-chromium   -  person guest271314    schedule 21.02.2019