Потоковая передача аудио через WebSockets на проигрыватель Web Audio - PullRequest
3 голосов
/ 21 марта 2020

У меня есть несколько работающая система, которая

  1. Воспроизводит звук на сервере в 1-секундном файле WAV
  2. Считывает файл WAV и отправляет его через веб-сокет
  3. Websocket отправляет двоичные данные в AudioContext.decodeAudioData
  4. Декодированное аудио буферизуется до 4 пакетов (4 секунды)
  5. Буфер обрабатывается и отправляется в AudioBufferSourceNode.start (время), где время = (clip_count * duration)

Так что, если у меня есть 4 аудиоклипа, вызовы будут выглядеть как

AudioBufferSourceNode.start(0);
AudioBufferSourceNode.start(1);
AudioBufferSourceNode.start(2);
AudioBufferSourceNode.start(3);

Я думал, что это будет идеально запланировать 4 секунды звука, но мне кажется, чтобы столкнуться с проблемами с часами, возможно, потому что я ожидаю, что аудио часы будут идеальными. Я уже использовал узел усиления для удаления щелчков между каждым звуковым клипом (1 секунда), но у меня появляются проблемы с синхронизацией сразу или по прошествии длительного времени. По сути, в худшем случае мой звук звучит так:

 ----------------------  -----------     -----------     -----------
| 1 second | 1 second |  |   950ms |     |  900ms  |    |   850ms  |
 ----------------------  -----------     -----------     -----------
                       gap          gap              gap

На этой диаграмме "1 секунда" и "#ms" - это количество воспроизводимого звука. Это всегда должно быть 1 секунда. По мере прохождения звука, похоже, также появляются пробелы. Я предполагаю, что даже когда я говорю звуковому контексту, что файл воспроизводится точно с 0, это нормально, но другие запланированные аудиоклипы могут быть или не быть вовремя.

Это правильно, или в моей системе что-то не так? Есть ли 100% -ная достоверность того, что я мог запланировать воспроизведение аудиоклипа в нужное время или мне нужно добавить в некоторые расчеты значение +/- нескольких мсек при воспроизведении?

1 Ответ

3 голосов
/ 30 марта 2020

Похоже, что цель этой задачи - AudioWorkletNode .

Согласно документации AudioBufferSourceNode :

Интерфейс AudioBufferSourceNode - это AudioScheduledSourceNode, представляющий источник звука, состоящий из аудиоданных в памяти, хранящихся в AudioBuffer. Это особенно полезно для воспроизведения аудио, которое предъявляет особенно строгие требования к точности синхронизации, например, для звуков, которые должны соответствовать заданному ритму c и могут храниться в памяти, а не воспроизводиться с диска или из сети. Для воспроизведения звуков, которые требуют точной синхронизации, но должны * передаваться из сети или воспроизводиться с диска, используйте AudioWorkletNode для его воспроизведения.

В этом случае точно реализована потоковая передача из сети. , AudioBufferSourceNode - это , а не , предназначенный для обновления на лету из сети.

Что может привести к десин c:

  1. По своей природе планировщик javascript не гарантирует выполнение кода в точное время. Узел может одновременно выполнять другую работу, что приводит к задержке отправки информации
  2. Таймер запускает следующий тик после отправки всех данных, что может занять некоторое время
  3. Планировщик на стороне клиента имеет даже больше ограничений, чем на стороне сервера. Как правило, браузер может выполнять около 250 таймеров в секунду (по одному каждые 4 мс).
  4. Используемый API не предназначен для этого потока

Рекомендации :

  1. Всегда сохраняйте буфер. Если по какой-то причине кадры из буфера уже воспроизводились, было бы разумно запросить новые быстрее.
  2. Увеличение буфера на лету. После получения двух сообщений неплохо начать воспроизведение, но может быть разумно увеличить количество буферизованных сообщений на лету, возможно, до 15 секунд.
  3. Предпочитать другой инструмент для работы с соединением и данными. передачи. Nginx отлично послужит. Если у клиента медленное соединение, он будет «удерживать» узел до тех пор, пока данные не будут переданы.
  4. В случае обрыва соединения на секунду (например, в мобильной сети) должно быть что-то для восстановления состояние из правильного кадра, обновить буфер и делать все это без перерывов.
...