Распределенный аудиоплеер на Odroid U2

в 20:12, , рубрики: linux, mpd, pulseaudio, музыка, Работа со звуком, метки: , ,

Распределенный аудиоплеер на Odroid U2Однажды я заметил, что довольно много времени я провожу на кухне, куда звук от колонок, расположенных в комнате доходит плохо. И тогда мне захотелось сделать хороший бесшумный плеер, способный синхронно воспроизводить музыку в нескольких комнатах. Конечно проблему можно было решить простым поворотом регулятора громкости, но этот способ был отброшен как негуманный по отношению к соседям. Другой важный момент заключался в том, что я хотел использовать те же колонки для вывода звука с компьютера. Зачем мне иметь несколько комплектов аккустики в одной комнате?
Пост получился довольно длиннный, так как я старался уделить внимание соображениям, по которым я выбирал то или иное решение.

Железо

  • HiFi колонки и усилитель — по комплекту для каждой комнаты. Все устройства в комнате должны их использовать.
  • USB звуковая карта
  • Ethernet — старая добрая надёжная и предсказуемая среда передачи данных. Лучшее решение, если есть возможность проложить несколько кабелей.
  • NAS — музыку надо где-то хранить. Флеш карты хороши, но их объема недостаточно для хранения loseless музыки, поэтому остаются HDD. Но жесткие диски шумят, так что им самое место в дальнем углу на антресолях или в кладовке. Кроме того, у нормального NAS будет гигабитный порт, а на всех маленьких ARM платах 100 мегабитный.

Софт

Синхронное воспроизведение

Программ, способный синхронно воспроизводить звук очень мало. Наше ухо может различать малейшие отклонения и мы начинаем слышать эхо. Удовольствия столько же, как от объявлений прибывающих поездов через громкую связь на вокзале в глубинке. Хороший результат показывают две звуковые системы: jack и PulseAudio. Говорят, что еще неплохо работает squeezebox. Я также пробовал mplayer и vlc, но добиться от них приемлемой синхронности не получилось. Vlc неплохо справляется с видеопотоком, если использовать RTP multicast, но у звука наблюдается заметное эхо. А с video on demand синхронизации вообще нет, так как каждый клиент получает отдельный поток. Mplayer просто ужасно тормозит, если включить udp синхронизацию.
Так что, если нет необходимости синхронно отображать видео, то jack или PulseAudio являются хорошим выбором за счет своей гибкости. Если же нужно видео… дайте мне знать, если найдется что-то действительно работающее.

Jack vs PulseAudio

После длительных поисков оказалось, что никакой борьбы между ними нет: их писали для совсем разных целей. Мне не нужны очень короткие задержки и огромная гибкость в коммутации потоков во время работы для того, чтобы слушать музыку. Зато я хочу меньше грузить CPU и не гонять пакеты по сети, если ничего не воспроизводится. Все, что мне надо — это включать и выключать заранее определенные выходы. Поэтому в моём случае PulseAudio является предпочтительным выбором.

PulseAudio

Hint: Первым делом надо правильно настроить часы. Если они будут плохо синхронизированны между устройствами, могут возникать странные баги. Поэтому везде надо установить ntpd.
Настроить синхронное воспроизведение можно несколькими способами. Можно использовать module-combine-sink совместно с module-tunnel-sink, а можно использовать широковещательные rtp потоки. Я выбрал module-combine-sink, так как он дает значительно меньшую зарежку. Но он не работает через WiFi, а rtp может быть и будет. Но я не люблю WiFi, я люблю проводочки.
Еще одна тонкость заключается в том, что PulseAudio может работать либо как общесистемный демон, либо для каждого пользователя отдельно. Последнее является предпочтительным решением, в основном из-за соображений безопасности, например, чтобы пользователи не могли отключать или перенаправлять чужие потоки. Но если речь идет о клиенте без X11, то остайтся толкьо системный режим. А проблемы с безопасностью… так это же ровно то, что мне надо: общий звуковой сервер для нескольких доверенных пользователей.
Если вы выбрали систеный режим, то не забудте добавить себя в группу pulse-access. Файлы настроек находятся в каталоге /etc/pulse/. Для системного режима это system.pa, а для пользовательского default.pa.

