К основному контенту

Автообзвон (auto-dial out) и обратный звонок (callback) с использованием AGI

Автообзвон

Есть задачи реализация которых возможна через автоматический обзвон. Например ?
Например вы сис.админ, у вас есть локальная сеть и куча оборудования в ней, но вы же не 24/7 на работе, а раз так, то в сети может что то произойти, например событие в системе мониторинга, а вас нет на рабочем месте. Конечно можно отправлять себе SMS, если такая вожможность есть, а имея сервер Asterisk можно и позвонить и самому себе рассказать что же случилось ;)
Или вам необходима система callback, что бы позвонив на номер заведенный на Asterisk, вы могли получить с него обратный звонок и набрать другой номер.
Итак, считаем что у вас у уже есть установленный и настроенный сервер Asterisk, который имеет выход в город.
Что бы совершить автоматический звонок нам потребуется следующие вещи:
  • сформировать call файл
  • иметь в диалплане (dialplan (определяется в /usr/local/etc/asterisk/extensions.conf)) контекст (context) со списком действий
Начнем с call файла, его основной синтаксис:
  • Channel: <channel> — Какой канал использовать для звонка
  • CallerID: «name» <number> — Установить Caller ID, проще сказать тут мы можем выставить АОН (номер с которого мы звоним).
  • MaxRetries: <number> — Максимальное кол-во попыток дозвониться, по умолчанию 0, что является одной попыткой.
  • RetryTime: <number> — Время в секундах между попытками дозвона, по умолчанию 300 (5 минут).
  • WaitTime: <number> — Сколько секунд ожидаем поднятия трубки, по умолчанию 45.
  • Context: <context-name> — Какой контекст используем из extensions.conf
  • Extension: <ext> - Какой экстеншн используем в выбранном контексте (так же в extensions.conf).
  • Priority: <priority> — С какого приоритета начинаем.
Я привел не полный список, полный список доступен тут. Лично я, для каждого номера, создаю свой контекст в extensions.conf.
Соответственно зная синтаксис мы теперь сможем сформировать call файл, на примере звонка через SIP канал:
Channel: SIP/89161112233@sip-provider
Callerid: 9998877
MaxRetries: 2
RetryTime: 20
WaitTime: 60
Context: outgoing_to_89161112233
Extension: s
Priority: 1
Для тех кто в танке :) разберем call файл построчно:
  • позвонить на SIP номер 89161112233 через провайдера sip-provider (имя из /usr/local/etc/asterisk/sip.conf для выхода в город)
  • использовать АОН 9998877
  • Максимальное кол-во попыток дозвона 2
  • Пауза между попытками 20 секунд
  • Ожидать поднятия трубки 60 секунд
  • Использовать контекст (context) с именем outgoing_to_89161112233
  • Начинать с экстеншена (ext) s
  • И начинать с приоритета 1 в экстеншене s
Сформировав call файл, его необходимо положить в папку:  /var/spool/asterisk/outgoing/ сервер Asterisk обнаружив в этой папке файл сразу же попытается отработать его.
Сразу скажу, что можно и задержать обработку файла, т.е. задержать исх. звонок и отложить его на определенное вами время.
Сервер Asterisk смотрит на дату создания call файла и если изменить дату создания на дату в будущем, то Asterisk не будет отрабатывать call файл, пока не наступит эта самая дата.
Как это сделать ? Очень просто, для этого воспользуемся командой touch, которая есть во всех unix системах.
После того как создали сам call файл берем и меняем дату его создания, шаблон даты такой:
ГОДМЕСЯЦДЕНЬЧАСЫМИНУТЫ.СЕКУНДЫ (внимание: перед секундами стоит символ точки, это так и нужно, а не опечатка).
Для примера выставим дату в будущем, скажем это 09.07.2010 19:18:55:
/usr/bin/touch -t 1007091918.55 /path/to/call/file.call
Дата создания call файла изменится и если переместить файл в /var/spool/asterisk/outgoing/, то соответственно Asterisk его не обработает до тех пор пока не наступит выставленная дата.
Совет: генерить call файл лучше в какой то tmp директории, выполнять над ними все необходимые и действия и затем мувить (переносить) в /var/spool/asterisk/outgoing/.
Теперь посмотрим на сам контекст (context), для системы мониторинга он может быть таким:
[outgoing_to_89161112233]
exten => s,1,Answer
exten => s,n,Wait(1)
exten => s,n,Background(/usr/local/share/asterisk/sounds/monitoring/welcome)
exten => s,n,Background(/usr/local/share/asterisk/sounds/monitoring/Down)
exten => s,n,Background(/usr/local/share/asterisk/sounds/monitoring/provider-a)
exten => s,n,Background(/usr/local/share/asterisk/sounds/monitoring/bye)
exten => s,n,hangup
Исходя из данного контекста Asterisk дозвонившись до 89161112233 (человек взял трубку) выполнит следущее:
  • поднимет трубку со своей стороны
  • секунду подождет
  • проиграет записанные вами звуковые файлы (полные пути к файлам указаны)
  • повесит трубку
