API веб-аудио для прямой трансляции?
Нам нужно потоковое воспроизведение live аудио (от медицинского устройства) к веб-браузерам с задержкой от трех до трех дней (предположим, 200 мс или менее задержка сети). Сегодня мы используем плагин для браузера (NPAPI) для декодирования, фильтрации (высокий, низкий, диапазон) и воспроизведения аудиопотока (доставляемого через веб-сокеты).
Мы хотим заменить плагин.
Я смотрел различные демоверсии Web Audio API, и большинство наших требуемых функций (воспроизведение, управление усилением, фильтрация), похоже, доступный в Web Audio API. Однако мне непонятно, может ли Web Audio API использоваться для потоковых источников, поскольку большая часть веб-аудио API использует короткие звуки и/или аудиоклипы.
Можно ли использовать API веб-аудио для воспроизведения потокового аудио в реальном времени?
Обновление (11-фев-2015):
После немного большего количества исследований и локального прототипирования я не уверен, что потоковая передача аудио в реальном времени с помощью Web Audio API возможна. Поскольку Web Audio API decodeAudioDatastrong > не предназначен для обработки случайных фрагментов аудиоданных (в нашем случае поставляется через WebSockets). Кажется, нужен весь "файл", чтобы правильно его обработать.
См. stackoverflow:
Теперь с помощью createMediaElementSource можно подключить элемент <audio>
к API веб-аудио, но мой опыт в том, что элемент <audio>
вызывает огромное количество сквозных задержки (15-30 с), и, похоже, нет никаких средств для снижения задержки до менее 3-5 секунд.
Я думаю, что единственным решением является использование WebRTC с API Web Aduio. Я надеялся избежать WebRTC, так как это потребует значительных изменений в нашей серверной реализации.
Обновление (12 февраля 2015 г.) Часть I:
Я не полностью уничтожил тег <audio>
(нужно закончить мой прототип). Как только я это исключил, я подозреваю, что createScriptProcessor (устаревший, но все еще поддерживаемый) будет хорошим выбором для нашей среды, поскольку я мог бы "потопить" (через WebSockets) наши данные ADPCM в браузер, а затем (в JavaScript) преобразовать его в PCM. Подобно тому, что в библиотеке Скотта (см. Ниже), используется с помощью createScriptProcessor. Этот метод не требует, чтобы данные были в размерах "кусков" и критических сроках в качестве подхода decodeAudioData.
Обновление (12 февраля 2015 г.) Часть II:
После большего тестирования я исключил интерфейс <audio>
в интерфейс веб-аудио API, потому что, в зависимости от типа источника, сжатия и браузера, конечная задержка может составлять 3-30 секунд. Это оставляет метод createScriptProcessor (см. Сообщение Скотта ниже) или WebRTC. После обсуждения с нашими лицами, принимающими решения, было решено, что мы примем подход WebRTC. Я предполагаю, что это сработает. Но это потребует изменений в нашем коде на стороне сервера.
Я собираюсь отметить первый ответ, так что "вопрос" закрыт.
Спасибо, что слушал. Не стесняйтесь добавлять комментарии по мере необходимости.
Ответы
Ответ 1
Да, для потоковой передачи можно использовать API веб-аудио (вместе с AJAX или Websockets).
В принципе, вы вытаскиваете (или отправляете в случае с Websockets) некоторые фрагменты длины n
. Затем вы декодируете их с помощью API веб-аудио и ставите их в очередь для воспроизведения один за другим.
Поскольку API веб-аудио имеет высокоточную синхронизацию, вы не услышите никаких "швов" между воспроизведением каждого буфера, если вы правильно планируете.
Ответ 2
Я написал поточную систему веб-аудио API, в которой я использовал веб-работников, чтобы все управление веб-сокетами связывалось с node.js, так что поток браузера просто воспроизводит аудио... отлично работает на ноутбуках, поскольку мобильные телефоны отстают от их внедрения веб-сокетов внутри веб-работников, вам нужно не меньше, чем леденец, чтобы он работал как закодированный... Я отправил полный исходный код здесь
Ответ 3
Подробнее о комментариях о том, как играть кучу отдельных буферов, хранящихся в массиве, каждый раз переставляя последнюю из них:
Если вы создаете буфер через createBufferSource()
, то он имеет событие onended
, к которому вы можете подключить обратный вызов, который будет срабатывать, когда буфер достигнет своего конца. Вы можете сделать что-то подобное, чтобы поочередно воспроизводить различные куски в массиве:
function play() {
//end of stream has been reached
if (audiobuffer.length === 0) { return; }
let source = context.createBufferSource();
//get the latest buffer that should play next
source.buffer = audiobuffer.shift();
source.connect(context.destination);
//add this function as a callback to play next buffer
//when current buffer has reached its end
source.onended = play;
source.start();
}
Надеюсь, что это поможет. Я все еще экспериментирую с тем, как все это гладко и гладко, но это хорошее начало и отсутствие во многих онлайн-сообщениях.