JACK и несколько звуковых карт
JACK — единственная звуковая система для UNIX систем, позволяющая коммутировать звуковые потоки на уровне приложений (самая распространённая на сегодняшний день система — Pulse Audio — умеет коммутировать звук только на уровне устройств, то есть можно перекинуть MP3-проигрыватель со внутренней звуковой карты на внешнюю, но нельзя перекинуть в Skype). Поэтому JACK является основой рабочей станции любого интернет-радиовещателя, использующего Linux. #
Основная проблема JACK в том, что он умеет работать только с одной звуковой картой. Для вещания обычно используется внешнее звуковое устройство, подключаемое по USB, или USB микрофон, потому что встроенные в ноутбуки или другие компьютеры звуковые карты, какими крутыми бы они ни были, дают отвратительный звук с сильными шумами. Для переключения между внешним и внутренним устройствами нужно перезапускать JACK, а в случае с использованием внешнего USB микрофона вообще не ясно: проигрывать в него нельзя и проигрывать, получается, не во что. #
Уточнение: при постоянном использовании JACK со внешним USB микрофоном можно
использовать ключи -P и -C командной строки; использовать разные карты для
ввода и вывода звука JACK умеет. Однако если нужно отключать микрофон на ходу,
то без описанной здесь схемы не обойтись. #
Пара слов об архитектуре JACK #
Здесь надо сделать отступление и вкратце объяснить, как работает коммуникация в JACK. JACK оперирует портами. У звуковой карты обычно есть два выходных порта: левый и правый, называются они "system:playback_1" и "system:playback_2", и есть два входных порта: "system:capture_1" и "system:capture_2" (это микрофон или линейный вход, я не знаю как они делятся между собой). #
Включение внешней звуковой карты в JACK #
Для того, чтобы JACK увидел ещё одну звуковую карту, используются утилиты
alsa_in и alsa_out, которые создают новые порты и тупо ретранслируют туда
вход или выход указанной звуковой карты. (Этот подход оказался для меня
несколько неожиданным: я долго пытался найти способ «скрестить» две звуковые
карты средствами ALSA — и нашёл, но он оказался слишком сложным для моего
понимания.) #
Итак, чтобы подружить JACK и внешнюю звуковую карту, достаточно запустить
alsa_out, указав её имя: #
$ alsa_out -d hw:USB
Чтобы узнать имя звуковой карты, используется утилита aplay: #
$ aplay -L
front:CARD=Intel,DEV=0
HDA Intel, ALC269 Analog
Front speakers
...
front:CARD=USB,DEV=0
E-MU 0202
Front speakers
(В этом примере видны две карты: "Intel" и "USB", эти названия и следует
указывать в качестве значений параметра -d.) #
Теперь в списке портов видны два новых: #
$ jack_lsp
system:playback_1
system:playback_2
...
alsa_out:playback_1
alsa_out:playback_2
В эти порты можно играть звук, и он пойдёт на внешнюю звуковую карту (причём можно в обе сразу, хотя это мне никогда не бывает нужно). Можно на ходу отправить какую-нибудь программу играть звук во внешнюю карту: #
$ jack_connect "MPlayer .*:out_0" "alsa_out:playback_1"
$ jack_connect "MPlayer .*:out_1" "alsa_out:playback_2"
Если теперь убить процесс alsa_out или отключить внешнюю звуковую карту — она
перестанет издавать звук, приложение alsa_out завершится, но больше ничего
плохого не произойдёт: программы, работающие со звуком, не зависнут и JACK
перезапускать нужды не будет. #
Автоматическая коммутация #
JACK не умеет сам определять что с чем коммутировать (философия UNIX: JACK
не этим занимается). Для автоматизации этого процесса используется утилита
jack.plumbing, которая обычно висит в фоне и коммутирует потоки в соответствии
с правилами из специального текстового файла, который называется
~/.jack.plumbing. Автоматическая отправка MPlayer во внешнюю и внутреннюю
звуковые карты выглядит так: #
# внутренняя карта
(connect "MPlayer .*:out_0" "system:playback_1")
(connect "MPlayer .*:out_1" "system:playback_1")
# внешняя карта
(connect "MPlayer .*:out_0" "alsa_out:playback_1")
(connect "MPlayer .*:out_1" "alsa_out:playback_1")
Теперь при подключении внешней звуковой карты MPlayer сразу будет начинать
играть через неё, в дополнение ко внутренней. (Можно использовать во втором
блоке директиву connect-exclusive, тогда при подключении ко внешней карте он
будет отключен от внутренней, однако на практике при проведении прямых эфиров
эксклюзивное подключение бесполезно, т.к. MPlayer должен играть и в звуковую
карту, и в Skype, и в эфир радиостанции — это как минимум три неэксклюзивных
направления; на практике проще временно заглушить внутреннюю карту с помощью
утилит alsamixer или amixer.) #
Примерный алгоритм работы #
Для начала прямого эфира у меня есть скрипт, который выполняет следующие действия: #
- Глушит внутреннюю карту утититой
amixer. - Запускает в фоновом режиме утилиты
jack.plumbing,alsa_outиalsa_in, если они не запущены. - Запускает в фоновом режиме
darkice(вещание в радиостанцию). - Запускает утилиту
jack_meterдля наблюдения за уровнем записи.
Следить за развитием событий можно через RSS ленту или почтовую рассылку.