Как записать голосовые файлы (то что вы будете проигрывать) вы можете узнать из этой статьи.
После того как Asterisk полностью отработает call файл, он его удаляет из директории /var/spool/asterisk/outgoing/.
Специальный экстеншен ‘failed
Если на вызов не ответили, и существует стандартный экстеншен с именем failed и команда с приоритетом 1 в заданном (в .call файле) контексте, управление будет передано этой команде.
exten => failed,1,Set(NumberDialed=${CUT(PassedInfo,,1)})
exten => failed,n,SetCDRUserField(${NumberDialed})
[Добавлено 11.02.2011]
Может появится ещё одна задача, а именно: если при автодозвоне трубку так и не подняли, то сразу набрать другой номер. Пример такой конструкции:
  • сначала набираем внутренний SIP  номер (6003) человека
  • если внутренний SIP номер не отвечает/занят/недоступен — набираем мобильный номер
Кажется, ну что может быть проще, написать:
exten => failed,1,Dial(SIP/89161112233@sip-provider)
А вот тут то и выяснилось, что не все так просто. На такое действо вы в консоле (выставив core set verbose 3) увидите подобное сообщение:
— Executing [failed@dialsip:1] Dial(«OutgoingSpoolFailed», «SIP/6003″) in new stack
[Feb 11 16:57:44] WARNING[94371]: channel.c:3441 ast_request: No translator path exists for channel type SIP (native 65535) to 0
[Feb 11 16:57:44] WARNING[94371]: app_dial.c:1296 dial_exec_full: Unable to create channel of type ‘SIP’ (cause 58 — Bearer capability not available)
== Everyone is busy/congested at this time (1:0/0/1)
== Auto fallthrough, channel ‘OutgoingSpoolFailed’ status is ‘CHANUNAVAIL’
[Feb 11 16:57:54] NOTICE[94371]: pbx_spool.c:356 attempt_thread: Call failed to go through, reason (8) Congestion (circuits busy)
Усе… приехали…. Лазая по результатам поиска в гугле я натыкался на сообщения:
Канал получается OutgoingSpoolFailed и именно в него пытается звонить и Dial и играть Playback. Как мне находясь в failed сделать звонок на SIP и проиграть сообщение?
Собственно точно такой же вопрос задавал себе и я сам, но ответа на него ни в Инете ни у меня не было.
Так же как и я народ пытался реализовать подобное через failed c Goto, System и т.п., но результат получался таким же — никаким :(
Получается из starndart extention failed сделать набор (Dial) другого номера не получится…..
Я уже было подумал, что не судьба и мне придется ловить DIALSTATUS, передавать его AGI скрипту (который ещё и писать придется) и тот уже будет решать что с этим делать (создавать новый call файл или ещё что то), но тут родился ещё один вариант:
core*CLI> core show channeltypes
Type        Description                              Devicestate  Indications  Transfer
----------  -----------                              -----------  -----------  --------
Skinny      Skinny Client Control Protocol (Skinny)  no           yes          no
SIP         Session Initiation Protocol (SIP)        yes          yes          yes
Console     OSS Console Channel Driver               no           yes          no
MGCP        Media Gateway Control Protocol (MGCP)    yes          yes          no
Local       Local Proxy Channel Driver               yes          yes          no
Zap         DAHDI Telephony Driver w/PRI             no           yes          no
Agent       Call Agent Proxy Channel                 yes          yes          no
----------
7 channel drivers registered

core*CLI> core show channeltype Local
-- Info about channel driver: Local --
Device State: yes
Indication: yes
Transfer : no
Capabilities: -1
Digit Begin: yes
Digit End: yes
Send HTML : yes
Image Support: no
Text Support: yes
core*CLI>
Создаем call-файл уже чуть другого содержания:
Channel: Local/1@autocaller
Callerid: 9998877
Context: outgoing_to_89161112233
Extension: s
Priority: 1
Где autocaller это название контекста, а 1-ца это приоритет в этом контексте. Соответственно делаем в extensions.conf этот контекст:
[autocaller]
exten => 1,1,Macro(call6003user,6003)
Тем самым мы как бы набираем уже не номер, а конкретный exten  в контексте и в нем передаем вызов в макро, создаем и макро, которое используется в этом контексте:
[macro-call6003user]
exten => s,1,Dial(SIP/${ARG1},15,t)
exten => s,n,Goto(s-${DIALSTATUS},1)
exten => s-NOANSWER,1,Dial(SIP/89161112233@sip-provider)
exten => s-NOANSWER,n,VoiceMail(${ARG1},u)
exten => s-NOANSWER,n,Hangup()
exten => s-BUSY,1,VoiceMail(${ARG1},b)
exten => s-BUSY,n,Hangup()
exten => _s-.,1,Goto(s-NOANSWER,1)
Собственно этот макро дает нам возможность уже управлять куда и в каком случае пойдет вызов. Пример конечно «грубый», но главное ведь принцип, а дальше уже ваше творчество ;)
И вот таким образом мы получаем искомый результат.
[Конец добавленного 11.02.2011]

