WirePlumber: продвинутые настройки wireplumber.conf
Если после загрузки выбирается не тот выход, HDMI встроенной карты торчит в списке лишней строкой, а внешний ЦАП засыпает через минуту простоя, причина почти всегда в конфиге WirePlumber. В версии 0.5 настройки разложены по десяткам фрагментов, и без понимания иерархии непонятно, какой из них всё решает. Разберу, где физически лежат файлы, как устроено правило для карты или узла и как отключить авто-поведение, которое мешает жить.
Где лежат настройки и в каком порядке их читают?
WirePlumber читает три каталога: /usr/share/wireplumber/ с фабричными файлами пакета, /etc/wireplumber/ для общесистемных правок и ~/.config/wireplumber/ для личных. Сначала загружается главный файл /usr/share/wireplumber/wireplumber.conf, затем подхватываются фрагменты из wireplumber.conf.d/ в каждом каталоге, в алфавитном порядке.
Два момента стоит запомнить сразу. Первый: файл с тем же именем в каталоге с более высоким приоритетом полностью заменяет системный, а не дополняет его. Второй: в 0.5 из поставки в wireplumber.conf.d/ лежит только alsa-vm.conf, а логика монитора ALSA живёт в Lua-скриптах /usr/share/wireplumber/scripts/monitors/alsa.lua. Файлов 50-alsa-config.conf и 51-alsa-acp.conf из версии 0.4 больше нет, и если искать правки в них, поиск заведёт в тупик.
pacman -Qo /usr/share/wireplumber/wireplumber.conf
ls -l /usr/share/wireplumber/wireplumber.conf.d/ /etc/wireplumber/
ls /usr/share/doc/wireplumber/examples/wireplumber.conf.d/
Готовые рабочие примеры лежат в последнем каталоге: alsa.conf, device.conf, profile.conf, stream.conf, log.conf. Скопируй нужный в ~/.config/wireplumber/wireplumber.conf.d/ под своим именем и правь на месте.
Как устроено правило monitor.alsa.rules?
Конфиг написан в SPA-JSON: ключи верхнего уровня, свойства контекста PipeWire, поэтому всё живёт в именованных пространствах monitor.alsa, monitor.bluez, monitor.v4l2, monitor.libcamera, плюс секции wireplumber.settings и wireplumber.profiles. Правило состоит из двух половин: matches с условиями отбора и actions с тем, что сделать.
# ~/.config/wireplumber/wireplumber.conf.d/50-custom.conf
monitor.alsa.rules = [
{
matches = [
{ node.name = "alsa_output.usb-Generic_USB_Audio-00.analog-stereo" }
]
actions = {
update-props = {
node.nick = "USB DAC"
node.priority.session = 2000
}
}
}
]
Условия и свойства берутся из одного пространства: для карты это device.*, для отдельного выхода или входа, node.*. Переименование узла и приоритет в примере из этого раздела меняют вид в списке и выбор по умолчанию, но не трогают остальные карты.
Значение с ведущей ~ читается как регулярное выражение, так что одним правилом ловятся все устройства сразу. update-props перезаписывает свойства, а insert-props добавляет их, ничего не затирая, второй вариант удобен, когда свойство уже задано в системном фрагменте.
Как отдать приоритет своему выходу и не забыть его?
Дефолтный выход выбирается по priority.session, и у большинства узлов там 1000. Подняв значение для нужного, получаешь его в списке первым. Но есть подвох: пока включено запоминание прошлого выбора, при старте сессии и при отключении устройства приоритеты почти не учитываются, и система возвращает то, что было выбрано в прошлый раз. Лечится отдельной настройкой.
wireplumber.settings = {
node.restore-default-targets = false
}
Убрать из памяти уже записанные значения можно полным сбросом состояния: сначала остановить сервис, удалить ~/.local/state/wireplumber, затем запустить обратно. Сброс стоит делать осознанно, вместе с ним улетят сохранённые громкости потоков. Подробнее про внешние ЦАП и их подключение, в статье про USB-карту как внешний ЦАП.
Почему приоритет не срабатывает с первого раза
Проверь вывод wpctl status: у узла с поднятым приоритетом в скобках должен стоять ненулевой vol, а сам он, выше в списке. Если приоритет в правиле выставлен, а в статусе значения прежние, значит правило не совпало: обычно из-за device.id в matches или опечатки в node.name. Второй частый случай, в каталоге лежит файл с расширением .txt или без .conf, и он молча игнорируется.
Как убрать лишнее устройство и задать профиль карты?
Отключается карта и узел по-разному: device.disabled = true прячет карту целиком вместе со всеми её выходами, а node.disabled = true убирает только конкретный выход, оставляя остальные рабочими. Для встроенного HDMI почти всегда нужен второй вариант с отбором по node.nick.
Профиль задаётся через ACP-свойство alsa.card.profile. Имя профиля берётся не из головы, а из конфигов UCM, которые перечисляют секции для конкретной подписи карты.
monitor.alsa.rules = [
{
matches = [
{ device.name = "alsa_card.pci-0000_0c_00.4" }
]
actions = {
update-props = {
alsa.card.profile = "iec958"
}
}
}
]
ls /usr/share/alsa/ucm2/conf.d/
grep -m5 '^Section' /usr/share/alsa/ucm2/conf.d/Signature-*/iec958.conf
Логику выбора профиля и ручное переключение я разбирал в статье про переключение аудиопрофилей в WirePlumber, с правилами становится понятно, что именно перебивает автоперебор.
Как отключить авто-приостановку и авто-подключение?
Узлы усыпляются при простое, потоки подключаются к первому подходящему выходу, а сессии пользователя отслеживаются через logind. Все три вещи включаются фрагментом, и каждая отключается своим ключом.
monitor.alsa.rules = [
{
matches = [
{ node.name = "~alsa_output.usb-.*" }
]
actions = {
update-props = {
node.suspend_on_idle = false
}
}
}
{
matches = [
{ node.name = "~alsa_output.pci-.*.iec958-stereo" }
]
actions = {
update-props = {
node.autoconnect = false
}
}
}
]
node.suspend_on_idle = false снимает усыпление по простою, а в 0.4 для этой же задачи клали node.suspend_timeout_ms = 0, ключ устарел и в новых версиях не читается. node.autoconnect = false пригождается, когда выход надо контролировать вручную: JACK-сессии, мастер-микшер или собственный роутинг. Плюс отключение слежения за сессией, которое в 0.5 живёт в профиле main:
wireplumber.profiles = {
main = {
monitor.bluez.seat-monitoring = disabled
}
}
В 0.4 для того же писалось support.logind = false, в 0.5 ключ устарел. Если не нужно сохранять громкости и прошлый выбор вообще, добавь wireplumber.persist = false.
Почему правка ничего не меняет и как это отлаживать?
Фрагмент без расширения .conf не читается, файл в неправильном каталоге игнорируется, а после правки сервис не перечитывает состояние сам. Порядок простой: перезапустить, посмотреть лог, найти идентификатор, вытащить свойства.
systemctl --user restart wireplumber
journalctl --user -u wireplumber -b -f
wpctl status
wpctl inspect 48
pw-top
Ошибка парсинга SPA-JSON видна в логе сразу после рестарта, чаще всего виновата лишняя запятая или забытые кавычки вокруг имени свойства. wpctl inspect показывает все свойства объекта целиком, оттуда берутся точные значения для matches. wpexec применяет фрагмент к уже запущенному экземпляру, но после рестарта настройки всё равно подхватятся из файла.
Подробные логи включаются отдельным фрагментом: в поставке уже есть готовый пример с настройкой уровня логов, копируешь его к себе, перезапускаешь сервис и читаешь вывод.
cp /usr/share/doc/wireplumber/examples/wireplumber.conf.d/log.conf \
~/.config/wireplumber/wireplumber.conf.d/90-log.conf
systemctl --user restart wireplumber
journalctl --user -u wireplumber -b -f
Порядок чтения работает и в пользу пользователя: личные фрагменты подключаются последними, поэтому update-props в них перебивает значения из системных файлов. Если свойство не меняется, сначала проверь, не задано ли оно там же в более позднем по алфавиту фрагменте, а потом уже переходи к отладке.
Частые вопросы
Нужно ли править /usr/share/wireplumber/ напрямую?
Нет, pacman перезапишет файл при следующем обновлении пакета. Правь в /etc/wireplumber/ для общесистемных настроек или в ~/.config/wireplumber/ для личных, второй вариант приятнее тем, что переживает обновления и легко удаляется.
Как сбросить запомненные устройства и громкости?
systemctl --user stop wireplumber
rm -r ~/.local/state/wireplumber
systemctl --user start wireplumber
Каталог восстановится пустым, и WirePlumber запишет в него состояние заново. Перед удалением стоит закрыть плеер, иначе громкость активных потоков перезапишет файл обратно.
Чем правило карты отличается от правила узла?
Отбором и набором свойств. В matches для карты пишют device.name, для узла, node.name или node.nick, а в actions для карты доступны device.*, для узла, node.*. Ошибка в этом месте выглядит как «правило есть, а ничего не изменилось».
Как найти стабильный идентификатор карты?
wpctl status даёт список, wpctl inspect с номером из этого списка, все свойства, включая device.name и node.name. Именно их и стоит класть в matches: device.id пересоздаётся между сессиями и ломает правило после перезагрузки.
Можно ли переключить вывод без конфига вообще?
Да, номер из wpctl status подходит как аргумент команды, а звёздочка в выводе помечает текущий дефолт.
wpctl status
wpctl set-default 48
Так удобно проверять приоритеты вживую, но выбор не переживает перезапуск сессии, пока включено запоминание, и после рестарта всё вернётся к тому, что лежит в состоянии. Для постоянства нужен либо сброс node.restore-default-targets, либо правило с приоритетом.
Полезные ресурсы
- ArchWiki: WirePlumber: каталог конфигурации, примеры правил, сброс состояния.
- ArchWiki: PipeWire: свойства узлов, маршруты, одновременный вывод на несколько устройств.
- PipeWire не запускается: конфликт с PulseAudio: когда мешает второй менеджер сессии.
- Нет звука после установки WirePlumber: проверка сервисов и маршрутизации до настройки правил.
Заключение
В WirePlumber 0.5 настройка живёт в правилах с matches и actions, а приоритеты работают только вместе с отключённым запоминанием выбора. Правь один фрагмент в ~/.config/wireplumber/wireplumber.conf.d/, перезапускай сервис и проверяй результат через wpctl inspect: этого хватает для почти всех задач с приоритетами, отключения лишних устройств и авто-поведения.
Не получилось? Поможем настроить
Задай вопрос в чате — отвечаем быстро, по делу и без воды.

Комментарии