Все об Arch Linux

Arch Linux будет тем, что вы из него сделаете!

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, либо правило с приоритетом.

Полезные ресурсы

Заключение

В WirePlumber 0.5 настройка живёт в правилах с matches и actions, а приоритеты работают только вместе с отключённым запоминанием выбора. Правь один фрагмент в ~/.config/wireplumber/wireplumber.conf.d/, перезапускай сервис и проверяй результат через wpctl inspect — этого хватает для почти всех задач с приоритетами, отключения лишних устройств и авто-поведения.



Не получилось? Поможем настроить

Задай вопрос в чате — отвечаем быстро, по делу и без воды.

Читайте также

Комментарии

Загрузка…

Откроется GitHub: создайте новый issue с вашим комментарием (кнопка «Submit new issue»). После отправки обновите эту страницу — комментарий появится ниже.

Telegram Max