Расширяем возможности Asterisk, используя PHP

в 13:22, , рубрики: asterisk, php, метки: , ,

Все слышали про мини-АТС нового поколения имя которой Asterisk. Так уж случилось что я заинтересовался этой системой и даже успел сделать пару коммерческих проектов.

В этой статье я хочу немного расказать об интеграции звездочки с языком программирования php. При этом мы будем использовать класс phpagi.

Под катом я приведу примеры использования нескольких методов этого класса которые помогли мне.


Первым делом качаем последнюю версию phpagi и подключаем его в наш проект, а так же правим файл /etc/asterisk/manager.conf

; 
; Asterisk Call Management support
;
[general]
enabled = yes   ; Включаем asterisk manager interface (AMI)
port = 5038
bindaddr = 127.0.0.1  ; Доступ только с локалхоста для безопастности
webenabled = no

; Each user has a section labeled with the username
; so this is the section for the user named "mark"
[user] ; имя пользователя для конекта
secret = qwerty  ; пароль
deny=0.0.0.0/0.0.0.0  ; еще запреты на коннект
permit=127.0.0.1/255.255.255.0
read = system,call,log,verbose,command,agent,user,originate  ; Права пользователя на выполнение комманд
write = system,call,log,verbose,command,agent,user,originate

В архиве с phpagi есть файл phpagi.conf, его нужно скопировать в /etc/asterisk и естественно исправить логин и пароль.
Теперь мы можем смело подключатся к AMI из php скрипта, например так:

include('phpagi.php');

$manager = new AGI_AsteriskManager();

$manager->connect(); // если нет файла phpagi.conf то тут можно указать хост, логин, пароль.

Первым делом я хотел бы расказать о написании простейшего монитора событий asterisk на php.
Как мне кажется это самая полезная функция класса phpagi.

Вот такой у меня вышел монитор событий:

function dump_events($ecode,$data,$server,$port) {
            $date_now = date('Y-m-d');
            $time_now = date('H:i:s');
            echo "$time_now : received event '$ecode' from $server:$portn";
            print_r($data);
        }

         include('phpagi.php');

        $manager = new AGI_AsteriskManager();

        $manager->connect();
        $manager->add_event_handler('*', 'dump_events'); // цепляем хендлер на все события которые
                                                         // поступают из AMI и передаем управление
                                                         // функции описанной выше

        $manager->wait_response();  // очень полезная вещь, благодаря этой функции скрипт будет
                                    // ждать событий и не стопится в отличии от sleep()
        $manager->disconnect(); 

Используя этот хендлер можно выполнять какие нибудь действия в зависимости от полученного эвента, например проверять баланс на sim-карте вставленной в модем huawei и подключенной через chan_dongle.
Приведу пример своей реализации используя метод Command:
Первый скрипт ловит событие newussd

function donglenewussd($ecode, $data) {
            if($model = Trunk::model()->find('value = :value', array(
                ':value' => $data['Device']))){
                if(!empty($data['MessageLine0'])){
                    $balance = explode(' ', $data['MessageLine0']);
                    switch($model->carrier){
                        case '0':
                            break;
                        case '1':
                            $model->balance = $balance[0];
                            $model->save();
                            echo $balance[0]."n";
                            break;
                        case '2':
                            $model->balance = $balance[2];
                            $model->save();
                            echo $balance[2]."n";
                            break;
                        case '3':
                            preg_match('/[+-]?d+.?d*/', $balance[1], $match);
                            $model->balance = $match[0];
                            $model->save();
                            echo $match[0]."n";
                            break;
                    }
                }
            }
        }
        $manager = new AGI_AsteriskManager();
        $manager->connect();
        $manager->add_event_handler('donglenewussd', 'donglenewussd');
        $manager->wait_response();
        $manager->disconnect();

Этот скрипт получает событие donglenewussd в котором нам приходит ответ от оператора на основе которого мы заносим в базу информацию о состоянии баланса.
Следующий скрипт будет по крону скажем раз в час отправлять ussd запрос по сотоянию баланса.

        $manager = new AGI_AsteriskManager();
        $manager->connect();
        $trunks =Trunk::model()->findAll();
        foreach($trunks as $trunk){
            switch($trunk->carrier){
                case '1':
                    $manager->Command('dongle ussd '.$trunk->value.' *101#');
                    break;
                case '2':
                    $manager->Command('dongle ussd '.$trunk->value.' *111#');
                    break;
                case '3':
                    $manager->Command('dongle ussd '.$trunk->value.' *111#');
                    break;
            }
        }
        $manager->disconnect();

Как вы могли заметить я испоьзую yii framework для своих проектов, у меня есть модель в которой хранятся настройки модема (системное имя, оператор, баланс, состояние и т.д.)

Данный пример работает с Украинскими операторами (МТС, Киевстар и Life)

И на десерт я хочу Вам расказать про метод Originate. Вы еще используете call файлы? тогда мы идем к Вам.

Очень полезная функция которая инициирует звонок используя AMI, а не старый дедовский способ путем копирования call файла в директорию /var/spool/asterisk/outgoing

Все параметры передаваемые в функцию почти такие же как и параметры call файла:

$manager->Originate(
'Канал для вызова, например SIP/1001',
'Экстеншн для диалплана',
'Контекст диалплана',
'Приоритет контекста диалплана',
'Или приложение астериска для запуска, например playback',
'параметры приложения, например пусть к аудиофайлу',
'таймаут',
'Номер абонента от которого идет вызов или имя',
'переменные для диалплана',
'account - незнаю зачем, не использовал еще',
'Синхронный или асинхронный запрос (ждет или не ждет ответа о состоянии запроса)',
'actionid - тоже пока не использовал'
);

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

Надеюсь моя статья окажется кому нибудь полезной, так как я не нашел упоминание phpagi на хабре, да и вообще с трудом нашел хоть какие нибудь примеры использования кроме тех что идут в архиве с библиотекой.

Если у кого то есть другие методы работы с этой библиотекой очень буду рад почитать о них в коментариях.

Автор: MrZaYaC

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js