Jack часто используют в связке, например, с Ardour, при этом хотелось бы обойти поставляемый по умолчанию во многие дистрибутивы сервер PulseAudio, чтобы избежать ненужной траты процессорных мощностей.

Два года назад я также столкнулся с некорректной совместной работой двух звуковых серверов (что приводило к периодическим «вылетам» звука) и решил раз и навсегда избавиться от PulseAudio в пользу чистого Jack.

Так как у меня дома два маломощных компьютера Raspberry Pi, я разделил задачи на две части: на одном компьютере я смотрю видео, записываю звук, слушаю плеер, а на втором компьютере, рядом с акустической системой, стоит полноценный аудио сервер, занятый только выводом потока на ЦАП, звук «передается» по сети.

В Интернете, конечно, много готовых решений «звуковых серверов» и я остановился на следующем: залить на карту памяти образ Volumio, но чуть-чуть допилить его для соединения по jackd.

Volumio не поддерживает jackd2 из коробки, поэтому пришлось посмотреть, что же именно установлено на Volumio, разархивировать файловую систему Volumio в Linux с помощью утилиты

$ unsquashfs volumio_current.sqsh

Итак, Volumio использует старую версию Debian Jessie с некоторыми итальянскими модификациями. Плохо то, что старая версия Debian 8 содержит ошибку пакета dbus, создающую проблему с jackd2.

Volumio не использует X11, поэтому jackd2 не запустится без небольших танцев с бубном. Кроме всего прочего, в Volumio нет пакета jackd2.

Однако все эти проблемы легко решаются.

Пакет jackd2 можно получить на сервере Debian, он называется deb.jackd2 armhf Джесси, установка стандартная, пакет ставится оверлеем. Хорошая новость - у Volumio уже есть все пакеты для работы с jackd2! Никаких дополнительных пакетов устанавливать не надо.

Так как мы используем старый jackd2 с ошибкой "dbus", ее потребуется «исправить». Можно исправить программным патчем, а затем скомпилировать, но проще сделать дополнительную настройку в скрипте. Поскольку я собирался запускать звуковой сервер удаленно по ssh, то я сразу написал скрипт start-jackd.sh со следующими командами.

#!/bin/bash
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket
# Этой командой  мы исправляем ошибку dbus
driver="alsa"
port_max="4"
priority="95"
# Определяем приоритет, чтобы сервер сильно нагружал процессор
device="hw:0,0"
nperiods="3"
# Рекомендуемое значение для внешних USB карт
outchannels="2"
# Количество каналов воспроизведения
period="1024"
# По умолчанию  1024
rate="96000"
# Частота дискретизации по умолчанию 48000, я увеличил ее
inchannels="2"
#  Каналы захвата, например, для микрофонов
jackd -R -P $priority -d $driver  -P -o $outchannels -i $inchannels -s -n $nperiods -p $period -r $rate -d $device  &
# Запускаем сервер, затем запускаем сетевой менеджер
jack_load netmanager -i -c 
# Это сетевой менеджер

exit 0

Конечно, файл нужно сделать исполняемым (chmod + x start-jackd.sh) и скопировать на компьютер Volumio.

Итак, сервер настроен, причем Volumio, если использовать две звуковые карты (как у меня) будет самостоятельно выбирать ту или иную карту. Теперь «звуковой сервер» jackd можно запускать автоматически из .profile (иным путем) или с помощью команды ssh. Чтобы было удобно управлять Volumio, лучше поставить утилиту sshpass.

Затем на клиентском компьютере необходимо настроить вывод jackd2. Здесь все еще проще. Сначала устанавливаем пакет jackd2 с помощью стандартной команды apt.

Смотрим локальную сеть. Подразумевается, что сервер Volumio в локальной сети 192.168.88.**.

$ nmap -sn 192.168.88.0/24

На будущее лучше настроить постоянный IP, я настроил с привязкой к MAC адресу в роутере.

Настраиваем клиентскую часть jackd2.

Примечание. Если вы перфекционист, то лучше сразу обратиться к передаче по сети с помощью Zita-njbridge. Но я решил ограничиться настройками для 24-битной звуковой карты с частотой дискретизации 96000. (Моя старенькая звуковая карта не поддерживает более мощные конфигурации.)

