Честно говоря, пособием при реализации описанного в статье подхода (использование PBX Asterisk в качестве платформы разработки телекоммуникационных сервисов) был «немногословный» сайт asterisk-java.org с его Asterisk-Java tutorial и API reference, а также www.voip-info.org. И, по сути, данная статья является небольшим пересказом вышеназванных ресурсов применительно к коду Agi-прокси из вышеназванной статьи.
Проект Asterisk-Java предоставляет возможности взаимодействия Asterisk с java-приложениями, выполняющимися на том же сервере или удаленно. Под взаимодействием понимается, во-первых, выполнение java-приложения при наступлении телекоммуникационного события (звонка), а во-вторых, управление и изменение состояния Asterisk непосредственно из java-приложений. В первом случае API Asterisk позволяет описывать обработку звонков (читай dialplan) с помощью высокоуровневых средств (The FastAGI protocol). Во втором случае используется Manager API. Отличие первого подхода от второго заключается в том, что при использовании FastAGI взаимодействие с java-приложением инициируется со стороны Asterisk, а при взаимодействии через Manager API необходимо из самого java-скрипта установить соединение с Asterisk и выполнять действия (ManagerActions), получать ответы (ManagerResponses) и обрабатывать события (ManagerEventListener) от сервера Asterisk.
В Agi-прокси используется и FastAGI (параметры звонка попадают в AgiProxyScript, а затем в web-сервис) и Manager API (при переадресации вызова выполняется фактически звонок в Asterisk).
FastAGI – набор java-классов, на основе которых реализуется AGI-скрипт.
AGI-java-скрипт выполняется сервером Asterisk в соответствии с dialplan, описанном в extensions.conf. Напомню, что обычно extensions.conf располагается в /etc/asterisk/. Итак, например, строка в extensions.conf
exten => 1300,1,Agi(agi://localhost/agiproxy.agi)
предписывает серверу Asterisk при вызове номера 1300 выполнить скрипт с названием agiproxy.agi. Название agiproxy.agi является маппингом на реальное имя class-файла, реализацию AGI-скрипта. Непосредственно маппинг прописывается в файле /var/lib/asterisk/agi-bin/fastagi-mapping.properties и может иметь, например, следующую строку:
agiproxy.agi = AgiProxyScript
где, AgiProxyScript – файл /var/lib/asterisk/agi-bin/AgiProxyScript.class.
Как видно из рисунка, запуск AGI-скрипта выполняется через AgiServer, java-класс из пакета Asterisk-Java реализующий AGI поверх протокола TCP/IP. По сути, Asterisk является своеобразным контейнером для AGI-скриптов, в некоторой степени аналогичным web-контейнеру.
Из исходного кода Agi-прокси видно, что в классе java-скрипта должен быть реализован метод service с двумя параметрами. В первом параметре типа AgiRequest приходят данные от Asterisk, такие как CallerIdName – имя абонента, CallerIdNumber – номер абонента, Extension – название расширения и т.д. На основе этих параметров и осуществляется поиск (в удаленной JSP) команд, которые необходимо выполнить в Asterisk (фактически, это формирование dialplan). Через второй параметр - интерфейс AgiChannel java-приложение получает доступ к командам Asterisk. В тестовом примере AgiProxyScript наследует от BaseAgiScripts, который в свою очередь реализует интерфейсы AgiChannel и AgiScript. Это означает, что AgiProxyScript имеет непосредственный доступ к командам Asterisk – answer(), hangup(), streamFile() и т.д. Одной из команд, которая выполняется в демонстрационном AgiProxyScript является переадресация вызова на указанный номер абонента. Однако такой команды в AgiChannel не предусмотрено, и данная возможность предоставляется через Manager API. В этом случае из java-приложения устанавливается TCP/IP соединение с Asterisk (по умолчанию порт 5038), используя имя пользователя и пароль согласно прописанным значениям в файле manager.conf. Получение соединения (ManagerConnection) выполняется через фабрику ManagerConnectionFactory. Перед использованием полученного соединения необходимо выполнить login(), при завершении - logoff(). Взаимодействие с Asterisk через Manager API сводится с отправке в Asterisk действий (с помощью классов-реализаций интерфейса ManagerAction), получении ответов (в виде интерфейса ManagerResponse) и обработке приходящих событий (реализовав интерфейс ManagerEventListener) от Asterisk. Так в AgiProxy перед выполнением переадресации создается соединение (в статусе ManagerConnectionState.
INITIAL):ManagerConnectionFactory factory = new ManagerConnectionFactory("hostname", "username", "password");
ManagerConnection managerConnection = factory.createManagerConnection();
затем
managerConnection.login();
соединение переводится в статус ManagerConnectionState.CONNECTED и готово к взаимодействию.
Непосредственно переадресация на номер 500:
RedirectAction action = new RedirectAction(getChannel(), aGIRequest.getContext(), “500”, new Integer(1)); managerConnection.sendAction(action);
В конце всего:
managerConnection.logoff();
Отмечу, что и FastAGI и Manager API посылают команды в Asterisk в строковом виде, но в FastAGI это выполняется через метод buildCommand() классов реализующих интерфейс AgiCommand (AnswerCommand, StreamFileCommand, HangupCommand…), а в Manager API - через интерфейс ActionBuilder.
И пару слов о процессе компиляции скрипта и запуске AgiServer. В простейшем случае после написания скрипта в /var/lib/asterisk/agi-bin/ должны находиться следующие файлы:
- библиотека Asterisk-Java, на момент написания статьи asterisk-java-0.3.1.jar
- файл маппинга fastagi-mapping.properties
- исходный файл AGI-скрипта, например HelloAgiScript.java
Для компилирования Java-скрипта используйте команду следующего вида (JDK должна быть установлена):
javac -cp Asterisk-Java-0.3.1.jar HelloAgiScript.java
После этого в /var/lib/asterisk/agi-bin/ появиться еще один файл - HelloAgiScript.class.
Запустить AgiServer можно выполнив следующую команду (Asterisk должен быть уже запущен):
java -cp Asterisk-Java-0.3.1.jar:. org.asteriskjava.fastagi.DefaultAgiServer
Не знаю на сколько широко и доходчиво я раскрыл концепцию проекта Asterisk-Java, так что буду рад поправкам, ссылкам и комментариям.