Зачастую возникает необходимость принять аудиосигнал с множества несвязанных устройств и выдать полученный сигнал на множество несвязанных акустических систем. Многие делают это через медиаматрицы BiAMP, Kramer в связке с управлением через Kramer,Palantir и т.д., но это оборудование стоит денег, а деньги есть не всегда.
Осмелюсь описать бюджетный вариант, который в базовом функционале не уступает вышеописанным продуктам. А с точки зрения управления может быть более гибок.
В проекте используется 15 медиасерверов(Windows 7) с каждого из которых идёт свой видеоряд отображаемый на плазмах и проекторах, а также аудиопоток сопровождающий видеоряд. Также имеется 3 акустические системы на которые аудиопоток теоретически можно вывести.
Немного о структуре.
Видеоряд транслируется из серверной комнаты через конверторы DVI и VGA сигналов на оборудование вынесенное от серверной на расстояние до 50 метров. Использование встроенных или выносных динамиков для трансляции аудиосигнала привело бы в какофонии и невозможности восприятия отображаемого контента. Для воспроизведения звука было решено разделить 15 медиасерверов на 3 группы и коммутировать аудиосигнал на 3 различных акустических системы территориально приближенных к плазмам и проекторам.
Так как переключением звука нужно управлять удалённо, значит нужно его где-то скоммутировать. Физическая коммутация вещь старая и надёжная, но мы живём в век цифровых технологий. Поэтому для коммутации звука мы будем использовать цифру, а чтобы получить цифровой поток, его нужно откуда-то взять.
Устанавливаем на компьютер драйвера виртуального аудио кабеля.
Данные драйвера представляют собой виртуальную звуковую карту в которую можно отправлять весь звук системы и снимать из неё звуковой поток в цифровом виде при помощи программ.
В нашем случае используется обычный ffmpeg.
Для получения списка аудиоустройств необходимо запустить ffmpeg со следующими ключами:
C:Progsffmpegbin>ffmpeg -list_devices true -f dshow -i dummy [dshow @ 00000000020a77e0] DirectShow video devices [dshow @ 00000000020a77e0] "Logitech HD Webcam C310" [dshow @ 00000000020a77e0] DirectShow audio devices [dshow @ 00000000020a77e0] "Микрофон (HD Webcam C310)" [dshow @ 00000000020a77e0] "CABLE Output (VB-Audio Virtual "
Устройством с которого мы будем снимать аудиопоток будет «CABLE Output (VB-Audio Virtual ».
В качестве устройства в которое будет выводиться весь звук системы будет «CABLE Input (Virtual Audio Cable)».
Запускаем ffmpeg и транслируем данные в сеть.
C:Progsffmpegbin>ffmpeg -re -f dshow -i audio="CABLE Output (VB-Audio Virtual " -f mp3 udp://239.1.1.1:5001 ffmpeg version N-49610-gc2dd5a1 Copyright (c) 2000-2013 the FFmpeg developers built on Feb 5 2013 13:26:02 with gcc 4.7.2 (GCC) libavutil 52. 17.101 / 52. 17.101 libavcodec 54. 91.100 / 54. 91.100 libavformat 54. 61.104 / 54. 61.104 libavdevice 54. 3.103 / 54. 3.103 libavfilter 3. 35.101 / 3. 35.101 libswscale 2. 2.100 / 2. 2.100 libswresample 0. 17.102 / 0. 17.102 libpostproc 52. 2.100 / 52. 2.100 [dshow @ 00000000024de080] Estimating duration from bitrate, this may be inaccurate Guessed Channel Layout for Input Stream #0.0 : stereo Input #0, dshow, from 'audio=CABLE Output (VB-Audio Virtual ': Duration: N/A, start: 270550.167000, bitrate: 1411 kb/s Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s Output #0, mp3, to 'udp://239.1.1.1:5001': Metadata: TSSE : Lavf54.61.104 Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p Stream mapping: Stream #0:0 -> #0:0 (pcm_s16le -> libmp3lame) Press [q] to stop, [?] for help size= 100kB time=00:00:06.37 bitrate= 128.5kbits/s
В любом месте сети Вы сможете слушать данный поток любым плеером(ffplay, vlc и т.д.). При желании можно менять кодек и битрейт.
Базовая настройка сделана, звук получили, драйвера растиражировали на 15 медиасерверов, получили 15 разных потоков, а теперь возникает вопрос «как же это слушать и коммутировать».
С точки зрения экономии железа и ресурсов можно воспользоваться единственной машиной с некоторым количеством аудиокарт выводящих звук на акустику. Сейчас в достаточной мере на рынке присутствуют различные малогабаритные USB аудиокарты. С точки зрения удобства использования дешевые карты аля CMEDIA не выгодны, потому не имеют внутри серийных номеров и определить какая карта после перезагрузки на какой канал стала работать невозможно. Я использовал карты «Creative SB Play!» которые дают довольно хороший звук и имеют возможность идентификации их в системе.
Т.к. при подключении USB audio картам присваиваются динамические номера, для devd был написан набор правил:
attach 50 { match "device-name" "uaudio[0-9]+"; match "sernum" "[0-9A-Za-z]+"; match "mode" "host"; action "logger USB Audio S/N:$sernum is attached"; action "ln -fs /dev/`head -n 1 /tmp/$device-name.dsp` /dev/$device-name.dsp"; action "ln -fs /dev/$device-name.dsp /dev/uaudio.serial.$sernum"; action "rm /tmp/$device-name.dsp"; match "device-name" "uaudio[0-9]+"; match "hubaddr" "[0-9]+"; match "port" "[0-9]+"; match "devaddr" "[0-9]+"; action "echo $device-name at ugen.$port.$devaddr"; action "ln -fs /dev/$device-name.dsp /dev/uaudio.ugen.$port.$devaddr"; }; attach 50 { match "device-name" "uaudio[0-9]+"; match "sernum" "$"; match "mode" "host"; action "logger USB Audio without serial number is attached"; action "ln -fs /dev/`head -n 1 /tmp/$device-name.dsp` /dev/$device-name.dsp"; action "rm /tmp/$device-name.dsp"; match "device-name" "uaudio[0-9]+"; match "hubaddr" "[0-9]+"; match "port" "[0-9]+"; match "devaddr" "[0-9]+"; action "echo $device-name at ugen.$port.$devaddr"; action "ln -fs /dev/$device-name.dsp /dev/uaudio.ugen.$port.$devaddr"; }; attach 40 { match "device-name" "pcm[0-9]+"; match "bus" "uaudio[0-9]+"; action "logger Found $device-name at $bus. Saving."; action "echo -n $device-name | sed -E 's/pcm/dsp/' >> /tmp/$bus.dsp"; }; detach 40 { match "device-name" "uaudio[0-9]+"; match "bus" "uhub[0-9]+"; action "logger Dropping dsp symlink for $device-name"; action "find /dev/ -type l -ls | awk '$$NF ~ /$device-name./ {print $(NF-2)}' | xargs rm"; action "rm -f /dev/$device-name.dsp"; }; notify 50 { match "type" "DETACH"; match "mode" "host"; match "sernum" "[0-9A-Za-z]+"; action "logger USB Audio S/N:$sernum detached"; };
который формирует симлинки на подключенное оборудование в виде "/dev/uaudio.serial.<SerialNumber>", в итоге список устройств выглядит вот так
lrwxr-xr-x 1 root wheel 16 May 15 09:27 /dev/uaudio.serial.131014000129 -> /dev/uaudio1.dsp lrwxr-xr-x 1 root wheel 16 May 15 09:23 /dev/uaudio.serial.140210000BB2 -> /dev/uaudio0.dsp lrwxr-xr-x 1 root wheel 16 May 15 09:23 /dev/uaudio.ugen.5.6 -> /dev/uaudio0.dsp lrwxr-xr-x 1 root wheel 16 May 15 09:27 /dev/uaudio.ugen.5.7 -> /dev/uaudio1.dsp lrwxr-xr-x 1 root wheel 16 May 15 08:37 /dev/uaudio.ugen.5.8 -> /dev/uaudio2.dsp lrwxr-xr-x 1 root wheel 9 May 15 09:23 /dev/uaudio0.dsp -> /dev/dsp6 lrwxr-xr-x 1 root wheel 9 May 15 09:27 /dev/uaudio1.dsp -> /dev/dsp7 lrwxr-xr-x 1 root wheel 9 May 15 08:37 /dev/uaudio2.dsp -> /dev/dsp8
Что позволяет однозначно идентифицировать карту и акустическую систему которую она обслуживает.
С картами мы разобрались. Теперь очередь за вопроизведением всего этого счастья.
Формируем Playlist.xspf:
<?xml version="1.0" encoding="UTF-8"?> <playlist version="1" xmlns="http://xspf.org/ns/0/" xmlns:vlc="http://www.videolan.org/vlc/playlist/ns/0/"> <title>AudioStreams</title> <trackList> <track> <title>TV 1</title> <location>udp://@239.1.1.1:5001</location> <extension application="http://www.videolan.org/vlc/playlist/0"> <vlc:id>1</vlc:id> <vlc:option>input-repeat=-1</vlc:option> </extension> </track> <track> <title>TV 2</title> <location>udp://@239.1.1.2:5001</location> <extension application="http://www.videolan.org/vlc/playlist/0"> <vlc:id>2</vlc:id> <vlc:option>input-repeat=-1</vlc:option> </extension> </track> <track> <title>TV 3</title> <location>udp://@239.1.1.3:5001</location> <extension application="http://www.videolan.org/vlc/playlist/0"> <vlc:id>3</vlc:id> <vlc:option>input-repeat=-1</vlc:option> </extension> </track> </trackList> </playlist>
Копируем дерево lua vlc в /usr/local/www/vlc_http
Плейлист кладём в /usr/local/www/vlc_http/playlists/Playlist.xspf
теперь запускаем пачку cvlc в следующем конфиге:
vlc -vvv --sout-transcode-venc none --network-caching 50 --sout-mux-caching 50 -Aoss --oss-audio-device=/dev/uaudio.serial.131014000129 -I http --http-src=/usr/local/www/vlc_http --http-host=192.168.5.2 --http-port=8101 --http-password=mypass1 /usr/local/www/vlc_http/playlists/Playlist.xspf vlc -vvv --sout-transcode-venc none --network-caching 50 --sout-mux-caching 50 -Aoss --oss-audio-device=/dev/uaudio.serial.140210000BB2 -I http --http-src=/usr/local/www/vlc_http --http-host=192.168.5.2 --http-port=8102 --http-password=mypass1 /usr/local/www/vlc_http/playlists/Playlist.xspf
Далее дело за малым. Взять примеры из http управлялки vlc и сделать свои страницы управления. Благо там сплошной jquery и javascript.
В основном дереве веб сервера формируем страницу где в iframe интегрируем управлялки каждым из поточных проигрывателей и открываем это дело через телефон или планшет. Вся остальная логика управления пишется на html и не представляет большой сложности.
Т.к. мы не завязаны на источники звука, это даёт огромную гибкость в управлении звуковыми потоками. Можно на всю акустику вывести один и тот же поток с любого медиасервера, можно поменять потоки местами и т.д.
Теперь вернёмся к USB аудиокартам, у нас остались микрофонные входы на которые можно подать звук с физических устройств типа проигрывателей, телефонов, микрофонов и т.д. Для подключения к микрофонному входу линейных выходов от проигрывателей необходимо собрать простейший делитель напряжения. Статья на хабре опять же имеется. Входящий сигнал с микрофонного входа так же заводится в поток и броадкастится либо на localhost, либо в сеть.
Вот как-то так. Будут вопросы — пишите.
© Aborche 2014
Автор: aborche