Создание мультирум аудио систем позволяет достичь сразу несколько целей.

  1. Воспроизведение в нескольких помещениях одинакового аудиосигнала (музыкальный фон)
  2. Возможность в каждом помещении воспроизводить свой собственный аудиосигнал
  3. Возможность распределенного воспроизведения уведомлений (например, дверной звонок звенит не около двери на полной громкости, а с небольшой громкостью через все либо через определенные динамики).

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

Основой для мультирум системы выступило свободное решение Snapcast . Серверная часть запущена на домашнем сервере, в качестве клиентов по комнатам выступают либо миникомпьютеры Orange PI zero с подключенными к ним активными колонками, либо более мощные Rasberry PI с установленным медиаплеером Kodi (дистрибьютив Libreelec).

Основные возможности готовой системы


  1. Воспроизведение фоном интернет радиостанции
  2. Возможность проиграть музыку на мультирум (либо на отдельно выбранном клиенте) с помощью Airplay, UPnP либо через плейер Plex. В планах добавить поддержку bluetooth, хотя мне это и не особо актуально
  3. Проигрывание произвольного контента с компьютера через веб интерфейс
  4. Смена воспроизводимой радиостанции вручную либо по расписанию
  5. Задание каждому клиенту любого источника
  6. Управление громкостью индивидуально для каждого звукового устройства (работает так: собственный регулятор аудиосистемы установлен на максимум, громкость каждого клиента snapclient регулируется с сервера при необходимости (обычно также установлена на максимум), а общий уровень громкости регулируется с того источника, с которого идет воспроизведение — телефон, компьютерый плеер либо mpd)

На клиентах сейчас сделано без изысков — стоит armbian, на который установлен shairport и snapclient, а в планах доставить upmpdcli и plexamp, что бы каждый клиент выступал универсальной точкой, воспроизводящей звук по любому возможному протоколу. Основная проблема, которая пока мешает это сделать, это то, что Linux не позволяет расшарить одно ALSA аудиоустройство между несколькими программами, и тут приходится либо на время воспроизведения звука через один сервис выключать другие, либо пытаться использовать Pulseaudio, что невозможно в случае Snapclient (Snapcast работает исключительно через ALSA, т.к. это позволяет минимизировать задержки и благодаря этому звучание всех источников абсолютно синхронно. подробнее можно почитать в документации по Snapcast).

Серверная часть оформлена в виде микросервисов в виде нескольких докер контейнеров, объединенных в стек. Первоначально были планы по запуску контейнеров в кластере Swarm (да, у меня дома два компьютера объединены в Swarm кластер, на котором запущены все сервисы, нужные и не совсем нужные мне дома), но от этой идее пришлось отказаться, и стек через docker-compose.yml файл запускается на одном из компьютеров. Надежность конечно хромает, но для дома хватит. Причина невозможности запуска в кластере заключается в том, что Snapcast сервер для получения звукового потока использует fifo (типовая цепочка работает так — звук воспроизводится с помощью mpd, выходным устройством выступает fifo, откуда читает snapserver и передает поток уже всем клиентам). Но в связи с тем, что кластер не может расшарить volume, на котором размещен fifo между несколькими узлами (использовать fifo на хосте и пробрасывать его с помощью распределенной файловой системы тоже не выходит. Хотя может быть через nfs и удастся, еще не пробовал), а заставить swarm кластер запустить все контейнеры на одном узле тоже нельзя, единственный способ дать всем сервисам доступ к fifo — это запустить все на одном узле (можно конечно сделать виртуалку, или один гиганский контейнер, где через supervisor запускается все что только можно, но я решил не делать так).

Состав стека


1) Snapserver. Контейнер с сервером Snapcast. Доступен по портам 1704, 1705 и в домашней сети обращения к нему идут через dns имя snapserver.local. Умеет анонсить себя через Avahi, но при работе в докере avahi анонсы идут через отдельный контейнер (в состав этого стека не входит).

2) Snapcastr. Веб сервис для управления snapserver. Доступен по порту 5011 (доступен как snapcastr.local через локальный reverse proxy).

3) Snapchanger. Python-скрипт, который анализирует источники, воспроизводящие звук, и переключает клиентов на наиболее приоритетный источник звука, который сейчас активен. Например, интернет радио имеет наименьший приоритет и играет всегда. При воспроизведении музыки с телефона через Airplay происходит переключение на этот поток, а если в этот момент будет сигнал от умного дома, то переключится на него. При остановке потока происходит переключение обратно на активные потоки с наивысшем приоритетом. Для каждого клиента можно указать свой список потоков и приоритеты для них.

4) Snapcron. Контейнер с cron, который может в определенное время запускать скрипты, например изменяющие громкость на клиентах (выключаем музыку в спальне на ночь полностью).

5) mpd. экземпляр mpd для воспроизведения интернет радио. В домашнюю сеть проброшен на нестандартном порту 36602.

6) radio. pyhthon скрипты, которые следят за тем, что бы радио всегда воспроизводилось (бывают случаи, когда прерывается соединение, либо соединение вроде как есть, но звук не воспроизводится) а также переключащие радиостанции и громкость в зависимости от времени суток.

7-8) mpd.fm и pifi — веб оболочки для проигрывания радиостанции. Две штуки однотипных для экспериментов.

9) mopidy. Еще одна оболочка (она же отдельный сервер mpd) для воспроизведения музыки. Она выступает в виде отдельного сервера mpd и отвечает по стандртному порту для mpd — 6600. Можно использовать для прослушивания музыки. Она использует свой собственный поток и работает независимо от mpd для радиостанций.

10-12) shairport-sync, upmpdcli, plexamp — контейнеры с соответствующими клиентами. В каждом из конейнером используется свой собственный экземпляр mpd, пишущий в свою fifo. Так что у каждого клиента свой независимый поток.

Таким образом сейчас стек поддерживает:

  • Несколько независимых источником звука с произвольным выбором между ними — Default, uPnP, Mopidy, Plexamp, AirPlay и интернет-радио.
  • Управление самим Snapcast server с помощью Snapcastr.
  • Набор скриптов для обеспечения надежного и бесперебойного звучания фонового радио.
  • Управление проигрыванием радио с помощью pi-fi либо mpd.fm (дополнительно я настроил управление этим экземпляром mpd с помощью используемого у меня в домашней автоматизации Node-red).

Ссылка на репозиторий