Для удобства создаем скрипт, запускающий сервер на стороне клиента (если нет желания запускать сервер автоматически при загрузке). Скрипт назовем, например, remote_start.sh

#!/bin/bash

IP="192.168.88.249"
# Допустим, это адрес сервера Volumio
sshpass -f <(printf '%s\n' volumio)  ssh volumio@"$IP" 'if ps -A | grep "jackd"; then  echo " ";  fi;' > ~log
sleep 1
# Входим с помощью программы sshpass, чтобы не вводить пароль 
# Запускаем сервер, создаем лог

sshpass -f <(printf '%s\n' volumio) ssh volumio@"$IP" nohup ./start-jackd.sh & 
# Запускаем сервер

# sshpass -f <(printf '%s\n' volumio)  ssh volumio@"$IP" 'pkill jackd'
# Так можно "убить" сервер

exit 0

Как написано выше, я не подключаю звуковую карту к компьютеру-клиенту, поэтому вместо драйверов звуковой карты я установил «виртуальную звуковую карту».

Если вы также хотите выводить звук из других программ (например, из браузера Chromium) на сервер Volumio, то лучше всего тоже подгрузить драйвер. Это специальный модуль ядра, имитирующий звуковую карту.

Процесс настройки минималистский, так как Raspberry Pi поддерживает модуль snd-aloop (ссылка выше).

Единственное, что потребуется сделать — написать файл .asoundrc с поддержкой нужного битрейта. Так как на сервере Jack у нас уже определена частота дискретизации 96000, то .asoundrc следует синхронизировать (зачем ненужная передискретизация?).

Вот мой файл .asoundrc

# hardware 0,0 :  playback
pcm.loophw00 {
  type hw
  card Loopback
  device 0
  subdevice 0
  format S32_LE
  rate 96000
}

# playback PCM: loopback subdevice 0,0

pcm.amix {
  type dmix
  ipc_key 219345
  slave {
    pcm loophw00
    period_size 4096
    periods 2
  }
}

# Софтверный регулятор громкости
pcm.asoftvol {
  type softvol
  slave.pcm "amix"
  control { name PCM }
  min_dB -51.0
  max_dB   0.0
}

#  jack alsa_in
pcm.cloop {
  type hw
  card Loopback
  device 1
  subdevice 0
  format S32_LE
#  rate 48000
}
#  alsa_out
pcm.ploop {
  type hw
  card Loopback
  device 1
  subdevice 1
  format S32_LE
  rate 48000
}
# duplex device
pcm.aduplex {
  type asym
  playback.pcm "asoftvol"
  capture.pcm "loophw01"
}
# default device
pcm.!default {
  type plug
  slave.pcm aduplex
  hint {
       show on
       description "Duplex Loopback"
  }
}

Напишем скрипт, запускающий Jack на стороне клиента. Можно добавить какие-то изюминки, например, встроить поддержку процессорной фишки из «рецепта звука BAMF»

Скрипт назовем jack_start.sh

#!/bin/bash

amixer -q sset PCM 10%
# При запуске звук будет тихим, чтобы случайно не разбудить соседей

IP="192.168.88.249"

	if ps -A | grep "jackd"; then 
    echo -e "<<< A server is already running: jackd >>>";
    echo -e " <<< kill jackd... >>>";
    pkill jackd 
    sleep 1;
	fi
# "Убивает jackd, если он запущен, помогает перезагрузить звук

# Настройки jackd
# --input_ports	-С число входных каналов (захват)
# --output_ports -Р число выходных каналов (воспроизведение)
# --midi_in_ports -i число входных MIDI-каналов
# --midi_out_ports -о число выходных MIDI-каналов

    multicast_ip="225.3.19.154"
    udp_net_port="19000"
    mtu="1500"
    input_ports="0"
    output_ports="2"
    midi_in_ports="0"
    midi_out_ports="0"
    client_name="hostname"
    transport_sync="1"
    latency="5"
