Глава 17. AMI и файлы вызовов
Джон Малкович: я видел мир, который не должен видеть ни один человек! Крейг Шварц: Правда? Потому что для большинства людей это довольно приятный опыт. – Быть Джоном Малковичем
Интерфейс Asterisk Manager (Asterisk Manager Interface - AMI) - это интерфейс мониторинга и управления системой, предоставляемый Asterisk. Он позволяет в реальном времени отслеживать события, происходящие в системе, а также позволяет запрашивать Asterisk выполнение некоторых действий. Доступные действия имеют широкий диапазон и включают такие вещи, как возврат информации о состоянии или инициирование новых вызовов. На Asterisk было разработано много интересных приложений, использующих AMI в качестве основного интерфейса для Asterisk.
Эта глава также включает документацию по использованию файлов вызовов. Файлы вызовов Asterisk - это простой способ инициировать несколько вызовов. Как только объем исходящих вызовов увеличивается или ваши потребности становятся более сложными, вы можете перейти к использованию AMI. На самом деле, мы находим файлы вызовов достаточно полезными, так что сначала поговорим о них.
Файлы вызовов
Обычно для инициализации вызовов используется AMI, но во многих ситуациях проще использовать файлы вызовов. Файл вызова - это простой текстовый файл, описывающий вызов, который вы хотите совершить через Asterisk. Когда файл вызова помещается в каталог /var/spool/asterisk/outgoing, Asterisk немедленно обнаружит, что файл был помещен туда, и обработает вызов.
Asterisk поставляется с образцом файла вызова, который вы найдете в ~/src/asterisk-15.<TAB>/sample.call (или там, где находится корневой каталог исходников Asterisk).
Ваш первый файл вызова
Для вашего первого файла вызова давайте создадим вызов между двумя вашими телефонами. Убедитесь, что хотя бы два ваших телефона зарегистрированы и работают. Для этого примера мы будем использовать SOFTPHONE_A
и SOFTPHONE_B
.
Создайте в домашнем каталоге следующий файл:
$ vim ~/call-file
Channel: PJSIP/SOFTPHONE_A
Extension: 103
Context: sets
Сделайте копию этого файла (так что вам не придется заново создавать его каждый раз, когда захотите запустить его):
$ cp ~/call-file docall
Измените владельца файла docall на asterisk
:
$ chown asterisk:asterisk docall
Переместите файл docall в каталог outgoing Asterisk.
$ sudo mv docall /var/spool/asterisk/outgoing
Иногда самый простой способ - лучший способ.
Вы, вероятно, обнаружите, что делаете несколько правок в исходном файле вызова. Вы можете просто переместить созданный файл, а не делать его копию, но тогда вам придется заново создавать его каждый раз, когда вы его редактируете, и это раздражает. Весь этот набор можно сохранить как однострочный и запустить следующим образом:
Попробуйте, и вы увидите, насколько это проще, чем каждый раз создавать и перемещать новый файл вызова. |
Предупреждение Использование |
Освойтесь с использованием файлов вызовов и вы обнаружите что они решают проблемы, которые в противном случае вам пришлось бы решать гораздо большим объемом работ.
Заметки о файлах вызова
Компонент Channel
файла вызова является обязательным. Обычно вызов, поступающий в Asterisk, инициируется конечной точкой (например, вы делаете вызов со своего телефона). В файле вызова это соединение должно происходить наоборот - Asterisk обращается к конечной точке, и только когда она отвечает, вызов может начаться. Планируйте соответственно.
Вы также должны указать Context
, в котором вызов начнется, как только первоначальный канал ответит. Это может быть полезно, так как это означает, что вы можете подключить вызов через контекст, который обычно недоступен для этого канала, но на практике мы бы предложили вам просто использовать тот же контекст, через который канал вошел бы в диалплан, если бы он инициировал вызов как обычно.
Расширение, конечно, также должно быть указано. Обычно это номер телефона, по которому нужно позвонить, но, конечно, это может быть любой допустимый добавочный номер в Context
.
Остальные параметры файла вызова являются необязательными и подробно описаны в файле ~/src/asterisk-15.<TAB>/sample.call и на веб-сайте Asterisk wiki.
AMI Быстрый старт
Этот раздел предназначен для того, чтобы как можно быстрее испачкать руки с помощью AMI. Во-первых, поместите следующую конфигурацию в /etc/asterisk/manager.conf:
; Включить AMI и указать ему принимать соединения только от localhost.
[general]
enabled = yes
webenabled = yes
bindaddr = 127.0.0.1
; Создайть аккаунт с именем "hello" и паролем "world"
[hello]
secret=world
read=all ; Получать все типы событий
write=all ; Разрешить этому пользователю выполнять все действия
Примечание Этот пример конфигурации настроен так, чтобы разрешить только локальные подключения к AMI. Если вы собираетесь сделать этот интерфейс доступным по сети, настоятельно рекомендуется использовать только протокол TLS. Использование TLS более подробно рассматривается далее в этой главе. |
Как только конфигурация AMI готова, включите встроенный HTTP-сервер, поместив следующее содержимое в /etc/asterisk/http.conf:
; Включить встроенный HTTP-сервер и слушайть только соединения на localhost.
[general]
enabled = yes
bindaddr = 127.0.0.1
Перезагрузите диспетчер и http-серверы из Asterisk CLI:
*CLI> manager reload
*CLI> module reload http
AMI через TCP
Существует несколько способов подключения к AMI, но наиболее распространенным является TCP-сокет. Мы будем использовать telnet
для демонстрации подключения AMI. Для этого нам нужно будет установить telnet
:
$ sudo yum -y install telnet
В этом примере показаны следующие шаги:
- Подключение к AMI через TCP-сокет на порту 5038.
- Вход в систему, используя действие
Login
. - Выполнение действия
Ping
. - Выход из системы с помощью действия
Logoff
.
Вот как это сделать с помощью telnet
:
$ telnet localhost 5038
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Asterisk Call Manager/4.0.3
Вы подключились, но он будет висеть на вас, если вы не подтвердите свою подлинность. Вставьте в окно telnet
следующее:
Action: Login
Username: hello
Secret: world
Обратите внимание, что после команд должна быть пустая строка (нажмите Enter после вставки всего, если ничего не происходит).
Response: Success
Message: Authentication accepted
Ладно, мы ему нравимся. Давайте выполним простую команду, чтобы убедиться, что он действительно говорит с нами:
Action: Ping
Response: Success
Ping: Pong
Все идет нормально. Мы просто уберемся и выйдем сейчас.
Action: Logoff
Response: Goodbye
Message: Thanks for all the fish.
Connection closed by foreign host.
Вы убедились что AMI принимает соединения через TCP-соединение.
AMI через HTTP
Также можно использовать AMI через HTTP. Мы будем выполнять те же действия что и раньше, но через HTTP вместо собственного TCP-интерфейса к AMI. АMI через HTTP подробно описаны в “AMI через HTTP”.
Примечание Учетные записи, используемые для подключения к AMI через HTTP, являются теми же учетными записями, настроенными в файле /etc/asterisk/manager.conf. |
В этом примере показано, как получить доступ к AMI по протоколу HTTP, войти в систему, выполнить действие Ping
и выйти из системы:
$ curl "http://localhost:8088/rawman?action=login&username=hello&secret=world" \
-c /tmp/tempcookie
Response: Success
Message: Authentication accepted
$ curl "http://localhost:8088/rawman?action=ping" -b /tmp/tempcookie
Response: Success
Ping: Pong
Timestamp: 1538871944.474131
$ curl "http://localhost:8088/rawman?action=logoff" -b /tmp/tempcookie
Response: Goodbye
Message: Thanks for all the fish.
Интерфейс HTTP для AMI позволяет интегрировать управление вызовами Asterisk в веб-службу.
Конфигурация
Раздел “AMI быстрый старт” показал очень простой набор конфигурационных файлов для начала работы. Существует много способов тонкой настройки конфигурации AMI.
manager.conf
Основной конфигурационный файл для AMI - это /etc/asterisk/manager.conf. Раздел [general]
содержит параметры, управляющие общей работой AMI. Любые другие разделы в manager.conf определяют учетные записи для входа в систему и использования AMI. Пример файла содержит подробные объяснения различных параметров и может быть найден в ~/src/asterisk-15<TAB>/configs/samples/manager.conf.sample.
Предупреждение Если вы собираетесь выставить свой AMI за пределы машины, на которой он работает, вам потребуется настроить подключение TLS. |
Конфигурационный файл manager.conf также содержит конфигурацию учетных записей пользователей AMI. Вы создаете учетную запись, добавляя раздел с именем пользователя в квадратных скобках. В каждом разделе [username]
есть параметры, которые могут быть установлены, которые будут применяться только к этой учетной записи. Файл ~/src/asterisk-15<TAB>/configs/samples/manager.conf.sample также содержит подробные объяснения каждого из этих параметров. Наш пользователь по имени [hello]
, имеет простейшую конфигурацию, которая позволяет все операции чтения и записи. Обычно следует создавать пользователей AMI, которые ограничены только действиями, необходимыми для их функционирования.
В разделе [username]
параметры read
и write
определяют к каким действиям и событиям диспетчера имеет доступ конкретный пользователь. На данный момент есть 20 из них: all
, system
, call
, log
, verbose
, agent
, user
, config
, command
, dtmf
, reporting
, cdr
, dialplan
, originate
, agi
, cc
, aoc
, test
, security
и message
. Вы увидите что файл manager.conf.sample содержит ссылку на каждый из них, относящийся к вашему выпуску (и, если какие-либо из них добавлены, которые не были перечислены здесь, они будут в файле примера).
Предупреждение Обратите особое внимание на разрешения |
http.conf
Как мы уже видели, интерфейс Asterisk Manager может быть доступен как по протоколу HTTP, так и по протоколу TCP. Для этого в Asterisk встроен очень простой HTTP-сервер. Все параметры, относящиеся к AMI, находятся в разделе [general] файла /etc/asterisk/http.conf.
Примечание Включение доступа к AMI по протоколу HTTP требует наличия /etc/asterisk/manager.conf и /etc/asterisk/http.conf. AMI должен быть включен в manager.conf с параметром |
Доступные опции будут найдены в вашем файле ~/src/asterisk-15<TAB>/configs/samples/http.conf.sample.
Обзор протокола
В AMI есть два основных типа сообщений: события диспетчера и действия диспетчера.
События диспетчера - это односторонние сообщения, посылаемые Asterisk клиентам AMI для сообщения о том, что произошло в системе (Рисунок 17-1).
Рисунок 17-1. События диспетчера
Действия диспетчера - это запросы от клиента к Asterisk для выполнения некоторого действия и возврата результата (Рисунок 17-2). Например, действие AMI инициирует запросы, чтобы Asterisk создал новый вызов, и, естественно, клиентскому приложению потребуются ответы от Asterisk, чтобы указать ход выполнения этого действия.
Рисунок 17-2. Действия диспетчера
Другие действия менеджера - это запросы данных. Например, есть действие - получить список всех активных каналов в системе: сведения о каждом канале доставляются как событие. Когда список результатов будет завершен, будет отправлено окончательное сообщение о том, что цель достигнута. См. Рисунок 17-3 для графического представления клиента, отправляющего этот тип управляющего действия и получающего список ответов.
Рисунок 17-3. Действия диспетчера возвращающие список данных
Кодировка сообщений
Все сообщения AMI, включая события, действия и ответы на действия, кодируются одинаково. Сообщения являются текстовыми, со строками, заканчивающимися возвратом каретки и символом перевода строки. Сообщение завершается пустой строкой:
Header1: This is the first header<CR><LF>
Header2: This is the second header<CR><LF>
Header3: This is the last header of this message<CR><LF>
<CR><LF>
Если вы запускаете тесты из telnet-клиента - это означает, что после последней строки инструкций вам нужно будет дважды нажать клавишу Enter.
События
События всегда имеют заголовок Event
и заголовок Privilege
. В заголовке Event
указывается имя события, а в заголовке Privilege
- уровни разрешений, связанные с данным событием. Любые другие заголовки, включенные в событие, являются специфичными для данного типа события. Вот вам пример:
Event: Hangup
Privilege: call,all
Channel: SIP/0004F2060EB4-00000000
Uniqueid: 1283174108.0
CallerIDNum: 2565551212
CallerIDName: Russell Bryant
Cause: 16
Cause-txt: Normal Clearing
CLI Asterisk включает в себя manager show events
и manager show event <event>
. Выполните эти команды в CLI Asterisk, чтобы получить список событий или узнать подробности конкретного события.
Не забывайте, что отличным справочником для всех вещей Asterisk, включая AMI, является официальная Asterisk wiki.
Действия
При выполнении действия необходимо включить заголовок Action
. Заголовок Action
определяет, какое действие выполняется. Остальные заголовки являются аргументами для действия и могут потребоваться или не потребоваться в зависимости от действия.
Чтобы получить список заголовков, связанных с определенным действием, введите в CLI Asterisk команду manager show command <Action>
. Чтобы получить полный список действий, поддерживаемых используемой версией Asterisk, введите manager show commands
.
Окончательный ответ на действие обычно представляет собой сообщение, содержащее заголовок Response
. Значение заголовка Response
будет Success
, если действие было выполнено успешно. Если действие не было успешно выполнено, то значение заголовка ответа будет Error
. Например:
Action: Login
Username: hello
Secret: world
Response: Success
Message: Authentication accepted
AMI через HTTP
Помимо собственного TCP-интерфейса, можно также получить доступ к AMI по протоколу HTTP. Программисты с имеющимся опытом написания приложений, использующие веб-API, скорее всего предпочтут его по сравнению с подключением TCP. В то время как интерфейс TCP предлагает только один тип структуры сообщений, AMI через HTTP предлагает несколько вариантов кодирования. Вы можете получать ответы в том же формате что и в TCP, в формате XML или в виде базовой HTML-страницы. Тип кодировки выбирается на основе поля в URL запросе. Варианты кодирования рассматриваются более подробно далее в этом разделе.
Аутентификация и обработка сессии
Существует два метода выполнения аутентификации против AMI через HTTP. Первый - это использование действия Login
, аналогичного аутентификации с помощью собственного интерфейса TCP. Это метод, который использовался в Примере быстрого запуска, как показано в AMI через HTTP.
После успешной аутентификации Asterisk предоставит файл cookie, который идентифицирует аутентифицированный сеанс. Вот пример ответа на действие Login
, которое включает в себя файл cookie сеанса от Asterisk:
$ curl -v "http://localhost:8088/rawman?action=login&username=hello&secret=world"
Второй вариант аутентификации - это HTTP-дайджест аутентификации. В этом примере запрошенный тип кодировки, основанный на URL-запросе, является rawman
. Чтобы указать, что следует использовать дайджест аутентификацию HTTP, префикс типа кодировки в URL-адресе запроса должен содержать a
:
$ curl -v --digest -u hello:world http://127.0.0.1:8088/arawman?action=ping
Кодирование /rawman (/arawman)
Тип кодирования rawman
- это то, что до сих пор использовалось во всех примерах AMI через HTTP в этой главе. Ответы, полученные от запросов, использующих rawman
, форматируются точно так же, как они были бы, если бы запросы были отправлены по прямому TCP-соединению к AMI.
curl -v "http://localhost:8088/rawman?action=login&username=hello&secret=world"
curl -v --digest -u hello:world http://127.0.0.1:8088/arawman?action=ping
Кодирование /manager (/amanager)
Тип кодировки manager
предоставляет ответ в простой HTML-форме. Этот интерфейс в первую очередь полезен для экспериментов с AMI:
$ curl -v "http://localhost:8088/manager?action=login&username=hello&secret=world"
$ curl -v --digest -u hello:world http://localhost:8088/amanager?action=ping
Кодирование /mxml (/amxml)
Тип кодировки mxml
предоставляет ответы на действия закодированные в XML:
$ curl -v "http://localhost:8088/mxml?action=login&username=hello&secret=world"
$ curl -v --digest -u hello:world http://localhost:8088/amxml?action=ping
События диспетчера
При подключении к собственному интерфейсу TCP для AMI события доставляются асинхронно. При использовании AMI через HTTP необходимо получить события путем опроса для них. Вы получаете события по протоколу HTTP, выполняя действие WaitEvent
. В следующем примере показано, как события могут быть извлечены с помощью действия WaitEvent
. Шаги такие:
- Запустите сеанс HTTP AMI с помощью действия
Login
. - Зарегистрируйте SIP-телефон на Asterisk, чтобы создать событие.
- Извлеките событие с помощью действия
WaitEvent
.
Взаимодействие выглядит следующим образом:
$ wget --save-cookies cookies.txt \
> "http://localhost:8088/mxml?action=login&username=hello&secret=world" -O -
<ajax-response>
<response type='object' id='unknown'>
<generic response='Success' message='Authentication accepted' />
</response>
</ajax-response>
$ wget --load-cookies cookies.txt \
< "http://localhost:8088/mxml?action=waitevent" -O -
<ajax-response>
<response type='object' id='unknown'>
<generic response='Success' message='Waiting for Event completed.' />
</response>
<response type='object' id='unknown'>
<generic event='PeerStatus' privilege='system,all'
channeltype='SIP' peer='SIP/0000FFFF0004'
peerstatus='Registered' address='172.16.0.160:5060' />
</response>
<response type='object' id='unknown'>
<generic event='WaitEventComplete' />
</response>
</ajax-response>
Вам потребуется разработать механизмы в вашем приложении чтобы гарантировать что буферизованные события часто опрашиваются.
Пример использования
Большая часть этой главы до сих пор обсуждала концепции и конфигурацию, связанные с AMI. В этом разделе приведены некоторые примеры использования.
Инициирование вызова
AMI имеет действие Originate
, которое можно использовать для инициирования вызова. Многие из принятых заголовков совпадают с параметрами, размещенными в файлах вызовов. В Таблице 17-1 перечислены заголовки, принятые действием Originate
.
Таблица 17-1. Заголовки для действия Originate
Параметр | Пример значения | Описание |
---|---|---|
ActionID |
a3a58876-f7c9-4c28-aa97-50d8166f658d |
Этот заголовок принимается большинством действий AMI. Он используется для предоставления уникального идентификатора, который также будет включен во все ответы на действие. Это дает вам возможность определить с каким запросом связан ответ. Он важен, так как все действия, их ответы и события передаются по одному и тому же соединению (если только не используется AMI через HTTP). |
Channel |
SIP/myphone |
Этот заголовок является критическим и обязательно должен быть указан. Он описывает исходящий вызов, который будет инициирован. Значение имеет тот же синтаксис, что и аргумент канала для приложения Dial() в диалплане. |
Context |
default |
Этот заголовок используется для указания положения в диалплане, которое будет запущено после ответа на исходящий вызов. Заголовки Context , Exten и Priority должны быть использованы вместе. При использовании этих заголовков не следует использовать заголовки Application и Data . |
Exten |
s |
Смотри документацию по заголовку Context . |
Priority |
1 |
Смотри документацию по заголовку Context . |
Application |
ConfBridge |
Заголовки Application и Data можно использовать вместо заголовков Context , Exten и Priority . В этом случае исходящий вызов напрямую соединяется с одним приложением после ответа на вызов. |
Data |
500 |
Смотри документацию по заголовку Application . |
Timeout |
30000 |
Этот заголовок определяет, как долго (в миллисекундах) ждать ответа, прежде чем отказаться от исходящего вызова. Значение по умолчанию - 30000 миллисекунд (30 секунд). |
CallerID |
Matthew Jordan <(555) 867-5309> |
Этот заголовок можно использовать для указания идентификатора вызывающего абонента, используемого для исходящего вызова. |
Account |
someaccount |
Этот заголовок задает код учетной записи CDR для исходящего вызова. |
Variable |
VARIABLE=VALUE или FUNCTION(arguments)=VALUE |
Заголовок Variable может использоваться для задания как переменных канала, так и функций канала на исходящем канале. Его можно задать несколько раз. |
Codecs |
ulaw,alaw |
Этот параметр можно использовать для ограничения количества кодеков, разрешенных для исходящего вызова. Если этот параметр не указан, то набор кодеков, настроенных в файле конфигурации драйвера канала, будет по-прежнему учитываться. |
EarlyMedia |
true |
Если этот заголовок указан и установлен в true , исходящий вызов будет подключен к указанному добавочному номеру или приложению, как только появится какой-либо медиапоток. |
Async |
true |
Если этот заголовок задан и имеет значение true , то этот вызов будет инициирован асинхронно. Это позволит вам продолжить выполнение других действий на AMI-соединении во время обработки вызова. |
Самый простой пример использования действия Originate
через telnet
:
$ telnet localhost 5038
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Asterisk Call Manager/4.0.3
Как только соединение установлено Вам необходимо войти в систему.
Action: Login
Username: hello
Secret: world
Response: Success
Message: Authentication accepted
Теперь вы готовы инициировать свой звонок. Мы делаем практически то же самое что и с файлом вызова, только на этот раз с помощью AMI:
Action: Originate
Channel: PJSIP/SOFTPHONE_A
Context: sets
Exten: 103
Priority: 1
Вы должны услышать звонок SOFTPHONE_A
. Как только вы ответите на него, вызов будет сделан на SOFTPHONE_B
.
AMI больше не участвует в том что происходит. Вы можете отключиться, и вызов будет продолжен (оставьте его в данный момент, так как мы собираемся работать с текущим вызовом далее).
Action: Logoff
Response: Goodbye
Message: Thanks for all the fish.
Connection closed by foreign host.
Если вы уже повесили трубку - это не проблема. Вам просто нужно будет восстановить вызов, что, конечно же, вы можете сделать, просто позвонив по одному номеру с другого (101-103 или как пожелаете).
Перенаправление вызова
Перенаправление (или transferring - передача) вызова из AMI - еще одна функция, заслуживающая упоминания. Действие AMI Redirect
можно использовать для отправки одного или двух каналов на любой другой модуль в диалплане Asterisk. Если вам нужно перенаправить два канала, которые соединены вместе, сделайте это с обоими одновременно. В противном случае, как только один канал будет перенаправлен, другой будет отключен.
Важно понимать, что каналы Asterisk не существуют до тех пор, пока не будет выполнен вызов. Имя, которое мы все считаем именем канала (например, Инициируйте вызов, а затем просмотрите Событие Вам нужно будет отслеживать эти имена каналов, если хотите правильно выполнять действия по текущим вызовам. Как только вызов заканчивается, канал уничтожается. Новому вызову, использующему ту же конечную точку, будет присвоено другое имя канала. Одно определение канала может поддерживать несколько вызовов (например, возможны несколько вызовов на телефон), и именно поэтому имя канала отличается от определения канала. |