- PVSM.RU - https://www.pvsm.ru -
Сидел я значится между двумя ноутбуками, на одном из которых играла музыка. Динамики старые и стерео выдают в неприкрытом моно. Между звуками барабанов и синтезаторов в моей голове прозвучала мысль — «А давай‑ка одновременно включим музыку на двух ноутбуках, получу ли я музыкальное наслаждение?» — Получил это музыкальное наслаждение я аж целых три года назад, тогда же появилась идея оформить сеё чудо в виде приложения, которое бы захватывало системный звук устройства и раздавало бы его на динамики любых других устройств (Компьютеры, планшеты, телефоны...), включая устройство захвата.
Начал я с трехступенчатой технологии Забрал - Отдал - Помолился
1. Забирал AudioChunk-и из аудиокарты Забрал
2. В сухом виде отдавал по WebSocket-у на фронт Отдал
3. AudioChunk-и отдавались Audio-элементу Помолился
Задержка была самая минимальная из всех используемых мною технологии, но вкладка в браузере, в которую беспощадно заливали мегатонны незакомпресированных, незасинхронизированных байт не щадила слабые устройства, из-за чего на телефоне высвечивалось предложение закрыть приложение браузера и попробовать другой способ передачи аудио

В рамках профессиональный деятельности познакомился с WebRTC, технология которая напомнила мне о моей заброшенной к этому моменту идее - Передача медиа-траффика между подписчиком и зрителем с наименьшей задержкой. Тогда я решил выйти за рамки и интегрировать WebRTC в свой личный проект. Использовал WebRTC Native библиотеку на C++, чтобы создавать RTCPeerConnection на том же уровне, на котором я забираю звук. По концепции получилась SFU сессия, где один участник, в виде аудиокарты устройства на котором запущено приложение, раздает звук всем участникам, подключающихся через фронт. Основная задача стояла в том, чтобы использовать WebRTC не только как передачу с низкой задержкой, но и засинхронизировать звук между участниками. Архитектура выглядела следующим образом
Создается loopback, который устанавливается как дефолтный аудиовыход, за счет чего получает все звуки устройства
MASTER RTCPeerConnection, который создается при запуске приложения как мастер-пир, забирает звук с loopback и с которым все создают соединения и получают от него audio, timestamp , syncTime
LOCAL RTCPeerConnection, который также создается при запуске приложения, устанавливает соединение с мастер-пиром и перенаправляет аудио-данные на физическую аудиокарту, это шаг позволяет устройству поставляющего звук, играть его синхронно с другими устройствами
BROWSER RTCPeerConnection, который создается
Выглядит просто, но настроить ее оказалось невозможно. Несмотря на то, что каждый участник получал чанки, с одинаковым syncTime для его проигрыша, рассинхрон был жуткий. Не помогала буферизация и принудительная задержка, чтобы браузер успел все обдумать и вовремя проиграть чанк.
Snapcast - сервер, который раздает звук в идеальной синхронизации, остается только его кормить
Архитектура вышла следующей:
LOOPBACK - Создается виртуальный аудиовыход, который устанавливается как дефолтный в системе
ROUTER - Перенаправляет звук с LOOPBACK на SNAPCAST
SNAPCAST - Сервер, который раздает
LOCAL SNAPCLIENT - Создается на устройство, где запущено приложение, подключается к SNAPCAST и перенаправляет звук на физические динамики
BROWSER SNAPCLIENT - Любое устройство, подключившееся к приложению через фронт
Приложение позволяет превратить любое устройство в колонку, находящееся в той же локальной сети и имеющее возможность открывать вкладки в браузере.

Автор: LiuBimba
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/mul-tirum/449464
Ссылки в тексте:
[1] Snapcast - Synchronous audio player: https://github.com/snapcast/snapcast
[2] github.com: https://github.com/pauldekarin/multiroom
[3] Источник: https://habr.com/ru/articles/1022124/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1022124
Нажмите здесь для печати.