# Это настройки по умолчанию

    taskset 0x4  jackd -S -R  -d net -a $multicast_ip -p $udp_net_port -M $mtu -C $input_ports -P $output_ports -i  $midi_in_ports -o $midi_out_ports -l $latency  & 
# Запустим jackd на одном процессоре =)
    sleep 1

    sshpass -f <(printf '%s\n' volumio) ssh volumio@"$IP" jack_lsp
# Посмотрим соединения на стороне сервера
    sleep 1

# Если уже запущены alsa_in или alsa_out, то процессы уничтожаются
	if ps -A | grep "alsa_in"; then 
    echo -en "kill alsa_in...";
    pkill alsa_in
	fi
	if ps -A | grep "alsa_out"; then 
    echo -en "kill alsa_out...";
    pkill alsa_out
	fi

# Опции для cloop, воспроизведение.
# -j
    jack_client_name="cloop"  # (имя клиента jack)
# -d   
    alsa_device="cloop" # (устройcтво)
# -c   
    channels="2" # (количество каналов)
# -r  
    sample_rate="96000" # (выборка, программа пересчитывает при необходимости
# -p   
    period_size="1024" 
# Если частота дискретизация высокая, могут быть помехи,  опция поможет
# исправить их
# -n   
    num_period="6" # периоды, см. period_size
# -q    
    quality="0"  # "Качество" ресемплера от 0 до 4, ресемлер отключен
# -m  
    max_diff="1024" # значение, когда происходит  xrun
# -t   
    target_delay="2048" 
# задержка alsa_in, такая же как для max_diff. Но  настройка на основе -p и -n  обычно достаточна
# -s  
    smooth_array_size="2048" # параметр управляет размером массива сглаживания задержки 

taskset 0x3 /usr/bin/alsa_in -j $jack_client_name -d $alsa_device  -c $channels -n $num_period -p $period_size  -m $max_diff -s $smooth_array_size -t $target_delay -r $sample_rate -q $quality  2>&1 1> /dev/null &
# Запускаем на отдельном процессоре
sleep 1

    jack_connect cloop:capture_1 system:playback_1
    jack_connect cloop:capture_2 system:playback_2
# устанавливаем соединение

# /usr/bin/alsa_out -j ploop -dploop -r 44100 -q 1 2>&1 1> /dev/null &
# jack_connect system:capture_3 ploop:playback_1
# jack_connect system:capture_3 ploop:playback_2
# Если используется захват каналов для работы с микрофонами

# Проверяем работу 

	if ps -A | grep "jackd"; then 
    echo -en " jackd reading..."
    PID=`pgrep "jackd"`
    echo -en " <<<<<<< $PID >>>>>>>"
	fi

	if ps -A | grep "alsa_in"; then 
    echo -en " alsa_in reading..."
    PID=`pgrep "alsa_in"`
    echo -en " <<<<<<< $PID >>>>>>>"
	fi

exit 0

Теперь вы можете проигрывать музыку на компьютере Raspberry и передавать поток по сети на компьютер с Volumio. При этом будет работать системный регулятор громкости, что позволит управлять громкостью из трея.

Причем у нас уже написаны скрипты для автоматизации работы сервера. Я предпочитаю запускать их из файла .profile

Чтобы запустить сервер на стороне Volumio, вам потребуется добавить команду remote_start.sh Чтобы подключить клиента jack, надо вызвать скрипт jack_start.sh

Совместная работа jack с виртуальной картой очень стабильная и почти никогда не «зависает». Однако возможны неприятные пропадания звука, особенно если процессоры сильно нагружены, в этом случае можно повторно вызвать скрипт jack_start.sh, что перезагрузит клиентскую часть.

Спасибо за внимание, надеюсь, моя небольшая заметка кому-то поможет.

Комментарии (2)


  1. 13werwolf13
    15.03.2022 09:48

    а как же модный piperware?


    1. renice Автор
      15.03.2022 09:51

      Я его не тестировал, но собираюсь когда-нибудь посмотреть в эту сторону. Думаю, там тоже есть какие-то интересные идеи, которыми можно воспользоваться. Потому что джек, к сожалению, не развивается как должно. Хотя более-менее стабильно работает