Выходные устройства

Это устройства, к которым подключены усилители. На них надо разрешить удаленный доступ, так что добавляем в конфиг module-native-protocol-tcp:

load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.0.0/16

Входные устройства

На устройстве, с которого будет идти звуковой поток, надо настроить удаленные выводы. Для каждого выходного устройства (кроме локальных выходов) добавляем строки следующего вида:

load-module module-tunnel-sink server=<output device address>

Теперь нужно научиться динамически включать и выключать их. PulseAudio посылает данные даже на заглушенные (muted) каналы, но не посылает на выключенные (suspended) выходы. Чтобы не выключать выво звука для всех приложений, создадим промежуточные выходы для каждого реального выхода:

load-module module-combine-sink sink_name=kitchen_mpd slaves=tunnel-sink.u2k.home
load-module module-combine-sink sink_name=hall_mpd slaves=alsa_output.usb-ESI_Audiotechnik_GmbH_Dr._DAC_nano-01-nano.analog-stereo

И, наконец, объединим эти выходы в один:

load-module module-combine-sink sink_name=mpd_sink slaves=kitchen_mpd,hall_mpd

Теперь, после перезапуска PulseAudio можно включать и выключать отдельные выходы командами вида

# Выключить
pactl suspend-sink hall_mpd 1
# Включить
pactl suspend-sink hall_mpd 0

Ура! Натсраиваемый выход, синхронно воспроизводящий звук через несколько выходных устройств, подключенных по сети, готов.

Восроизведение музыки

Теперь к этому выходу надо подключить какой-нибудь проигрыватель. Я выбрал MPD, так как им можно удаленно управлять почти с любого устройства. Это удобно, когда музыку слушаешь на кухне, а компьютер стоит в комнате. Настройка очень простая:

audio_output {
        type            "pulse"
        name            "Pulse"
        server          "u2.home"               # optional
        sink            "mpd_sink"
}

Но при наличии нескольких выходов хочется еще ими и управлять через интерфейс MPD. Я написал небольшой хак для MPD, который позволяет это делать. Это модифицированный NullOutput, который выполняет произвольные команды при включении и выключении. Остается настроить эти выходы на соответсвующие вызовы pactl и спрятать основной (первый) выод другим маленьким хаком.

audio_output {
        type            "exec"
        name            "Зал"
        enable          "pactl suspend-sink hall_mpd 0"
        disable         "pactl suspend-sink hall_mpd 1"
}

audio_output {
        type            "exec"
        name            "Кухня"
        enable          "/usr/bin/pactl suspend-sink kitchen_mpd 0"
        disable         "/usr/bin/pactl suspend-sink kitchen_mpd 1"
}

Совместное использование

На стационарном компьютере я прописал в /etc/pulse/client.conf

default-server = u2.home

В результате все приложения связываются с удаленным звуковым сервером напрямую. Работает безотказно.

Проблемы

Основная проблема, с которой пришлось столкнуться — это ненадежность. Если пропадает сетевое соединение PulseAudio удаляет соответствующие выходы и не пересоздает их. Приходится перезапускать вручную.
Другая проблема заключается в том, что состояние выходов в MPD и PulseAudio может не совпадать. Приходится лишний раз наживать на кнопку, чтобы включить или выключить звук.

Достоинства

Я могу слушать музыку за завтраком и за ужином. Более того, музыка хорошо слышна в большей части квартиры и играет не тихо и не громко. По-желанию отдельные зоны можно отключать. Управлять ей легко и просто. В общем, коте одобряет:

Распределенный аудиоплеер на Odroid U2

Автор: kibergus

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js