AMI функционал из PHP
Статья затрагивает набор стандартных Action’s (действий), которыми можно управлять из любого кода или приложения удаленно сервером телефонии.
Первым делом определимся с реализацией. Возьмем скриптовый серверный язык PHP (но им все не ограничено, подробнее читать в статье: ) и напишем несколько базовых функций-примитивов. Но прежде всего разберемся с тем, куда и как отправляются команды.
Создание сокета и его закрытие
Первым делом нужно определиться с тем куда мы будем обращаться на сетевом уровне. Нам необходимо создать объект типа сокет. Выполняем это следующим образом (внимание! параметры указаны примерные, в Вашей реализации они могут отличаться):
$socket = fsockopen(ami_host, ami_port, $ac_err_num, $ac_err_msg, 3);
if (!$socket){
echo «AMI connection: failed!
Error number: «.$ac_err_num.»
Error notice: «.$ac_err_msg.»
«;
}
else{
//echo «AMI connection: success
«;
}
Константы: ami_host, ami_port должны быть определены до создания сокета. По умолчанию при запуске внутри сервера применяются параметры:
define(‘ami_host’,’localhost’);
define(‘ami_port’,’5038′);
Теперь у нас определен сетевой объект на который мы будем засылать обращения. Следующим шагом опишем, как нам освободить его. Для этого достаточно всего одной строки:
fclose($socket);
Обратите внимание, эта функция вызывается с параметром сокета, который необходимо закрыть.
Авторизация и ее отмена
Мы научились определять элемент сокета и отображать результат о статусе подключения к нему. Но даже при успешном соединении, нам необходимо выполнить еще один шаг прежде чем получить доступ к AMI, а именно нужно пройти авторизацию пользователя или менеджера. Как создать нового можно ознакомиться по ссылке:
Первым делом снова объявим константами логин и пароль:
define(‘ami_user’,’fromami’);
define(‘ami_pass’,’testamiconnecter’);
И попробуем пройти авторизацию, выполнив следующее обращение к сокету:
$auth = «Action: loginrn»;
$auth .= «Username: «.ami_user.»\r\n»;
$auth .= «Secret: «.ami_pass.\r\n»;
$auth .= «Events: off\r\n\r\n»;
fputs($socket,$auth);
usleep(500000);
Здесь допустимо как использование конкатенации для сбора всех команд и единовременной отправки сокету, так и построчное выполнение.
Если все правильно и нашему пользователю разрешен доступ, мы увидем следующий ответ сокета (не обязательно в таком оформлении, но слова те же):
Теперь у нас есть возможность отправлять команды в сокет, и посредством AMI управлять astrisk. Но прежде стоит заметить, что отмена авторизации выполняется так же обращением к сокету:
$action = «Action: Logoff\r\n\r\n»;
fputs($socket,$action);
usleep(500000);
Примеры функций работы со звонками
К этому пункту мы умеем назначать объект сокета и освобождать его. Проходить и отменять авторизацию. Осталось описать то, зачем нам это было нужно: привести несколько примеров работы с AMI.
Для примера были выбраны самые распространенные функции АТС Asteriks: работа со звонком и конференцией.
1. Функции работы со звонком из AMI
Инициализируем вызов, за исключением некоторых различий функция напоминает синтаксис создания call-файлов. Обратите внимание в строке определения «Callerid», после самого имени, в угловых скобках указывается номер назначения, иначе в базу пойдет неверный номер.
function init_call($ext_from,$ext_to){
global $socket;
$action = «Action: Originate\r\n»;
$action .= «Channel: SIP/$ext_from\r\n»;
$action .= «Callerid: Phoenix-call <$ext_to>\r\n»;
$action .= «Timeout: 15000\r\n»;
$action .= «Context: from-internal\r\n»;
$action .= «Exten: $ext_to\r\n»;
$action .= «Priority: 1\r\n\r\n»;
$action .= «Async: yes\r\n\r\n»;
fputs($socket,$action);
usleep(500000);
}
Перехват вызова. Обратите внимание! Здесь нам необходимо передавать не только номер, того кто осуществляет перехват, но и номер канала.
function pickup_call($ext_from,$channel){
global $socket;
$action = «Action: Originatern»;
$action .= «Channel: SIP/$ext_from\r\n»;
$action .= «Callerid: Phoenix-Pickup\r\n»;
$action .= «Application: PickupChan\r\n»;
$action .= «Data: $channel\r\n\r\n»;
$action .= «Timeout: 15000\r\n»;
$action .= «Priority: 1\r\n\r\n»;
$action .= «Async: yes\r\n\r\n»;
fputs($socket,$action);
usleep(500000);
}
Прослушка разговора. Использует два параметра: номера того кто прослушивает и того ктого будут слушать. Обратите внимание на параметры, которые передаются после номера вызываемого абонента.
function spy_call($ext_from,$ext_to){
global $socket;
$action = «Action: Originatern»;
$action .= «Channel: SIP/$ext_from\r\n»;
$action .= «Callerid: Phoenix-Spy\r\n»;
$action .= «Application: ChanSpy\r\n»;
$action .= «Data: $ext_to,qx\r\n»;
$action .= «Timeout: 15000\r\n»;
$action .= «Priority: 1\r\n\r\n»;
$action .= «Async: yes\r\n\r\n»;
fputs($socket,$action);
usleep(500000);
}
Суфлирование вызова. Параметры аналогичные прослушке.
function whispers_call($ext_from,$ext_to){
global $socket;
$action = «Action: Originatern»;
$action .= «Channel: SIP/$ext_fromrn»;
$action .= «Callerid: Phoenix-whispersrn»;
$action .= «Application: ChanSpyrn»;
$action .= «Data: $ext_to,wxrn»;
$action .= «Timeout: 15000rn»;
$action .= «Priority: 1rnrn»;
$action .= «Async: yesrnrn»;
fputs($socket,$action);
usleep(500000);
}
И функция-антогонист инициализации вызова: завершение. Принимает единственный параметр — номер канала который необходимо прервать.
function destr_call($channel){
global $socket;
$action = «Action: Hanguprn»;
$action .= «Channel: $channelrnrn»;
fputs($socket,$action);
usleep(500000);
}
Просто? Возможно. А как будет выглядеть управление конференцией? Следующими функциями. Обратите внимание, здесь все функции имеют комплементарные пары.
Блокирование звука у участница конференции. Фактически перекрывание RTP потока от определенного канала. Поэтому передаются параметры: номер конференции и канала.
function mute_conf($conf_num,$channel){
global $socket;
$action = «Action: ConfbridgeMutern»;
$action .= «Conference: $conf_numrn»;
$action .= «Channel: $channelrnrn»;
fputs($socket,$action);
usleep(500000);
}
Отмена предыдущей команды.
function unmute_conf($conf_num,$channel){
global $socket;
$action = «Action: ConfbridgeUnmutern»;
$action .= «Conference: $conf_numrn»;
$action .= «Channel: $channelrnrn»;
fputs($socket,$action);
usleep(500000);
}
Включить запись разговора конференции. Поскольку здесь нет работы с каналами, передается единственный параметр: номер очереди.
function start_record_conf($conf_num){
global $socket;
$action = «Action: ConfbridgeStartRecordrn»;
$action .= «Conference: $conf_numrn»;
fputs($socket,$action);
usleep(500000);
}
Отмена: выключение записи конференции.
function stop_record_conf($conf_num){
global $socket;
$action = «Action: ConfbridgeStopRecordrn»;
$action .= «Conference: $conf_numrn»;
fputs($socket,$action);
usleep(500000);
}
Блокирование конференции. Запрещает подключение новых участников конференции.
function locked_conf($conf_num){
global $socket;
$action = «Action: ConfbridgeLockrn»;
$action .= «Conference: $conf_numrn»;
fputs($socket,$action);
usleep(500000);
}
Отмена: открытие конференц-комнаты.
function unlocked_conf($conf_num){
global $socket;
$action = «Action: ConfbridgeUnlockrn»;
$action .= «Conference: $conf_numrn»;
fputs($socket,$action);
usleep(500000);
}
Функция удаления из конференции. Фактически, после оповещения оператора прерывает его канал, поэтому два параметра.
function kick_from_conf($conf_num,$channel){
global $socket;
$action = «Action: ConfbridgeKickrn»;
$action .= «Conference: $conf_numrn»;
$action .= «Channel: $channelrnrn»;
fputs($socket,$action);
usleep(500000);
}
Внимательный читатель мог заметить недостачу. Было оговорено, что все функции конференции парные. Но при этом у функции удаления из конфы не было пары. Как же попасть в конференцию? Все просто: нужно инициализировать вызов на внутренний номер оператора и связать с номером конференции. Т.е. допустимо использовать функцию init_call из предыдущего пункта.
Осталось доработать интерфейс на свой вкус и настроить взаимодействие с перечисленными функциями. По аналогии можно выполнить множество других команд, о которых можно прочитать по ссылке:
А в конце приведу полный код файла-скрипта. Его можно включать в проект и использовать как библиотеку.
<?php
function ami_connect(){
global $socket;
$socket = fsockopen(ami_host, ami_port, $ac_err_num, $ac_err_msg, 3);
if (!$socket){
echo «AMI connection: failed!
Error number:».$ac_err_num.»
Error notice:».$ac_err_msg.»
«;
}
else{
//echo «AMI connection:success
«;
}
$auth = «Action: loginrn»;
$auth .= «Username: «.ami_user.»rn»;
$auth .= «Secret: «.ami_pass.»rn»;
$auth .= «Events: offrnrn»;
fputs($socket,$auth);
usleep(500000);
}
function mute_conf($conf_num,$channel){
global $socket;
$action = «Action: ConfbridgeMutern»;
$action .= «Conference: $conf_numrn»;
$action .= «Channel: $channelrnrn»;
fputs($socket,$action);
usleep(500000);
}
function unmute_conf($conf_num,$channel){
global $socket;
$action = «Action: ConfbridgeUnmutern»;
$action .= «Conference: $conf_numrn»;
$action .= «Channel: $channelrnrn»;
fputs($socket,$action);
usleep(500000);
}
function start_record_conf($conf_num){
global $socket;
$action = «Action: ConfbridgeStartRecordrn»;
$action .= «Conference: $conf_numrn»;
fputs($socket,$action);
usleep(500000);
}
function stop_record_conf($conf_num){
global $socket;
$action = «Action: ConfbridgeStopRecordrn»;
$action .= «Conference: $conf_numrn»;
fputs($socket,$action);
usleep(500000);
}
function locked_conf($conf_num){
global $socket
$action = «Action: ConfbridgeLockrn»;
$action .= «Conference: $conf_numrn»;
fputs($socket,$action);
usleep(500000);
}
function unlocked_conf($conf_num){
global $socket;
$action = «Action: ConfbridgeUnlockrn»;
$action .= «Conference: $conf_numrn»;
fputs($socket,$action);
usleep(500000);
}
function kick_from_conf($conf_num,$channel){
global $socket;
$action = «Action: ConfbridgeKickrn»;
$action .= «Conference: $conf_numrn»;
$action .= «Channel: $channelrnrn»;
fputs($socket,$action);
usleep(500000);
}
function init_call($ext_from,$ext_to){
global $socket;
$action = «Action: Originatern»;
$action .= «Channel: SIP/$ext_fromrn»;
$action .= «Callerid: Phoenix-call <$ext_from>rn»;
$action .= «Timeout: 15000rn»;
$action .= «Context: from-internalrn»;
$action .= «Exten: $ext_torn»;
$action .= «Priority: 1rnrn»;
$action .= «Async: yesrnrn»;
fputs($socket,$action);
usleep(500000);
}
function pickup_call($ext_from,$channel){
global $socket;
$action = «Action: Originatern»;
$action .= «Channel: SIP/$ext_fromrn»;
$action .= «Callerid: Phoenix-Pickuprn»;
$action .= «Application: PickupChanrn»;
$action .= «Data: $channelrnrn»;
$action .= «Timeout: 15000rn»;
$action .= «Priority: 1rnrn»;
$action .= «Async: yesrnrn»;
fputs($socket,$action);
usleep(500000);
}
function spy_call($ext_from,$ext_to){
global $socket;
$action = «Action: Originatern»;
$action .= «Channel: SIP/$ext_fromrn»;
$action .= «Callerid: Phoenix-Spyrn»;
$action .= «Application: ChanSpyrn»;
$action .= «Data: $ext_to,qxrn»;
$action .= «Timeout: 15000rn»;
$action .= «Priority: 1rnrn»;
$action .= «Async: yesrnrn»;
fputs($socket,$action);
usleep(500000);
}
function whispers_call($ext_from,$ext_to){
global $socket;
$action = «Action: Originatern»;
$action .= «Channel: SIP/$ext_fromrn»;
$action .= «Callerid: Phoenix-whispersrn»;
$action .= «Application: ChanSpyrn»;
$action .= «Data: $ext_to,wxrn»;
$action .= «Timeout: 15000rn»;
$action .= «Priority: 1rnrn»;
$action .= «Async: yesrnrn»;
fputs($socket,$action);
usleep(500000);
}
function destr_call($channel){
global $socket;
$action = «Action: Hanguprn»;
$action .= «Channel: $channelrnrn»;
fputs($socket,$action);
usleep(500000);
}
function ami_disconnect(){
global $socket;
$action = «Action: Logoff\r\n\r\n»;
fputs($socket,$action);
usleep(500000);
fclose($socket);
}
?>
Остались вопросы?
Я - Компаниец Никита, менеджер компании Voxlink. Хотите уточнить детали или готовы оставить заявку? Укажите номер телефона, я перезвоню в течение 3-х секунд.
категории
- DECT
- Linux
- Вспомогательный софт при работе с Asterisk
- Интеграция с CRM и другими системами
- Интеграция с другими АТС
- Использование Elastix
- Использование FreePBX
- Книга
- Мониторинг и траблшутинг
- Настройка Asterisk
- Настройка IP-телефонов
- Настройка VoIP-оборудования
- Новости и Статьи
- Подключение операторов связи
- Разработка под Asterisk
- Установка Asterisk
VoIP оборудование
ближайшие курсы
Новые статьи
10 доводов в пользу Asterisk
Распространяется бесплатно.
Asterisk – программное обеспечение с открытым исходным кодом, распространяется по лицензии GPL. Следовательно, установив один раз Asterisk вам не придется дополнительно платить за новых абонентов, подключение новых транков, расширение функционала и прочие лицензии. Это приближает стоимость владения станцией к нулю.
Безопасен в использовании.
Любое программное обеспечение может стать объектом интереса злоумышленников, в том числе телефонная станция. Однако, сам Asterisk, а также операционная система, на которой он работает, дают множество инструментов защиты от любых атак. При грамотной настройке безопасности у злоумышленников нет никаких шансов попасть на станцию.
Надежен в эксплуатации.
Время работы серверов некоторых наших клиентов исчисляется годами. Это значит, что Asterisk работает несколько лет, ему не требуются никакие перезагрузки или принудительные отключения. А еще это говорит о том, что в районе отличная ситуация с электроэнергией, но это уже не заслуга Asterisk.
Гибкий в настройке.
Зачастую возможности Asterisk ограничивает только фантазия пользователя. Ни один конструктор шаблонов не сравнится с Asterisk по гибкости настройки. Это позволяет решать с помощью Asterisk любые бизнес задачи, даже те, в которых выбор в его пользу не кажется изначально очевидным.
Имеет огромный функционал.
Во многом именно Asterisk показал какой должна быть современная телефонная станция. За многие годы развития функциональность Asterisk расширилась, а все основные возможности по-прежнему доступны бесплатно сразу после установки.
Интегрируется с любыми системами.
То, что Asterisk не умеет сам, он позволяет реализовать за счет интеграции. Это могут быть интеграции с коммерческими телефонными станциями, CRM, ERP системами, биллингом, сервисами колл-трекинга, колл-бэка и модулями статистики и аналитики.
Позволяет телефонизировать офис за считанные часы.
В нашей практике были проекты, реализованные за один рабочий день. Это значит, что утром к нам обращался клиент, а уже через несколько часов он пользовался новой IP-АТС. Безусловно, такая скорость редкость, ведь АТС – инструмент зарабатывания денег для многих компаний и спешка во внедрении не уместна. Но в случае острой необходимости Asterisk готов к быстрому старту.
Отличная масштабируемость.
Очень утомительно постоянно возвращаться к одному и тому же вопросу. Такое часто бывает в случае некачественного исполнения работ или выбора заведомо неподходящего бизнес-решения. С Asterisk точно не будет такой проблемы! Телефонная станция, построенная на Asterisk может быть масштабируема до немыслимых размеров. Главное – правильно подобрать оборудование.
Повышает управляемость бизнеса.
Asterisk дает не просто набор полезных функций, он повышает управляемость организации, качества и комфортности управления, а также увеличивает прозрачность бизнеса для руководства. Достичь этого можно, например, за счет автоматизации отчетов, подключения бота в Telegram, санкционированного доступа к станции из любой точки мира.
Снижает расходы на связь.
Связь между внутренними абонентами IP-АТС бесплатна всегда, независимо от их географического расположения. Также к Asterisk можно подключить любых операторов телефонии, в том числе GSM сим-карты и настроить маршрутизацию вызовов по наиболее выгодному тарифу. Всё это позволяет экономить с первых минут пользования станцией.