Многие пользователи Linux годами смирялись с заиканиями при воспроизведении, конфликтами устройств вывода и нестабильной работой Bluetooth-наушников. Причиной часто была архитектура PulseAudio, которая не справлялась с современными задачами обработки звука. Появление PipeWire кардинально изменило ситуацию: новый медиасервер объединил низкую задержку JACK, совместимость с PulseAudio и нативную поддержку видеопотоков в одном процессе. В этой статье разберём, как правильно удалить PulseAudio, настроить PipeWire и WirePlumber, добиться одновременного звука на двух парах Bluetooth-наушников и устранить типичные проблемы.
Архитектурные преимущества новой подсистемы
PipeWire не просто заменяет PulseAudio - он перестраивает всю графовую модель обработки звука. Вместо жесткой иерархии приёмник - источник, PipeWire строит динамический граф узлов, где каждый поток может быть соединён с любым другим. Фоновая служба pipewire работает как единственный процесс, управляющий всеми медиапотоками, а WirePlumber выступает в роли менеджера сессий, автоматически связывая устройства и приложения по заданным правилам.
В основе лежит SPA - Simple Plugin API, набор C-интерфейсов для плагинов обработки звука и видео. Каждый узел графа представляет собой поток данных с входными и выходными портами. Форматы согласовываются динамически: при соединении узлы обмениваются возможностями через параметр EnumFormat и выбирают общий формат без пересэмплирования, если это возможно. Это исключает потерю качества при цепочке преобразований.
Ключевое отличие - поддержка профессионального аудио с задержкой ниже 1 мс без отдельного запуска JACK. Приложения, написанные под PulseAudio, JACK или ALSA, продолжают работать без изменений благодаря модулям совместимости pipewire-pulse, pipewire-jack и pipewire-alsa. Для контейнеров Flatpak и песочниц это означает единый путь доступа к звуковому оборудованию без лишних прослоек.
Bluetooth-стек в PipeWire переписан с нуля. Вместо старого модуля module-bluez5-device теперь используется нативный SPA-плагин libspa-bluez5, который напрямую общается с BlueZ через D-Bus. Это даёт поддержку современных профилей LE Audio и кодека LC3, аппаратное управление громкостью VCP/VCS и корректную работу TWS-наушников, где каждое ухо - отдельное устройство. Синхронизация каналов достигается на уровне графа с точностью до субсэмплов.
Видеоподдержка интегрирована в тот же граф: захват экрана, веб-камеры и аппаратное кодирование через VAAPI/VDPAU работают как обычные узлы. Приложения Wayland (GNOME Shell, OBS, браузеры) запрашивают видеопотоки через PipeWire вместо отдельных фоновых служб, что упрощает конвейер записи экрана и видеоконференций.
Удаление PulseAudio и установка PipeWire
Полная замена требует установки пакетов PipeWire и одновременного удаления конфликтующих пакетов PulseAudio. В Arch Linux и производных выполните:
sudo pacman -Rns pulseaudio pulseaudio-alsa pulseaudio-bluetooth pavucontrol
sudo pacman -S pipewire wireplumber pipewire-pulse pipewire-alsa pipewire-jack libpipewire03 gst-plugin-pipewire helvum
В Fedora используйте dnf swap:
sudo dnf swap pulseaudio pipewire --allowerasing
sudo dnf install wireplumber pipewire-pulseaudio pipewire-alsa pipewire-jack pipewire-libs gstreamer1-plugin-pipewire helvum
В Ubuntu и Debian 12+ переключение делается через метапакет:
sudo apt install pipewire wireplumber pipewire-pulse pipewire-alsa pipewire-jack libspa-02-bluetooth libpipewire-0.3-modules gstreamer1.0-pipewire helvum
sudo apt remove pulseaudio pulseaudio-module-bluetooth pavucontrol
После установки включите пользовательские службы:
systemctl --user enable --now pipewire wireplumber pipewire-pulse
Проверьте, что сервер запущен и виден клиентам:
pactl info | grep "Server Name"
wpctl status
Вывод pactl info должен показать Server Name: PulseAudio (on PipeWire 1.2.x) - это подтверждает, что модуль совместимости работает. Команда wpctl status выдаст дерево устройств с метками * у активных приёмников.
Настройка WirePlumber для стабильной работы Bluetooth
WirePlumber управляет политиками подключения устройств через Lua-скрипты в /usr/share/wireplumber/main.lua.d/ и пользовательские переопределения в ~/.config/wireplumber/. Для Bluetooth критически важны два параметра: автоматическое переключение профиля и приоритет кодеков.
Создайте файл ~/.config/wireplumber/main.lua.d/50-bluetooth-policy.lua со следующим содержимым:
-- Принудительное включение A2DP Sink для наушников
rule = {
matches = {
{
{ "device.api", "=", "bluez" },
{ "device.profile", "=", "a2dp-sink" },
},
},
apply_properties = {
["bluez5.auto-connect"] = "[ a2dp-sink ]",
["bluez5.codecs"] = "[ aac aptx aptx-hd ldac ]",
},
}
Этот скрипт заставляет WirePlumber сразу переключать подключенные наушники в профиль a2dp-sink с приоритетом высококачественных кодеков. По умолчанию может выбираться hfp или headset-head-unit, что даёт моно-звук низкого качества.
Для LE Audio устройств (современные TWS-наушники с поддержкой LC3) добавьте в /etc/bluetooth/main.conf:
[General]
ControllerMode = le
Experimental = true
KernelExperimental = true
Перезапустите службу Bluetooth:
sudo systemctl restart bluetooth
Теперь устройства с поддержкой LE Audio будут соединяться по новому профилю bap-sink или bap-duplex, обеспечивая стерео-звук с кодеком LC3 и аппаратную синхронизацию ушных модулей.
Решение проблем с заиканиями и xrun
Заикания (xrun) возникают, когда графический процесс не успевает обработать буфер за квант времени. В PipeWire основные параметры задержки задаются в /etc/pipewire/pipewire.conf секции context.properties:
context.properties = {
default.clock.rate = 48000
default.clock.allowed-rates = [ 48000 44100 96000 192000 ]
default.clock.quantum = 1024
default.clock.min-quantum = 32
default.clock.max-quantum = 8192
}
Параметр default.clock.quantum - размер буфера в семплах. При 48 кГц значение 1024 даёт задержку 21,3 мс. Для низколатентных задач (игры, мониторинг) уменьшите до 256 или 128, но это повышает нагрузку на CPU. Если xrun остаются, добавьте в context.modules модуль реального времени:
{ name = libpipewire-module-rt
args = {
nice.level = -11
rt.prio = 88
rt.time.soft = 200000
rt.time.hard = 200000
}
}
Модуль запрашивает планировщик SCHED_FIFO с приоритетом 88. Требует настройки лимитов в /etc/security/limits.conf:
@audio - rtprio 90
@audio - memlock unlimited
Добавьте пользователя в группу audio:
sudo usermod -aG audio $USER
После перелогинивания заикания при высокой нагрузке должны исчезнуть. Проверить наличие xrun можно командой:
pw-top -p
Колонка ERR покажет количество пропусков буфера. Ненулевые значения - повод увеличить quantum или снизить приоритет реального времени.
Частая причина xrun - конфликт частот дискретизации. Если одно приложение просит 44,1 кГц, а устройство работает на 48 кГц, включится ресэмплер. В PipeWire используется нативный ресэмплер со скосом, но при малом quantum он может не укладываться. Добавьте в context.properties принудительную частоту для проблемных узлов:
default.clock.force-rate = 48000
default.clock.force-quantum = 1024
Также проверьте, не занят ли CPU другими процессами. htop покажет загрузку по ядрам. Если одно ядро на 100%, увеличьте quantum до 2048 или перенесите PipeWire на выделенное ядро через taskset:
systemctl --user edit pipewire
# Добавьте в секцию [Service]:
# ExecStartPre=/bin/sh -c 'taskset -cp 1 $(pgrep -f "pipewire$")'
Одновременный вывод на две пары Bluetooth-наушников
PipeWire позволяет объединить несколько приёмников в один виртуальный приёмник через модуль libpipewire-module-combine-stream. Это нативный аналог module-combine-sink из PulseAudio, но с компенсацией задержки и работой в графе.
Создайте файл ~/.config/pipewire/pipewire.conf.d/99-combine-bluetooth.conf:
context.modules = [
{
name = libpipewire-module-combine-stream
args = {
combine.mode = sink
node.name = "combined_bt_sink"
node.description = "Две пары Bluetooth-наушников"
combine.latency-compensate = true
combine.props = {
audio.position = [ FL FR ]
}
stream.props = {
stream.dont-remix = true
node.passive = true
}
stream.rules = [
{
matches = [
{ media.class = "Audio/Sink" }
{ device.api = "bluez" }
{ node.name = "~bluez_output.*" }
]
actions = { create-stream = { } }
}
]
}
}
]
Правило stream.rules автоматически находит все Bluetooth-приёмники (device.api = "bluez") и создаёт для каждого поток в комбинированном приёмнике. Параметр combine.latency-compensate = true добавляет задержки к более быстрым устройствам, чтобы звук играл синхронно.
Перезапустите PipeWire:
systemctl --user restart pipewire wireplumber
В pavucontrol или wpctl status появится новый приёмник "Две пары Bluetooth-наушников". Выберите его как устройство вывода по умолчанию:
wpctl set-default $(wpctl status | awk '/combined_bt_sink/ {print $2}' | tr -d '.')
Теперь звук из любого приложения пойдёт на обе пары наушников одновременно. Громкость каждой пары регулируется отдельно через pavucontrol - виртуальный приёмник имеет монитор-каналы для каждого входящего потока.
Если нужно объединить конкретные устройства по MAC-адресу, замените stream.rules на явные совпадения:
stream.rules = [
{
matches = [
{ media.class = "Audio/Sink" }
{ node.name = "bluez_output.XX_XX_XX_XX_XX_XX.a2dp-sink" }
]
actions = { create-stream = { combine.audio.position = [ FL FR ] } }
},
{
matches = [
{ media.class = "Audio/Sink" }
{ node.name = "bluez_output.YY_YY_YY_YY_YY_YY.a2dp-sink" }
]
actions = { create-stream = { combine.audio.position = [ FL FR ] } }
}
]
Узнайте точные имена узлов командой wpctl status или pw-dump | jq '.[] | select(.info.props["media.class"] == "Audio/Sink") | .info.props["node.name"]'.
Диагностика и устранение конфликтов устройств
Когда несколько приложений борются за одно устройство, или приёмник "пропадает" после сна, помогает анализ графа PipeWire. Установите helvum - графический патчбей для визуального управления связями:
helvum
В интерфейсе увидите все узлы (приложения, устройства, виртуальные приёмники) и связи между ними. Перетаскиванием проводов можно вручную перенаправить поток, клик правой кнопкой на узле - посмотреть свойства и формат.
Для консольной диагностики используйте pw-dump - он выдаёт полный JSON-снимок графа:
pw-dump | jq '.[] | select(.type == "PipeWire:Interface:Node") | {id, name: .info.props["node.name"], class: .info.props["media.class"], device: .info.props["device.api"]}'
Покажет таблицу всех узлов с классами и API устройств. Ищите узлы с media.class = "Audio/Sink" и device.api = "bluez" - это ваши Bluetooth-приёмники.
Если устройство не переключается на нужный профиль, проверьте доступные профили:
pactl list cards | grep -A 20 "bluez_card"
И принудительно установите профиль:
pactl set-card-profile bluez_card.XX_XX_XX_XX_XX_XX a2dp-sink
Для постоянного решения добавьте правило в WirePlumber (файл ~/.config/wireplumber/main.lua.d/51-force-a2dp.lua):
rule = {
matches = {
{
{ "device.api", "=", "bluez" },
{ "device.profile", "=", "a2dp-sink" },
},
},
apply_properties = {
["session.profile"] = "a2dp-sink",
},
}
При проблемах с автоподключением после сна проверьте настройки bluez5.auto-connect в свойствах устройства через pw-dump и при необходимости задайте явно:
apply_properties = {
["bluez5.auto-connect"] = "[ a2dp-sink hfp ]",
}
Настройка приоритетов устройств и автоматического переключения
По умолчанию WirePlumber выбирает приёмник по приоритету: выше приоритет у устройств с priority.session и priority.driver. Посмотреть текущие значения:
pw-metadata -n default 0
Ключи default.configured.audio.sink и default.audio.sink хранят настроенное и текущее устройство. Изменить приоритет навсегда:
pw-metadata -n default 0 default.configured.audio.sink '{ "name": "bluez_output.XX_XX_XX_XX_XX_XX.a2dp-sink" }'
Для автоматического переключения на недавно подключённое устройство загрузите модуль module-switch-on-connect в pipewire-pulse.conf:
pulse.cmd = [
{ cmd = "load-module" args = "module-switch-on-connect" flags = [ ] }
]
Или через context.exec в pipewire.conf:
context.exec = [
{ path = "pactl" args = "load-module module-switch-on-connect" }
]
Теперь при подключении новых наушников звук автоматически переключится на них, а при отключении - вернётся на предыдущий приёмник. В GNOME и KDE это поведение также настраивается в системных настройках звука - переключатель "Автоматически переключаться на новые устройства".