Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 124, АПРЕЛЬ 2009 г.

Звездное попурри. Фокусничаем с IP-PBX Asterisk

Sergey Jaremchuk feat. Andrey Matveev




Сервер телефонии Asterisk обладает поистине колоссальными возможностями обеспечения переговоров по IP-сетям, заменяя обычную офисную АТС при большей функциональности и меньшей цене. Но Asterisk - это еще и необычайно гибкая система, предоставляющая широкое поле для творчества. Немного фантазии, и можно реализовать практически любую функцию, не предусмотренную разработчиками.

Система видеонаблюдения с оповещением

Одна из часто востребованных возможностей Asterisk – это запуск программ и скриптов из экстеншена (при наборе определенного номера) или вызов абонента из другого (внешнего) приложения. Для удобства админа реализовано несколько путей, позволяющих инициировать исходящий звонок на лету:

  1. Call-файл – обычный текстовый файл, имеющий определенную структуру.
  2. API – подключившись к порту управления (по умолчанию 5038) при помощи telnet, можно задать все необходимые команды.
  3. CLI (command line interface) команда – управление сервером в консоли (вызывается при помощи «asterisk -r»).
  4. Использование настроек переадресации на другой номер – FollowMe.

Наиболее удобен в работе вариант с использованием файла с расширением .call. Достаточно такому файлу появиться в каталоге /var/spool/asterisk/outgoing (настраивается в asterisk.conf при помощи astspooldir), как сервер выполнит заданные в нем команды. Call-файл можно сгенерировать налету и затем просто скопировать в данный каталог. Asterisk проверяет время создания файла, если оно «в будущем», то команда выполнится, когда системное время и время модификации совпадут. Это также можно использовать для отложенного запуска команд в Call-файле. Единственное условие - активация параметра «autoload=yes» (так сделано по умолчанию) в modules.conf. В файле используются инструкции из extensions.conf, но у него несколько другая структура и количество возможных команд в нем ограничено.

Чтобы было понятнее, о чем речь, рассмотрим совместную работу Asterisk и системы видеонаблюдения Motion (www.lavrsen.dk/twiki/bin/view/Motion/WebHome), способной выполнять заданную программу или скрипт при обнаружении движения. Такой тандем может понадобиться для контроля над некоторым объектом, скажем, сервером. Роль Asterisk здесь – главная: с его помощью при возникновении события мы будем звонить админу на SIP-телефон (можно на городской или сотовый).
Полностью установку Motion и настройки в /etc/motion/motion.conf рассматривать не будем, за подробностями обращайся к статье «Сумеречный дозор», опубликованной в мартовском номере ][ за 2008 год. Остановимся только на самых важных моментах:

$ sudo nano /etc/motion/motion.conf

# Включаем встроенный веб-сервер, разрешаем к нему удаленный доступ
webcam_port 8000
webcam_motion on
webcam_localhost off
webcam_quality 30
webcam_maxrate 6
control_authentication username:password
# При обнаружении движения запускаем скрипт, который будет поднимать тревогу, вместо директивы on_motion_detected можно использовать on_event_start
on_motion_detected /usr/bin/webcam_event.sh

Смотрим отладочную информацию, запустив Motion с флагом '–n':

$ motion –n
Thread is from /etc/motion/motion.conf

Если все в порядке, стартуем программу в обычном режиме и переходим к написанию скрипта webcam_event.sh:

$ sudo nano /usr/bin/webcam_event.sh

#!/bin/sh
cat << EOF > /tmp/alarm.call
# Устанавливаем параметры канала и CallerID
Channel: SIP/admin
Callerid: 11111111
# Количество повторных попыток вызова в случае неудачи, не включая первую (т.е. в нашем случае при возникновении проблем будет сделано 3 попытки вызова абонента)
MaxRetries: 2
# Время до повторной попытки набора (по умолчанию 300 сек)
RetryTime: 30
# Время ожидания ответа (по умолчанию 45 сек)
WaitTime: 30
# Контекст из extensions.conf и приоритет вызова
Context: alarm
Extension: s
Priority: 1
EOF
# Задаем нужные права для созданного файла и переносим его в нужную папку
chown asterisk:asterisk /tmp/alarm.call
mv /tmp/alarm.call /var/spool/asterisk/outgoing/

Вот практически и все параметры, возможные в Call-файле. Опционально для установки времени можно использовать timestamp:

Set: timestamp=20091023104500

Теперь добавляем описание в extension.conf:

$ sudo nano /etc/asterisk/extension.conf

[alarm]
exten => s,1,Answer()
exten => s,n,Wait(2)
exten => s,n,Playback(activated)
exten => s,n,Wait(1)
exten => s,n,Hangup()

После внесения изменений не забываем перечитать план набора командой «dialplan reload». Теперь, обнаружив движение, Motion запустит выполняться скрипт webcam_event.sh, который создаст /tmp/alarm.call и скопирует его в /var/spool/asterisk/outgoing. После чего Call-файл будет обработан Asterisk, и на номер admin, описанный в sip.conf, поступит звонок с CallerID «11111111». Немного допилив этот скрипт, можно заставить Asterisk выполнять и другие операции, например, отправлять e-mail или SMS. Как ты понимаешь, вместо Motion подойдет любая другая программа, умеющая создавать или копировать файлы при возникновении определенного события.

Усложняя конфигурацию, упрощаем управление

Рассмотрим еще одну возможность выполнения команд в Asterisk, а заодно – немного дополним нашу схему. Например, в рабочее время в использовании Motion особого смысла нет, поэтому его можно смело отключать. Это можно сделать из консоли или при помощи планировщика cron, но удобнее для включения/отключения просто позвонить по определенному номеру. Создадим небольшой скрипт, при помощи которого будем управлять демоном Motion:

$ sudo nano /usr/bin/motion.sh

#!/bin/sh
case $1 in
start)
/usr/bin/motion
;;
stop)
PID=`pidof motion`
kill $PID
killall webcam_event.sh
rm -f /var/spool/asterisk/outgoing/alarm.call
;;
esac

В extension.conf заносим описания номеров, которые будут использованы для запуска скрипта с разными параметрами:

$ sudo nano /etc/asterisk/extension.conf

exten => *001,1,Answer()
exten => *001,n,Playback(activated)
exten => *001,n,System(/usr/bin/motion.sh start)
exten => *001,n,Hangup()
exten => *002,1,Answer()
exten => *002,n,System(/usr/bin/motion.sh stop)
exten => *002,n,Playback(de-activated)
exten => *002,n,Hangup()

Теперь, чтобы запустить Motion, достаточно набрать номер *001, а чтобы остановить – *002.

Будильник на Asterisk

Реализовать будильник в *nix можно далеко не единственным способом (самый простой, наверное: «sleep 20m && mpg123 ~/bell.mp3»), но хочется чего-то красивого и нестандартного. Поиск в интернете по запросу «asterisk wakeup» выдаст несколько решений, написанных с использованием разных языков программирования и немного отличающихся как процессом установки, так и возможностями. Самое популярное из них - PHP скрипт wakeup.php, автором которого стал Анди Высоцки (www.voip-info.org/liberty/view/file/2388). Скачиваем по ссылке tar-архив, распаковываем php-файл в каталог с AGI скриптами (Asterisk Gateway Interface - шлюзовой интерфейс, посредством которого внешние программы могут управлять диалпланом Asterisk) и делаем его исполняемым: «chmod a+x /var/lib/asterisk/agi-bin/wakeup.php» (нужный каталог можно узнать, просмотрев значение переменной astagidir в конфиге asterisk.conf).

Скрипт wakeup.php содержит ряд переменных, которые необходимо подправить с учетом настроек системы:

; Расположение интерпретатора PHP в разных *nix-системах может отличаться
#!/usr/bin/php -q
; Журнал из /tmp лучше убрать
$parm_error_log = '/var/log/asterisk/wakeup.log';
; По умолчанию скрипт создает временные файлы в /tmp, но если этот каталог находится на отдельном разделе, то wakeup.php откажется работать, поэтому:
$parm_temp_dir = '/var/spool/asterisk/tmp';

Принцип запуска скрипта аналогичен примеру с Motion - просто заносим в extensions.conf информацию о новом номере:

exten => *97,1,Answer()
exten => *97,n,AGI(wakeup.php)
exten => *97,n,Hangup()

Теперь достаточно позвонить на номер *97 и по запросу ввести время, когда система должна произвести обратный звонок. Например, чтобы завести будильник на 17:55 (сегодня финал кубка английской лиги :)), набираем «0555», а затем «2» (1 - до полудня, 2 - после полудня).

Если при запуске скрипта возникли проблемы, доустанови пакеты php5-cli и asterisk-sound-extra и используй утилиту fromdos, чтобы привести wakeup.php к Unix-стандартам.

Виртуальный диктофон

Дистрибутивный комплект Asterisk и пакет дополнений asterisk-sounds содержат около 1000 голосовых сообщений на английском языке (голос принадлежит дамочке по имени Allison Smith). В качестве альтернативы можно записать мессаджи на русском/украинском/суахили самостоятельно, но для этого необязательно прибегать к аудиоредактору типа Audacity. Нижеследующее дополнение в диалплан обеспечит возможность звонить на номер *98 и записывать сообщения в папку /tmp под именами myrecordНОМЕР.wav. После завершения записи (осуществляется нажатием #) звуковой файл будет воспроизведен, и соединение разорвется. Примечание: чтобы уровень громкости был постоянным, а «белый» шум, создаваемый системами отопления/охлаждения/кондиционирования, сведен к минимуму, для записи лучше воспользоваться аппаратным VoIP-телефоном.

exten => *98,1,Answer()
exten => *98,n,Wait(2)
exten => *98,n,Record(/tmp/myrecord%d:wav)
exten => *98,n,Wait(1)
exten => *98,n,Playback(${RECORDED_FILE})
exten => *98,n,Wait(1)
exten => *98,n,Hangup()

Не забудь скопировать/перенести полученный файл из временной директории в папку для звуковых файлов Asterisk и наделить его каким-нибудь осмысленным именем, вроде privetstvie.wav. Кстати, голосовые сообщения лучше не конвертировать в gsm/mp3/ogg, чтобы на проц не легла дополнительная нагрузка по преобразованию.

Телефонный справочник

Если в компании используется более трех добавочных номеров, без телефонного справочника не обойтись. Сотрудники начинают путать цифры, забывать номера, нервничать и дергать по пустякам админа. Бумажные варианты справочника и экселевские таблички оставим в прошлом. Приложение Directory(), используя имена, заданные в описаниях голосовых почтовых ящиков, предоставляет телефонный справочник абонентов офисной АТС для набора номеров по имени. В качестве аргументов директивы нужно подставить контекст голосовой почты, из которого считываются имена, и контекст диалплана, в котором вызывается абонент:

exten => *99,1,Directory(default,internal)

Создаем почтовый ящик в файле voicemail.conf:

[default]
401 => 1234,Andrey Matveev,andrushock@real.xakep.ru

На клавиатуре софтофона набираем *99, затем первые три буквы фамилии пользователя, номер которого мы хотим узнать (в данном случае – «mat»). Allison Smith начнет по буквам «зачитывать» из voicemail.conf имя и фамилию найденного абонента: «a-n-d-r-e-y m-a-t-v-e-e-v». Подтверждаем правильность выбора нажатием «1». Виртуальный оператор проговорит добавочный номер 401 (если в диалплане используется конструкция вида «exten => _XXX,1,SayDigits(${EXTEN})») и произведет соединение. Очень удобно!

Который час?

Оказывается, служба точного времени - невероятно популярный сервис: судя по материалу из Википедии, ежедневно по номеру 100 звонят около миллиона москвичей. Может быть, пойдем навстречу МГТС (или твоей городской телефонной станции) и чуточку разгрузим их оборудование за счет создания своих «говорящих часов»? В этом нам поможет приложение SayUnixTime(), проговаривающее указанное время в определенном формате:

exten => *100,1,Answer()
exten => *100,n,SayUnixTime(,,QdhAR)
exten => *100,n,WaitMusicOnHold(10)
exten => *100,n,Goto(*100,1)

Набираем *100, Allison Smith приветливо сообщает о том, что сейчас 1 марта, воскресенье, 14 часов и 50 минут. Затем воспроизводится 10-секундная музыкальная пауза (путь к папке с музоном задается параметром directory в файле musiconhold.conf), и вызов номера повторяется (на тот случай, если мы что-то не расслышали).

Будущее телефонии за видеозвонками

Изначально вопрос о поддержке видеосвязи перед разработчиками не ставился, однако сегодня необходимость в такой функциональности очевидна. Кроме того, вычислительные мощности многократно возросли, трафик подешевел, а пропускная способность каналов позволяет гонять видеопоток хорошего качества. Так или иначе, но поддержка видео в Asterisk 1.4 находится в зачаточном состоянии (плохое согласование кодеков, не распознаются расширенные атрибуты для видеопотоков, не поддерживаются популярные видеоформаты, нет возможности перекодировки и т.д.). Часть перечисленного, вероятно, так никогда и не появится в Asterisk, в том числе, из-за возможных проблем с лицензированием. Например, разработчики не могут использовать библиотеку ffmpeg, хотя сегодня уже доступно приложение app_transcoder (sip.fontventa.com/content/view/30/57), работающее с ffmpeg и имеющее ограниченные функции, связанные с перекодированием. В новой версии 1.6 планировались некоторые подвижки в этом направлении, в частности, полная перестройка поддержки видео в каналах (так называются соединения в Asterisk), но пока дальше идей дело не пошло.

Из всего множества каналов передача видео реализована только в двух - SIP и IAX2. Некоторые популярные реализации (chan_h323, chan_oh323, chan_ooh323) старого доброго H.323 не обеспечивают такой возможности, хотя в самом стандарте H.323 это предусмотрено. Так, чтобы разрешить совершать вызовы с поддержкой видео, достаточно добавить в файл sip.conf параметр:

[general]
videosupport=yes

В IAX эта возможность заложена изначально, поэтому параметр videosupport в файле iax.conf не поддерживается. Список видеокодеков, умеющих работать с видео, невелик: H.261 (только транзит), H.263, H.263p и H.264 (последние два с Asterisk версии 1.4). Но так как Asterisk 1.4 имеет проблемы с согласованием кодеков, активировать их все одновременно не следует. Лучше подобрать наиболее оптимальный для конкретной ситуации, отключив остальные при помощи «disallow=all». Но не забывай, что выбранный кодек должен поддерживаться и клиентом.

disallow=all
allow=alaw
allow=gsm
allow=speex
allow=ilbc
allow=h264
allow=h261

По умолчанию максимальный битрейт для видео установлен в 384 Кб/с, – его можно изменить при помощи директивы maxcallbitrate. Нельзя не отметить, что Asterisk умеет задавать биты TOS (Type of Service) в заголовке IP-пакета, чтобы ускорить передачу потока данных через маршрутизаторы, которые учитывают биты TOS при определении маршрутов. В sip.conf директивы tos_sip, tos_audio и tos_video управляют TOS-битами для SIP-сообщений, аудио- и видеоданных соответственно.

tos_video=af41

В iax.conf все поля TOS устанавливаются при помощи одного параметра:

tos=0x18

В настоящее время передачу видео поддерживает огромное количество софт-клиентов: Ekiga, Bria, X-lite, Linphone, Milliphone, WengoPhone, Windows Messenger и некоторые другие.

Вместо заключения

Что еще можно сделать с помощью Asterisk? Например, расширить функции устаревшей коммутируемой АТС, создать интерактивный автоответчик (это может быть прогноз погоды для любой точки земного шара, обучающая программа или аудиоигра - ответы можно вводить посредством номеронабирателя телефона), организовывать аудиоконференц-залы, читать электронную почту вслух, когда ты, например, в дороге или принимаешь ванну (связка Asterisk + Festival), управлять системой сигнализации, контролировать няню и детей (допустим, мать и отец, сидя на работе, подключаются VPN-клиентом к домашнему серверу, звонят в контекст добавочного номера, защищенного паролем, после успешной аутентификации устанавливается аудиосвязь со всеми IP-телефонами в квартире - это позволит родителям слышать, что происходит в каждой комнате, - своеобразные VoIP-жучки). Прояви творческие способности, замути что-нибудь экстраординарное и напиши нам :).

INFO

Существует патч от разработчика с ником IVeS (смотри на нашем диске файл videocodec_nego_fix_ast-1.4.13.patch.gz), в котором проблема согласования кодеков устранена, но сама заплатка до сих пор не принята Digium.

VIDEO

В видеоролике мы разберем некоторые трюки с Asterisk: говорящие часы, будильник, виртуальный диктофон и телефонный справочник.

WWW

  • Все возможности по инициированию исходящего звонка в Asterisk ты найдешь в документе «Asterisk auto-dial out» - www.voip-info.org/wiki-Asterisk+auto-dial+out.
  • Описание всех известных проблем, связанных с передачей видео, можно найти в списке рассылки Asterisk-Video (lists.digium.com/pipermail/asterisk-video).
Содержание
ttfb: 7.3819160461426 ms