Делаем медиаматрицу на коленке

от автора

Зачастую возникает необходимость принять аудиосигнал с множества несвязанных устройств и выдать полученный сигнал на множество несвязанных акустических систем. Многие делают это через медиаматрицы BiAMP, Kramer в связке с управлением через Kramer,Palantir и т.д., но это оборудование стоит денег, а деньги есть не всегда.

Осмелюсь описать бюджетный вариант, который в базовом функционале не уступает вышеописанным продуктам. А с точки зрения управления может быть более гибок.
В проекте используется 15 медиасерверов(Windows 7) с каждого из которых идёт свой видеоряд отображаемый на плазмах и проекторах, а также аудиопоток сопровождающий видеоряд. Также имеется 3 акустические системы на которые аудиопоток теоретически можно вывести.


Немного о структуре.
Видеоряд транслируется из серверной комнаты через конверторы DVI и VGA сигналов на оборудование вынесенное от серверной на расстояние до 50 метров. Использование встроенных или выносных динамиков для трансляции аудиосигнала привело бы в какофонии и невозможности восприятия отображаемого контента. Для воспроизведения звука было решено разделить 15 медиасерверов на 3 группы и коммутировать аудиосигнал на 3 различных акустических системы территориально приближенных к плазмам и проекторам.

Так как переключением звука нужно управлять удалённо, значит нужно его где-то скоммутировать. Физическая коммутация вещь старая и надёжная, но мы живём в век цифровых технологий. Поэтому для коммутации звука мы будем использовать цифру, а чтобы получить цифровой поток, его нужно откуда-то взять.
Устанавливаем на компьютер драйвера виртуального аудио кабеля.
Данные драйвера представляют собой виртуальную звуковую карту в которую можно отправлять весь звук системы и снимать из неё звуковой поток в цифровом виде при помощи программ.
В нашем случае используется обычный ffmpeg.
Для получения списка аудиоустройств необходимо запустить ffmpeg со следующими ключами:

  C:\Progs\ffmpeg\bin>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:\Progs\ffmpeg\bin>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

ссылка на оригинал статьи http://habrahabr.ru/post/222905/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *