[general]
enabled = yes
port = 5038
bindaddr = 0.0.0.0
[1cami] ;
secret=PASSWORD1cami
deny=0.0.0.0/0.0.0.0
permit=0.0.0.0/0.0.0.0
; Достаточно ограниченного набора прав.
read=call
write=originate
Далее необходимо в CLI консоли Asterisk выполнить команду:
module reload manager
Для подключения будем использовать средства telnet:
~ # telnet 127.0.0.1 5038
Asterisk Call Manager/1.2
Как только появится приглашение “Asterisk Call Manager”, можно вводить команды. Первой командой должна быть авторизация.
Action: Login
Username: 1cami
Secret: PASSWORD1cami
Завершением ввода команды служит пустая строка. В случае успеха, получаем ответ:
Response: Success
Message: Authentication accepted
Базовый пример Originate
- Channel — Имя канала. Формат type/identifier. Type — тип канала, в зависимости от используемого драйвера SIP / IAX2 / DAHDI
- Context — Имя контекста для совершения вызова. Следует использовать совместно с параметрами Exten и Priority
- Exten — номер телефона, определенный в контексте «Context»
- Priority — Приоритет, позиция в Context, с которой начнеться обработка вызова
- Timeout — Таймаут в милисекундах. Если инициатор исходящего звонка не ответил, вызов будет завершен
- CallerID — значение callerid для исходящего звонка. Формат «ИмяСотрудника <НомерТелефона>»
- Variable — установка переменных для порожденных Originate каналов
- Account — Значение поля accauntcode для исходящих вызовов
- Application — команда dialplan, которая будет выолнена, используется совместно с параметром «Data»
- Async — признак асинхронного выполнения команды. Если установлен в значение «1», результат будет возвращен в пакете типа «Event» с именем «OriginateResponse»Data — Параметры команды dialplan
- ActionID — идентификатор запроса, полезно использовать при несколькоих одновренменных асинхронных запросах. Позволяет сопоставить результат с исходных запросом
Коды ответа «Event» с именем «OriginateResponse»
- 0 = Номер не найден в Context
- 1 = Нет ответа (no answer)
- 4 = Успешное выполнение (answered)
- 8 = Перегрузка или абонент не доступен (congested or not available)
Рассмотрим инициацию вызова с SIP канала 104 на номер 74952293042 в контексте from-internal:
Action: Originate
Channel: SIP/104
Context: from-internal
Exten: 74952293042
Priority: 1
Callerid: 104
Variable: SIPADDHEADER="Call-Info:\;answer-after=0"
В результате этой команды, зазвонит внутренний телефон, связанный с каналом SIP/104. После поднятия трубки, вызов пойдет на номер 74952293042 в контекст from-internal, приоритет 1.
В некоторых случаях удобно совмещать исходящий вызов с intercom, для этого следует задействовать параметр Variable.
Для Cisco, Linksys, Yealink и некоторых программных телефонов, подойдет установка переменной “SIPADDHEADER” в значение: "Call-Info:\;answer-after=0"
Допустим, на рабочем месте используется телефон Linksys. В результате Originate, сработает автоматический ответ на вызов, на телефоне, связанном с каналом SIP/104.
Перехват вызова
Все слышали о функции перехвата вызова, поступившего на соседний телефонный аппарат.
Обычно функция реализуется “старкодом” *8.
Для реализации перехвата, в dialplan можно задействовать приложение PickUp или PickupChan, сети довольно много примеров использования.
Как организовать эту функцию средствами AMI?
Для захвата вызова можно воспользоваться командой Originate. У нее есть два интересных параметра:
- Application — приложение, которое должно быть запущено
- Data — данные приложения
Опишем пример перехвата вызова, поступившего на sip аккаунт 104:
Action: Originate
Channel: SIP/104
Application: PickupChan
Data: SIP/104-0000003c
Priority: 1
Callerid: 104
Variable: SIPADDHEADER="Call-Info:\;answer-after=0"
Особенность этого Originate — нет необходимости описывать параметр «context».
Но появляется потребоность отслеживать каналы, которые мы можем перехватить. В данном примере канал описан как «SIP/104-0000003b».
Отслеживать появление новых каналов возможно в event "Newstate", где "ChannelState" установлено в значение «5» (Ringing). Ниже пример event:
Event: Newstate
Privilege: call,all
Channel: SIP/104-0000003c
ChannelState: 5
ChannelStateDesc: Ringing
CallerIDNum: 104
CallerIDName: Default Extension
ConnectedLineNum: 104
ConnectedLineName:
Uniqueid: askozia-1438348824.146
Как только поступит event "Newstate", где "ChannelState" установлено в значение «6» (Up) — на вызов уже ответили:
Event: Newstate
Privilege: call,all
Channel: SIP/104-0000003c
ChannelState: 6
ChannelStateDesc: Up
CallerIDNum: 104
CallerIDName: Default Extension
ConnectedLineNum: 104
ConnectedLineName:
Uniqueid: askozia-1438348824.146
Внимательный читатель заметит в примере некоторую несуразицу:
Action: Originate
Channel: SIP/104
Application: PickupChan
Data: SIP/104-0000003b
Ошибки нет. Вызов выполняем с Channel SIP/104, PickupChan выполняем для канала SIP/104-0000003b. То есть для своего же канала.
Прокомментирую на примере
Эту функцию мы запустили в повседневное использование. На моем рабочем месте установлен IP телефон. К телефону подключена гарнитура.
- Мне поступает входящий вызов;
- Жму кнопку «Ответить на вызов» в нашем CTI приложении;
- Выполняется описанный выше пример originate;
- Благодаря установленному «SIPADDHEADER» происходит автоответ;
- Телефон выполняет исходящий звонок и «пикапит» вызов.
Физически, я не поднимаю трубку телефона. Общаюсь с клиентом по гарнитуре. Руки свободны — профит на лицо.
Прослушать запись разговора
В некоторых случаях удобно прослушать запись разговора с телефонного аппарата в виде обратного звонка. На наш номер 104 поступит вызов. При ответе мы услышим запись разговора.
Пример AMI:
Action: Originate
Channel: SIP/104
Application: Playback
Data: /storage/usbdisk1/test_file
Priority: 1
Callerid: Playback
Variable: SIPADDHEADER="Call-Info:\;answer-after=0"
Используется приложение "Playback", в качестве данных передаем полное имя файла без расширения "/storage/usbdisk1/test_file".
Подслушать разговор
Для обучения новых сотрудников мы начали использовать необычный подход. Каждый стажер может подслушивать / прослушивать разговоры своего куратора. Благодаря этому, сотрудник быстрее начинает понимать, как построить разговор с клиентом.
В этом случае мы используем приложение "ChanSpy":
Action: Originate
Channel: SIP/104
Application: ChanSpy
Data: SIP/105,qx
Priority: 1
Callerid: Spy-105 <105>
Variable: SIPADDHEADER="Call-Info:\;answer-after=0"
- q — “тихий режим”, присоединение к разговору не анонсируется в разговор.
Присоединиться к разговору
В некоторых случаях куратору необходимо присоединиться к разговору и “вырулить” ситуацию. В этом случае используем следующий пример:
Action: Originate
Channel: SIP/104
Application: ChanSpy
Data: SIP/105,qBx
Priority: 1
Callerid: Spy-105 <105>
Variable: SIPADDHEADER="Call-Info:\;answer-after=0"
- B — оба канала могут слышать присоединившегося абонента
Режим суфлера
Куратор может присоединиться к разговору и подсказывать стажеру:
Action: Originate
Channel: SIP/104
Application: ChanSpy
Data: SIP/105,wx
Priority: 1
Callerid: Spy-105 <105>
Variable: SIPADDHEADER="Call-Info:\;answer-after=0"
- w — режим шепота, присоединившегося абонента будет слышать только канал, за которым «шпионим»
Заключение
Описанные команды отлично вписываются в CTI приложения и значительно могут улучшить удобство работы и эффективность сотрудников.
При разработке я рекомендую обратить внимание на проекты PAMI, NAMI и Shift8.
Надеюсь эта статья поможет в понимании работы команды originate, что позволит сделать ваши CTI приложения более функциональными.
Комментарии (11)
Nokin
10.09.2015 12:00Спасибо, Алексей. Вы пишите хорошо и интересно. Я в свое время делал проект с использованием AMI. На тот момент не смог реализовать функцию hold (постановка на удержание). Не знаете, можно ли это реализовать на ami сейчас?
boffart
16.09.2015 17:41Спасибо за отзыв. Я в нашем проекте воспользовался парковкой вызова.
Кратко алгоритм и пример:
Action: Park Channel: SIP/104-000001ce Parkinglot: Timeout: 30000
При этом, "Parkinglot" не указывать. Вызов будет помещен на свободный слот.
"Timeout" — через указанное время вызов вернется обратно.
Далее анализировать event:
- "ParkedCall" — тут можем понять на какой слот попал наш клиент.
- "UnParkedCall" и "ParkedCallGiveUp" — event оповещяет о завершении парковки.
Снять с такого «удержания» возможно позвонив на слот парковки, простой "originate".
simplit
23.09.2015 15:56Многие примеры, которые вы привели, работать не будут, из-за лишнего параметра Priority
Параметр Priority используется только вместе с Context, Exten
Команда Originate ответит вам «extension not found»
текст примераAction: Originate
Channel: SIP/104
Application: PickupChan
Data: SIP/104-0000003c
Priority: 1
Callerid: 104
Variable: SIPADDHEADER=«Call-Info:\;answer-after=0»boffart
24.09.2015 09:53Прошу описать детали, на какой версии Asterisk проявляется? Есть ли ссылка на более подробную документацию. Не сталкивался с описанной ситуацией.
Все примеры из текущей статьи тестировалась на Asterisk 10.9.0.
Кроме того, используются в реальном проекте.
Версии Asterisk — начиная с 1.8 и заканчивая 13.
На некоторых АТС было замечено поведение — если не указан "Priority", то originate завершается с ошибкой.simplit
24.09.2015 15:58Документация есть на официальном Wiki
Вот цитата:
Priority — Priority to use (requires Exten and Context)
Насколько я помню, так было всегда — еще с версии 1.4 и вряд ли это изменится.
Упрощенно, Priority — это номер строки в описании экстена. А сам экстен не располагается в вакууме — ему нужен контекст. Примере ниже 1,2,4 — это и есть Priority
Пример с Asterisk-WikiWithin each extension, there must be one or more priorities. A priority is simply a sequence number. The first priority on an extension is executed first. When it finishes, the second priority is executed, and so forth.
exten => 6123,1,do something
exten => 6123,2,do something else
exten => 6123,4,do something differentsimplit
24.09.2015 16:06+1Забыл добавить к предыдущему посту, что сама статья — хорошая, важная и нужная. Спасибо за статью
boffart
24.09.2015 16:43Спасибо за комментарий. Обязательно перепроверим.
Priority — Priority to use (requires Exten and Context)
Да, с этим знаком, доку читал.
Я на текущий момент не могу привести точный пример, но был случай с одной из станций, где без этого параметра не работала команда.
Подумайте, какой смысл в Priority, если нет ни экстена, ни контекста
От части согласен с Вами, но в моем понимании свойство просто игнорируется если не назначены "Exten" и "Context".
у вас же не совсем Астериск, у вас его форк — Аскозия
Помимо Askozia наше работает и с прочими атс:
- MyPBX U серии (там кстати Asterisk 1.6 версии), это особый случай, не все примеры описанные выше применимы.
- АТС на базе Asterisk с 1.8 по 13 версии
nooze
хорошая статья, пришлось как раз все это постигать по кусочкам месяца два назад для нового проекта ) жаль тогда этого матерала не было
хороший проект PAMI (php ami) хотя очень скудная документация (можно сказать её нет) но пользоваться все равно удобно
boffart
Спасибо. PAMI мне понравился, прост в использовании, заслуживает внимания. Документации не много, согласен.
AlexGx
У PAMI скудная документация, но это компенсируется большим кол-вом примеров и официальной докой астера. А вообще какие то простые вещи можно реализовать через fsock.
nooze
Через fsock можно, но у PAMI мне понравился обширный вывод DEBUG информации, столько всего я через fsock вытащить в читабельном виде не смог, это сильно помогло в поиске проблемы когда originate не проходил