Например, к локальной машине подключены Bluetooth наушники, и на них нужно вывести звук с удаленного сервера. На сервере и на локальной машине — Debian. Давайте настроим, чтобы локальные Bluetooth наушники отображались на удаленном сервера как еще один аудиовыход. И выведем на этот аудиовыход звук. Погнали!
Настройка локальной машины
Звук через PipeWire вместо PulseAudio
Проверяем, что используем звук через более современный PipeWire, а не через устаревший звуковой сервер PulseAudio:
pactl info
Если строка вида:
Server Name: PulseAudio (on PipeWire 0.3.65)
то это PipeWire.
Если строка вида:
Server Name: pulseaudio
то это PulseAudio.
Если PulseAudio, то устанавливаем PipeWire. PipeWire объединяет возможности PulseAudio и JACK, обладает лучшей поддержкой Bluetooth, более низкой задержкой и лучшей совместимостью с современными системами.
Устанавливаем:
apt install pipewire-audio-client-libraries pipewire-pulse wireplumber libspa-0.2-bluetooth
Далее проще всего перезагрузиться, и после перезагрузки будет уже работать PipeWire вместо PulseAudio.
systemctl --user status pipewire pipewire-pulse
«Проброс» аудиоустройства через сеть
Чтобы Bluetooth наушники, подключенные к локальной машине, были видны на удаленном сервере как аудиоутройство, нужно «пробросить» аудиоустройство через сеть.
Создаем конфигурационный файл ~/.config/pipewire/pipewire-pulse.conf.d/tcp-server.conf:
mkdir -p ~/.config/pipewire/pipewire-pulse.conf.d
touch ~/.config/pipewire/pipewire-pulse.conf.d/tcp-server.conf
В созданный конфигурационный файл добавляем следующий текст:
pulse.cmd = [
{ cmd = "load-module" args = "module-native-protocol-tcp auth-ip-acl=127.0.0.1,192.168.1.0/24 auth-anonymous=1" flags = []}
]
Это команда разрешает входящие сетевые подключения к звуковому серверу по TCP (порт 4713).
module-native-protocol-tcp
— это модуль, разрешающий сетевые подключения.
auth-ip-acl=127.0.0.1,192.168.1.0/24
— это список IP адресов и подсетей, из которых разрешено подключаться. У меня локальная машина и удаленный сервер находятся в одной подсети 192.168.1.0/24.
auth-anonymous=1
— разрешает анонимные подключения. Это безопасно только в локальной сети. В случае работы через Интернет необходимо настраивать авторизацию.
Перезагружаем PipeWire:
systemctl --user restart pipewire pipewire-pulse
Проверяем, что теперь принимаются подключения по TCP на порт 4713:
ss -tulnp | grep pipewire-pulse

Узнаем sink подключенных Bluetooth наушников, которые «пробрасываем» через сеть:
pactl list short sinks

У меня это bluez_output.28_A6_54_CF_62_79.1.
Итак, на локальной машине звуковой сервер, принимающий сетевые подключения по TCP на порт 4713. А для подключения именно к Bluetooth наушникам мы узнали их sink.
Далее на удаленном сервере мы настроим подключение по TCP к этому звуковому серверу и к именно Bluetooth наушникам. Так на удаленном сервере эти Bluetooth наушники отобразятся как локальное аудиоустройство, аудиовыход.
Настройка удаленного сервера
Аналогично, как на локальной машине, проверяем, что звук через PipeWire.
Туннельное подключение
Создаем конфигурационный файл ~/.config/pipewire/pipewire-pulse.conf.d/tcp-client.conf:
mkdir -p ~/.config/pipewire/pipewire-pulse.conf.d
touch ~/.config/pipewire/pipewire-pulse.conf.d/tcp-client.conf
В созданный конфигурационный файл добавляем следующий текст:
pulse.cmd = [
{cmd = "load-module" args = "module-tunnel-sink server=192.168.1.50 sink=bluez_output.28_A6_54_CF_62_79.1" flags = []}
]
Эта команда создает локальный sink (аудиоустройство, аудиовыход) через туннельное подключение к звуковому серверу по TCP.
module-tunnel-sink
— модуль, создающий туннельное подключение.
server=192.168.1.50
— IP адрес звукового сервера, принимающего подключения по TCP.
sink=bluez_output.28_A6_54_CF_62_79.1
— это sink Bluetooth наушников.
Перезагружаем PipeWire:
systemctl --user restart pipewire pipewire-pulse
Смотрим аудиовыходы:
pactl list short sinks

Созданный нами аудиовыход с наименованием, начинающимся с tunnel-sink. У меня: tunnel-sink.192.168.1.50.
Давайте проверять работоспособность. Созданный аудиовыход делаем аудиовыходом по умолчанию, например, так:

И проиграем какой-нибудь звуковой файл:
paplay /usr/share/sounds/alsa/Side_Left.wav
В Bluetooth наушниках локальной машины должны услышать звучание.
Автоматическое восстановление туннельного подключения
Для автоматического восстановления разорвавшегося туннельного подключения к звуковому серверу напишем bash скрипт и добавим его в планировщик задач cron.
Создаем bash скрипт /home/user/cron_tunnel_reconnect.sh:
touch /home/user/cron_tunnel_reconnect.sh
В него добавляем следующий текст:
#!/bin/bash
AUDIO_SERVER_IP="192.168.1.50"
BLUETOOTH_SINK="bluez_output.28_A6_54_CF_62_79.1"
export DISPLAY=:0
uid=$(id -u)
export XDG_RUNTIME_DIR=/run/user/$uid
export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus
if ! pactl list short modules | grep -q tunnel-sink; then
pactl load-module module-tunnel-sink server="$AUDIO_SERVER_IP" sink="$BLUETOOTH_SINK"
fi
Скрипт экспортирует переменные окружения: DISPLAY, XDG_RUNTIME_DIR, DBUS_SESSION_BUS_ADDRESS, чтобы привязаться к конкретной графической пользовательской сессии. И уже в конкретной графической пользовательской сессии проверяет, загружен ли модуль tunnel-sink. Если не загружен, то загружает и устанавливает туннельное подключение к звуковому серверу, к Bluetooth наушникам.
Делаем скрипт /home/user/cron_tunnel_reconnect.sh исполняемым:
chmod +x /home/user/cron_tunnel_reconnect.sh
Открываем crontab на редактирование:
crontab -e
И добавляем строку:
*/1 * * * * /home/user/cron_tunnel_reconnect.sh
Готово! Скрипт будет вызываться на исполнение каждую минуту.
Вывод
«Проброс» аудиоустройства через сеть в Debian оказался несложной задачей. Все вопросы жду в комментариях под статьей.
Комментарии