5 авг. 2008 г.

Комментарий-заметка к статье от 6 июля 2008 г.

По просьбе читателя хотел было сначала попробовать описать подход Asterisk-Java в виде комментария к предыдущей статье "Модель разработки телекоммуникационных сервисов с использованием IP PBX Asterisk", но в конце концов решил оформить это небольшой заметкой.
Честно говоря, пособием при реализации описанного в статье подхода (использование 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, так что буду рад поправкам, ссылкам и комментариям.

6 июл. 2008 г.

The Asterisk as a platform for the development of telecommunication services.

We would like to share with you one interesting model for the use of the PBX Asterisk. To be more precise, the main idea is to use the Asterisk as a platform for the development of telecommunication services. With its open source software and API, the Asterisk can bring the development of telecommunication services down to a simpler process of Web programming thus considerably lowering “the entrance barrier” for those involving in the programming of new services.
We propose to integrate a new component (proxy) into the Asterisk platform. The main functionality of the proxy is to translate telecommunication calls into HTTP requests to external web services. Telecommunication services are located separately from the PBX, while the information they receive from Asterisk is presented as a HTTP-request. Technically, HTTP GET/POST request is a request, in which external telecommunications service passed information about the subscriber's name - CallerIdName, caller’s number - CallerIdNumber and and called number - Extension. Upon receiving necessary parameters, such as (calling/called number) a web service produces and forwards its instructions to the proxy. The latter receives and translates them into Asterisk instructions. The development of such services under the architecture described above is similar to a conventional CGI-script, for which there is a plenty of programming tools. As a result a programmer doesn’t need to be familiar with the Asterisk API.
Let’s consider in a more detailed way the model for the development of telecommunication services. Its global framework is shown below.
As seen the AGI-proxy component is at the heart of the model. The AGI-proxy is a Java-based application implemented on the basis of FastAGI, an open source library. The AGI-proxy is installed directly on the PBX Asterisk side.
In fact, the Asterisk represents the same thing for the AGI-proxy, as the J2EE container does for a Java-servlet. All calling massages produced by the Asterisk come to the proxy within the method service with two parameters: interfaces AgiRequest and AgiChannel. Through the first parameter one can get the information about the calls (caller name / number, called number, context of the call, feed settings, etc.) and through the second one the interaction with the Asterisk is carried out (call termination, transfer mode and etc.). Subscriber’s name (CallerIdName), caller’s number (CallerIdNumber) and called number (Extension) are wrapped within a string-parameter by the AGI-proxy. Then the AGI-proxy executes an HTTP request on its behalf to an external web service, whose URL is set in the configuration. The response from the invoked service is seen as an indication to what to do with the call. The call may be terminated or redirected to a specified number; a media file may be played. The instructions returned by an external service must be presented in an xml-format. It has a very simple scheme:
An example of the typical response of a web service is shown below:
On receiving this xml-response, the proxy will play the media file "demo-nogo" (playMadiaFile).

Under this architecture the sequence of calls is reduced to a very simple diagram.
We would like to say a few words about external web services and provide you with one simplified example. Web services within this model may have many different purposes - from the statistics (to record a call and terminate it - in voting systems) to the Asterisk dialplan control (auto- answering and call forwarding in communication systems).
To demonstrate the functionality the proxy we need two files agiproxy.jar, AgiProxyScript.java and two configuration files - agiproxy.conf, fastagi-mapping.properties. The files should be copied to the directory /var/lib/asterisk/agi-bin/. Let’s make the following steps to configure the proxy:

1. Set the extensions (calls), to which the proxy will “react”. In the file /etc/asterisk/extensions.conf one may write, for example, the following instruction:
exten => _1XXX,1,Agi(agi://localhost/proxy.agi)
(To run the proxy when a four-digit number beginning with "1" is dialing up)

2. Set the URL of an external service (see below), with which the proxy will interact. For example:
urltunnel=http://localhost:8080/agiweb/agi.jsp
(to perform an HTTP-request to the agi.jsp at the localhost)

3. Set parameters for the interaction of the proxy with the Asterisk:
hostname=localhost (Asterisk server name)
username=manager (user name indicated in manager.conf)
password=pa55w0rd (password from manager.conf)

4. Compile AgiProxyScript.java for your operating system as follows: to run the instruction written below from /var/lib/asterisk/agi-bin/-directory (for Java version 1.6):
javac -cp .:asterisk-java-0.3.1.jar:agiproxy.jar AgiProxyScript.java

5. Run the Asterisk, using, for example, the following instruction:
asterisk -vvvvvcd

6. Launch the AgiServer by invoking the instruction below from /var/lib/asterisk/agi-bin/ -directory:
java -cp agiproxy.jar:asterisk-java-0.3.1.jar:. org.asteriskjava.fastagi.DefaultAgiServer

As the example of external services a trivial java server page (agi.jsp) has been written. It parses the string of parameters received from the AGI-proxy and determines a called number (Extension). Then it creates instructions for Asterisk depending of the called number: for the number “1200” a media file will be played, a call having the number “1300” will be redirected to the number “500”, any other numbers will be terminated.
In conclusion, let me remind you the advantages of using this model to develop telecommunication services as opposed to the traditional "programming" dialplan in configuration files:
1. The entry barrier for programmers of new telecommunication services becomes lower.
2. The possibility to develop services using various technologies, such as CGI, JSP, ASP.NET.
3. The possibility of integration of new external services without any changes on the PBX side.

This article does not claim to carry revolutionary ideas, neither the examples have a rich functionality. This is only an attempt to create some basis for the open source project aimed to develop further programming technology and tools for the Asterisk.

Source code and files necessary to install the demonstration examples are available here.

Article in Russia language.

Модель разработки телекоммуникационных сервисов с использованием IP PBX Asterisk.

Хотелось бы поделиться с Вами работой, в которой рассмотрена интересная, на мой взгляд, модель использования PBX Asterisk. Если быть более точным, то идея заключается в использовании Asterisk в качестве платформы разработки телекоммуникационных сервисов. Обладая открытым исходным кодом и API, Asterisk позволяет свести разработку телекоммуникационных сервисов к веб-программированию, что резко снижает входной барьер для программиста, создающего новые сервисы.
В данной работе предлагается расширить Asterisk новым компонентом (прокси), основной функцией которого является перевод телекоммуникационных вызовов в HTTP запросы к внешним веб-сервисам. При этом телекоммуникационные сервисы располагаются отдельно от PBX, а информацию от Asterisk в виде HTTP-запроса. Технически - это HTTP GET/POST запрос, в котором внешнему телекоммуникационному сервису передается информация об имени абонента - CallerIdName, номере вызывающего абонента - CallerIdNumber и номере вызываемого абонента - Extension. Исходя из полученных параметров (номер вызывающего/вызываемого абонента) веб-сервис формирует ответные инструкции, которые получает прокси и транслирует в команды Asterisk. Разработка сервисов в такой архитектуре выглядит как создание обычного CGI-скрипта, для написания которого имеется не мало средств разработки. В результате программист освобождается от изучения API Asterisk.
Рассмотрим более подробно модель разработки телекоммуникационных сервисов. На схеме показана общая архитектура решения.

На данной схеме центральное место занимает AGI-proxy, который представляет из себя Java-приложение, реализованное на базе открытой библиотеки FastAGI. AGI-proxy устанавливается непосредственно на стороне PBX Asterisk.
По сути, Asterisk является тем же для AGI-proxy, что и J2EE контейнер для сервлета. Все вызовы от Asterisk приходят в прокси в метод service с двумя параметрами: интерфейсы AgiRequest и AgiChannel. Через первый параметр можно получить информацию о вызове (имя/номер вызывающего абонента, номер вызываемого абонента, контекст вызова, параметры канала и т.д.), а через второй – осуществлять взаимодействие с Asterisk (прекращение вызова, перевод в режим ответа и т.д.). AGI-proxy "заворачивает" в строку имя абонента - CallerIdName, номер вызывающего - CallerIdNumber, номер вызываемого абонента - Extension и от своего имени выполняет HTTP запрос к некоторму веб-сервису, URL которого настроен при конфигурации. Ответ сервиса рассматривается как указание на то, что дальше делать со звонком, например, звонок можно терминировать, проиграть позвонившему медиа-файл, можно переадресовать звонок на указанный номер. Инструкции, которые возвращает внешний сервис должны быть в xml-формате, схема которого очень проста:

Пример типичного отклика веб-сервиса:

Получив данный xml-ответ, прокси проиграет медиа-файл (playMadiaFile) с названием «demo-nogo».
В такой архитектуре последовательность вызовов сводится к очень простой диаграмме, отдельные шаги которой упоминались выше.

Хотелось бы несколько слов сказать о внешних веб-сервисах и привести упрощенный пример. Веб-сервисы в такой модели могут преследовать самые разные цели – от статистических (отметить факт звонка и завершить его - в системах голосования) до задач управления планами маршрутизации Asterisk (автоответчики и переадресация в информационных системах).
Для демонстрации работоспособности модели прокси представлен двумя файлами agiproxy.jar, AgiProxyScript.java и парой файлов конфигурации - agiproxy.conf, fastagi-mapping.properties. Необходимо скопировать их в /var/lib/asterisk/agi-bin/ и выполнить следующие шаги для настройки прокси:

1. Настроить extensions (вызовы), на которые будет «реагировать» прокси: в файле /etc/asterisk/extensions.conf прописать, например такую строку:
exten => _1XXX,1,Agi(agi://localhost/proxy.agi)
(прокси запуститься при наборе четырехзначного номера, начинающегося с «1»)

2. Настроить URL внешнего сервиса (см.далее), с которым прокси будет взаимодействовать. В файле /var/lib/asterisk/agi-bin/agiproxy.conf добавить, например, строку:
urltunnel=http://localhost:8080/agiweb/agi.jsp
(выполнять HTTP-запрос к agi.jsp на localhost)

3. Настроить параметры для взаимодействия прокси с Asterisk в файле /var/lib/asterisk/agi-bin/agiproxy.conf:
hostname=localhost (имя сервера Asterisk)
username=manager (имя пользователя из файла manager.conf)
password=pa55w0rd (пароль из файла manager.conf)

4. Скомпилировать AgiProxyScript.java для вашей операционной системы следующим образом: из /var/lib/asterisk/agi-bin/ выполнить команду (для java версии 1.6):
javac -cp .:asterisk-java-0.3.1.jar:agiproxy.jar AgiProxyScript.java

5. Запустить Asterisk, например командой:
asterisk -vvvvvcd

6. Запустить AgiServer выполнив из /var/lib/asterisk/agi-bin/ команду
java -cp agiproxy.jar:asterisk-java-0.3.1.jar:. org.asteriskjava.fastagi.DefaultAgiServer

В качестве внешнего сервиса была написана тривиальная java server page (agi.jsp), которая сначала разбирает строку параметров от AGI-proxy и определяет вызываемый номер (Extension), а затем по этому номеру формирует инструкции для Asterisk: для номера 1200 будет проигран медиа-файл, вызов номера 1300 будет переадресован на номер 500, а все остальные звонки терминированы.
В заключении напомню преимущества использования данной модели разработки телекоммуникационных сервисов по сравнению с традиционным «программированием» диалплана в файлах конфигурации:


1. Снижается входной барьер для программиста, создающего новые телекоммуникационные сервисы.
2. Возможность разработки сервисов с использованием различных средств – CGI, JSP, ASP.NET.
3. Возможность добавления внешних сервисов без каких-либо изменений на стороне PBX.

Статья не претендует на революционность идеи, а представленные пример на богатый функционал. Это всего лишь попытка создать некоторую базу для Open Source проекта, направленного на развитие средств разработки для Asterisk.

Исходный код прокси и файлы для установки примера доступны здесь.

Текст статьи на английском языке.