Callback

Он работает по тому же принципу, что и описанный выше автообзвон, за некоторыми исключениеми:
  • генерация call файла происходит при звонке человека на номер выделенный под callback.
  • в контексте (context) мы не просто проигрываем звуковые, а предлагаем пользователю ввести номер, на который он хочет позвонить
Что нам потребуется в этом случае:
  • выделить номер для callback и создать контекст (context) под него в  extensions.conf.
  • «передать»  звонок в AGI скрипт, который проверит АОН звонящего на предмет разрешен ли этому номеру callback
  • если  callback разрешен, то сформирует call файл.
AGI — это Asterisk Gateway Interface.
Asterisk Gateway Interface это возможность расширить функционал Asterisk`а с помощью использования скриптов на многих языках программирования. Например Perl, PHP, C, Pascal, Bourne Shell.
Начнем с номера, допустим это будет гор. номер 84955556677. Добавим в extensions.conf в контекст (context) куда поступают все входящие звонки:
exten => 84955556677,1,AGI(sms-callback.php)
exten => 84955556677,n,Hangup()
Т.е. звонок на экстеншн (ext) 84955556677 будет передан AGI скрипту callback.php, а затем звонок будет сразу же завершен.
AGI скрипты для Asterisk располагаются в директории  /usr/local/share/asterisk/agi-bin/.
Почему скрипт на PHP ? PHP был выбран для AGI, т.к. callback является неотъемлимой частью проекта написанного на PHP + MySQL, потому решили и AGI пусть на PHP будет.
Сам скрипт: http://subnets.ru/files/callback.php.txt
Что происходит с скрипте ?
  • определяем необходимые переменные
  • получаем данные от Asterisk`а.
  • логи, куда же без них. В лог мы поместим все то, то получил AGI скрипт от Asterisk`а, это для дебага, потом можно выключить логирование.
  • проверяем номер (АОН) звонящего на доступ к callback
  • смотрим нет ли уже call файла для  данного номера, если нет, то создаем его
В переменной $agivar['agi_callerid'] и содержится АОН (телефонный номер) звонящего переданного нам Asterisk`ом, что в других передаваемых переменных вы сможете увидеть в log файле.
Если установить $debug в ноль, то тем самым выключите логирование.
В массиве  $permit_num содержатся номера для которых разрешен callback.
Ну и осталось дело за малым, а именно что бы был контекст (context) под звонящий номер в extensions.conf.
Допустим наш callback номер 84955556677 набрали с мобильного 89105647899 и ему разрешен callback (номер84955556677 указан в массиве  $permit_num в скрипте), то его контекст может выглядеть вот так:
[outgoing_to_89105647899]
exten => s,1,Set(CallbackNumTries=0)
exten => s,n,Set(CALLERID(num)="9998877")
exten => s,n(start),Background(vo-vvedite-ton-num-abonent)
exten => s,n,WaitExten(10)
exten => 100,1,Dial(SIP/8495${EXTEN}@sip-provider,120)
exten => _XXXXXXX,1,Dial(SIP/8495${EXTEN}@sip-provider,120)
exten => _8X.,1,Dial(SIP/${EXTEN}@sip-provider,120)
exten => i,1,Set(CallbackNumTries=$[${CallbackNumTries} + 1])
exten => i,n,Playback(vo-nomer-nabran-ne-verno)
exten => i,n,GotoIf($["${CallbackNumTries}" < "3"]?s|start)
exten => i,n,Playback(vo-dosvidaniya)
exten => t,1,Set(CallbackNumTries=$[${CallbackNumTries} + 1])
exten => t,n,GotoIf($["${CallbackNumTries}" < "3"]?s|start)
exten => t,n,Playback(vo-dosvidaniya)
exten => t,n,Hangup()
  • устанавливаем число попыток в ноль
  • выставляем АОН (под исх. звонок)
  • проигрываем записанный текст: «переведите ваш телефон в тональный набор…. бла… бла.. бла…»
  • 10 сек. ждем от человека набора номера
  • указываем возможный набор номеров: 100 (узнать время ;) ), 7-ми значный номер, 8-рка и далее сколько угодно цифр
  • даем человеку три попытки на набор номера, если истек таймаут набора номера или номер был набран не верно, то человеку это озвучивается и кол-во попыток увеличивается на 1-цу и наше мини голосовое меню начинается сначала (возврат к метке start)
  • если кол-во попыток исчерпано, то Asterisk вешает трубку
