Привет, Хабр! Мне вот сказали, что было бы интересно почитать тут статью о моих приключениях с доставшимся мне по наследству Philips LX8300SA, как я его пытался осовременить для использования с моим Mac. Поэтому я и решил попробовать себя в написании своей первой тут статьи 🙂
Как все начиналось
Отрыл у нас в квартире эту вундервафлю, попытался подключить — динамики показались вполне неплохими. Быстренько собрал полную конфигурацию у себя на столе, звук понравился больше, чем у недавно проданной тогда Яндекс Станции 2. К сожалению, фото уже не найду, но расстановка 5.1 там была нарушена полностью. Сделав AirPlay через ShairPort-Sync, слушал на нем треки из Apple Music. А потом мне захотелось большего — наконец понять, правда ли треки в Dolby Atmos так хороши.
Скрытый текст
Я прекрасно знаю, что 5.1(.0) система недостаточна для Dolby Atmos. Но, даже в документации Dolby по конфигурациям аудиосистем, есть отступление, что в системах без потолочных/up-firing динамиков можно использовать «виртуальный» Atmos.
Up-firing динамики — это колонны, так же играющие звук в потолок под определенным углом. Ими можно отчасти заменить потолочные динамики в конфигурациях Dolby Atmos.
Расстановка динамиков
Как я уже написал выше, изначально все это добро просто стояло на столе. Никакой схемы расстановки, upmix делал Dolby Pro Logic II, встроенный в DSP домашнего кинотеатра. В общем, дикий колхоз и 0 смысла от 5.1 конфигурации. Ниже показана авторская репрезентация того, как это было.
После того, как я захотел испытать на слух нормальный 5.1, я сделал нормальную расстановку по гайдам Dolby. Задние динамики разнесены по краям комнаты (RL — с края дивана, RR — на коробке от штатива у стенки), стол стоит по центру комнаты (стены комнаты), напротив дивана, на его краях FL и FR динамики, а по центру стола — сабвуфер (LFE). Фото задних динамиков не будет, простите. Мне слишком стыдно показывать колхоз, на котором они держатся. Передние динамики немного повернуты, чтобы быть более направленными в сторону слушателя.
Передача 6-канального звука на двадцатилетний домашний кинотеатр с современной машины
Самая интересная часть — как же передавать многоканальный звук на данный AV ресивер с современного железа? Для начала — аналоговых входов на каждый канал у него нет.
Да и ALC662 на борту моего Linux сервера — довольно посредственный кодек. Поэтому вариант с передачей аналогового звука я отбросил сразу же. Остается только коаксиальный S/PDIF. Какие же кодеки мы имеем на борту?
-
PCM 2.0 (заявлены 48kHz/24bit, но, если верить ALSA, спокойно принимает и 96kHz/32bit)
-
Dolby Digital (AC-3) 5.1 до 640 Kbps
-
DTS 5.1 до 768 Kbps
Скрытый текст
Потолок у Dolby AC-3 по битрейту — 640 Kbps даже на бумаге, так что тут с моими опытами все ясно.
Что же не так с DTS? По умолчанию, DTS на DVD шел с битрейтом в 1536 Kbps. Это позволяло получить довольно приличное качество для 6-канального lossy кодека. Пропатчив dcaenc
(прозрачный энкодер DTS для ALSA), опытным путем выяснил, что максимальный битрейт без артефактов — 768Kbps. Дело, скорее всего, не в подключении. Битрейт того же PCM 2.0 48kHz / 24 bit уже равен 48 kHz * 24 bit * 2 ch = 2304 Kbps. И он работает нормально.
Самый простой вариант применить эти кодеки, который я нашел — использовать Linux сервер для прозрачного энкодинга PCM 5.1 в Dolby AC-3 / DTS. Я использую Fedora, установка плагина ALSA для AC-3 была довольно простой:
sudo dnf install alsa-plugins-a52
Далее я поднял битрейт в стандартном конфиге A52 по пути /etc/alsa/conf.d/60-a52-encoder.conf
:
... @args.BITRATE { type integer default 640 } ...
Качество звука при проигрывании тестовых файлов через mpv меня устраивало. С DTS оно было хуже, поэтому я остановился на Dolby AC-3. Но теперь возник вопрос: как передать 5.1 звук с Mac на Linux, причем так, чтобы Mac видел это безобразие как 5.1 звуковое устройство, чтобы декодер Atmos в Apple Music правильно раскидывал звук на динамики?
Стриминг 5.1 звука по сети с Mac на Linux
С первого взгляда нетривиальная задача. Давайте посмотрим найденных мною кандидатов, а именно способы стриминга между платформами в целом:
-
NetJACK2. Хороший вариант, если бы сервер был у меня в LAN. К сожалению, весь трафик роутера идет через сервер, он стоит в WAN, поэтому мультикаст добраться до локальной сети не сможет.
-
ROC: Новый способ передачи звука по сети, имеет удобные утилиты и низкую задержку. Но не поддерживает 5.1 звук (есть незакрытый Issue с полупустым чеклистом на момент написания статьи).
-
AirPlay: Не поддерживает Dolby Atmos стриминг (хоть и есть движения в этом направлении).
Задуманные для этого добра методы нам не подходят. Итак, пришло время делать костыли — за протокол был взят PulseAudio, который умеет прозрачно передавать звук по TCP. Для включения этого протокола на PipeWire требуется создать файл ~/.config/pipewire/pipewire-pulse.conf.d/network.conf
:
pulse.properties = { server.address = [ "unix:native" "tcp:192.168.128.1:4656" ] }
192.168.128.1
здесь — локальный IP самого сервера.
Теперь поговорим о стороне клиента. Устанавливаем PulseAudio на macOS (да, я сам был удивлен, что это — кроссплатформа):
brew install pulseaudio
Но тут возникает проблема. PulseAudio на macOS не умеет работать с CoreAudio (подсистемой аудио на Mac), в результате чего устройств из PA мы не видим. Поэтому я пошел пересобирать BlackHole (Open-Source loopback драйвер под Mac). Устанавливаем Xcode Command Line Tools, скачиваем репозиторий и собираем с изменненой конфигурацией (названия изменены для отсутствия конфликтов с обычным BlackHole) без codesign:
xcodebuild CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO \ -project BlackHole.xcodeproj \ GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS kLatency_Frame_Size=4096 kNumber_Of_Channels=6 kSampleRates=44100,48000 kDevice_IsHidden=false kDevice_HasInput=true kDevice_HasOutput=false kDevice_Name="PhilipsCapture" kDevice2_Name="Philips5.1" kDevice2_IsHidden=false kDevice2_HasInput=false kDevice2_HasOutput=true'
Далее подписываем драйвер для использования локально на вашем Mac, чтобы Gatekeeper не делал нам мозг:
sudo codesign --force --deep --sign - build/Release/BlackHole.driver
Следующий вопрос — чем писать звук в pipe? Самым стабильным вариантом у меня оказался sox. Устанавливаем:
brew install sox
После этого я решил на скорую руку сделать скрипт для быстрого включения всего этого безобразия. Пройдемся по основным частям.
Аргументы запуска. Из основных для себя настроек я выделил звуковую схему (5.1 / 2.0) и тип моего расположения в данный момент (диван/стол). О расположении поясню далее.
#!/bin/bash # Sound stage mode: # 5.1 / 2.0 MODE="$1" [ -z "$MODE" ] && MODE="5.1" # 5.1 mode: # table / couch MODE51="$2" [ -z "$MODE51" ] && MODE51="couch" # SSH target TARGET="tdrk@supercomputer.local"
Адаптация громкости динамиков под моё расположение. Иногда я люблю слушать музыку за столом, сидя на кресле, а иногда сидя на диване. Понятное дело, что расстояния между мною и передними / задними динамиками при смене моей позиции сильно меняются. Это чинится с помощью громкости и задержки на ближайших к слушателю динамиках (так уж вышло, что скорость звука не такая и высокая). Задержку я так и не понял как реализовать на PipeWire, так что ее я пропустил. Подобрал вот такие значения опытным путем:
51prepare() { # 0 - 65535 if [ "$MODE51" = "table" ]; then VOL_FS=53768 VOL_FC=50368 VOL_RS=65535 VOL_LFE=65535 elif [ "$MODE51" = "couch" ]; then VOL_FS=65535 VOL_FC=65535 VOL_RS=60535 VOL_LFE=65535 else echo "Unknown 5.1 mode - $MODE51" exit 1 fi # FL FR RL RR FC LFE ssh "$TARGET" "pactl set-sink-volume $PADEVICE $VOL_FS $VOL_FS $VOL_RS $VOL_RS $VOL_FC $VOL_LFE" }
Подготовка клиента и сервера к проигрыванию. Необходимо выбрать нужный профиль S/PDIF и нужное звуковое устройство на Mac. Для этого надо скачать еще одну маленькую утилиту:
brew install switchaudio-osx
В коде все выглядит так:
setprofile() { ALSA_PCI="pci-0000_00_1b.0" ssh "$TARGET" "pactl set-card-profile alsa_card.$ALSA_PCI output:$1" export PADEVICE="alsa_output.$ALSA_PCI.$1" sleep 0.2 # Let AV receiver detect Dolby Digital / PCM output } prepare() { if [ "$MODE" = "2.0" ]; then setprofile "iec958-stereo" DEVICE="BlackHole 2ch" elif [ "$MODE" = "5.1" ]; then setprofile "iec958-ac3-surround-51" DEVICE="Philips5.1" 51prepare # Adjust volumes depending on listener position else echo "Unknown sound stage $MODE" exit 1 fi export PADEVICE SwitchAudioSource -s "$DEVICE" }
Стриминг. Sox пишет данные из CoreAudio, отправляя их в pipe в формате PCM 5.1 (48kHz, S32LE). В аргументы функции пишем Loopback устройство на вход и маппинг каналов в формате PulseAudio.
run() { PASERVER="192.168.128.1:4656" CAP_DEVICE="$1" CHANNEL_MAP="$2" # Space acts as a +1 CHANNELS=$(printf '%s ' `sed 's/[^,]//g' <<< "$CHANNEL_MAP"` | wc -c) sox \ -r 48000 -b 32 -c $CHANNELS -e signed-integer \ -t coreaudio "$CAP_DEVICE" \ -p | paplay \ -s "$PASERVER" -d "$PADEVICE" -v --raw \ --rate 48000 --format s32le --channels $CHANNELS \ --channel-map="$CHANNEL_MAP" }
Далее делаем простую функцию для выбора этих аргументов на базе выбранной звуковой схемы:
pick() { case "$MODE" in "5.1") run \ "PhilipsCapture" \ "front-left,front-right,front-center,lfe,rear-left,rear-right" ;; "2.0") run \ "BlackHole 2ch" \ "front-left,front-right" ;; *) echo "Unknown sound stage $MODE" exit 1 ;; esac }
Заходим в Audio MIDI Setup и выставляем каналы и частоту дискретизации как указаны ниже.
Скрытый текст
48000 Гц
1 — передний левый
2 — передний правый
3 — передний центральный
4 — сабвуфер
5 — задний левый
6 — задний правый
Заканчивается скрипт простым while true для автоматического перезапуска всей системы при обрывах соединения:
prepare while true; do pick sleep 0.1 done
Полный текст скрипта:
Скрытый текст
#!/bin/bash # Sound stage mode: # 5.1 / 2.0 MODE="$1" [ -z "$MODE" ] && MODE="5.1" # 5.1 mode: # table / couch MODE51="$2" [ -z "$MODE51" ] && MODE51="couch" # SSH target TARGET="tdrk@supercomputer.local" 51prepare() { # 0 - 65535 if [ "$MODE51" = "table" ]; then VOL_FS=53768 VOL_FC=50368 VOL_RS=65535 VOL_LFE=65535 elif [ "$MODE51" = "couch" ]; then VOL_FS=65535 VOL_FC=65535 VOL_RS=60535 VOL_LFE=65535 else echo "Unknown 5.1 mode - $MODE51" exit 1 fi # FL FR RL RR FC LFE ssh "$TARGET" "pactl set-sink-volume $PADEVICE $VOL_FS $VOL_FS $VOL_RS $VOL_RS $VOL_FC $VOL_LFE" } setprofile() { ALSA_PCI="pci-0000_00_1b.0" ssh "$TARGET" "pactl set-card-profile alsa_card.$ALSA_PCI output:$1" export PADEVICE="alsa_output.$ALSA_PCI.$1" sleep 0.2 # Let AV receiver detect Dolby Digital / PCM output } prepare() { if [ "$MODE" = "2.0" ]; then setprofile "iec958-stereo" DEVICE="BlackHole 2ch" elif [ "$MODE" = "5.1" ]; then setprofile "iec958-ac3-surround-51" DEVICE="Philips5.1" 51prepare # Adjust volumes depending on listener position else echo "Unknown sound stage $MODE" exit 1 fi export PADEVICE SwitchAudioSource -s "$DEVICE" } run() { CAP_DEVICE="$1" CHANNEL_MAP="$2" # Space acts as a +1 CHANNELS=$(printf '%s ' `sed 's/[^,]//g' <<< "$CHANNEL_MAP"` | wc -c) sox \ -r 48000 -b 32 -c $CHANNELS -e signed-integer \ -t coreaudio "$CAP_DEVICE" \ -p | paplay \ -s 192.168.128.1:4656 -d "$PADEVICE" -v --raw \ --rate 48000 --format s32le --channels $CHANNELS \ --channel-map="$CHANNEL_MAP" } pick() { case "$MODE" in "5.1") run \ "PhilipsCapture" \ "front-left,front-right,front-center,lfe,rear-left,rear-right" ;; "2.0") run \ "BlackHole 2ch" \ "front-left,front-right" ;; *) echo "Unknown sound stage $MODE" exit 1 ;; esac } prepare while true; do pick sleep 0.1 done
./audio.sh 5.1 couch
И… Оно работает! Не без проблем, но работает. И, за свои 0 рублей (кинотеатр этот достался мне по наследству), звук просто шикарен. Что еще нужно для счастья?)
Заключение
Иногда соединение прерывается, иногда приходится делать systemctl --user restart pipewire pipewire-pulse
(так и не разобрался, почему), но я доволен результатом такого колхоза и костылей, даже такой 5.1 звук имеет очень выраженный объем, многие треки из своей библиотеки я будто бы первый раз слушал.
Скрипт не идеален, потому-что писал в основном для себя. Мне будет приятно, если эта статья была вам чем-то полезна или просто принесла удовольствие при прочтении!)
Если таки найду деньги на покупку второго такого же кинотеатра и USB S/PDIF, попытаюсь выпустить вторую часть с доработкой данной 5.1 системы до 5.2.4 (уже Atmos-enabled система).
Спасибо за ваше внимание, буду рад услышать критику, так или иначе, моя первая статья тут 🙂
ссылка на оригинал статьи https://habr.com/ru/articles/861748/
Добавить комментарий