Источник http://subnets.ru/blog/?p=1444

Комментарии

Популярные сообщения из этого блога

Автообзвон на Asterisk (FreePBX)

Syntax of call files Specify where and how to call Channel : <channel>: Channel to use for the call. CallerID : «name» <number> Caller ID, Please note: It may not work if you do not respect the format: CallerID: «Some Name» <1234> MaxRetries : <number> Number of retries before failing (not including the initial attempt, e.g. 0 = total of 1 attempt to make the call). Default is 0. RetryTime : <number> Seconds between retries, Don't hammer an unavailable phone. Default is 300 (5 min). WaitTime : <number> Seconds to wait for an answer. Default is 45. Account : Set the account code to use. If the call answers, connect it here: Context : <context-name> Context in extensions.conf Extension : <ext> Extension definition in extensions.conf Priority : <priority> Priority of extension to start with Set : Set a variable for use in the extension logic (example: file1=/tmp/to ); in Asterisk 1.0.x use

Настройка записи разговоров freepbx

1. Заходим на Web-интерфейс  2. Выбираем   « Панель пользователя» и вводим логин и пароль для входа(логин и пароль — это внутренний номер абонента). 3. Если правильный логин и пароль, то попадаем в интерфейс пользователя: Дата  — дата звонка; Время  — время звонка; Номер  — отображается телефонный номер   ( а под ним — внутренний номер   ), с которого был произведен звонок; Источник  — указывается внутренний номер; Назначение  — указывается внутренний номер, куда был послан звонок; Длительность  — указывается время в секундах, телефонного разговора; Монитор  — имеет две иконки:  — открывает флеш плеер для проигрывания записи разговора;  — предлагает сохранить запись разговора на жесткий диск. 3. Прослушивание записи разговоров может происходить в двух вариантах: Вариант 1 Выбираете интересующий Вас звонок и нажимаете на иконку  , после чего под строчкой звонка откроется полоска флеш-плеера, где можно будет управлять ходом прослушивания звукового файла: Ва

Запись и обслуживание разговоров в Asterisk FreePBX

Как и многие другие компании мы используем  FreePBX —  графический интерфейс для Астериск. Служба безопасности требует записывать все входящие и исходящие звонки , не проблема все делается просто: Заходим в админку http://sip.domain.local/admin/config.php , далее General Settings и делаем как у казанно у меня на скрине: Вот вроде и все , но если не следить за записями  они забьют все место на масиве. На помощь нам приходит bash =) , пишем скрипт который будет удалять записи старше 14 дней ( для службы безопасности такой срок устраивает) #!/bin/bash # Указываем директорию где расположены файлы RECORDINGS=/var/spool/asterisk/monitor # Указываем период за какой срок удалять файлы записи  RECORDINGEXPIRY=14 # Указываем за какой срок хранить логи LOGEXPIRY=365 # Дата DATE=`date` # Удаляем записи старше $RECORDINGEXPIRY дней find $RECORDINGS -mtime +$RECORDINGEXPIRY -exec rm -rfv > removal-$DATE.log # Удаляем логи старше $LOGEXPRY find . -mtime +$LO