
Asterisk callback
Обратные звонки
Звонить из роуминга дорого, поэтому мы заставим Астериск инициировать вызов на наш мобильный (вместе с которым мы греем ноги на пляже) и дать нам возможность позвонить «как будто мы дома». Хорошо, если наш тарифный план в роуминге дает возможность принимать входящие бесплатно, но сейчас речь не об этом.
Вводные данные: номер мобильного — 89007654321, номер Астериска — 84951230001, название провайдерского транка, с которого будет осуществлен обратный звонок — mytrunk1, название контекста, в котором находятся внутренние телефоны — localphones, название контекста, обрабатывающего входящие вызовы — default.
Для реализации используем проверку по условию GotoIf(), call-файлы и функцию DISA(). Call-файлы помещаются в /var/spool/asterisk/outgoing, но Астериск постоянно мониторит эту директорию и как только видит в ней файл с расширением .call — бросается его выполнять, поэтому создадим мы его в любой другой директории (в этом примере — в /var/spool/asterisk/).
У пользователя, от имени которого работает asterisk, должны быть полные права на .call файл.
~$ cd /var/spool/asterisk
/var/spool/asterisk$ touch 89007654321.call
/var/spool/asterisk$ nano 89007654321.call
Наполняем файл 89007654321.call:
Channel: SIP/mytrunk1/89007654321
MaxRetries: 1
RetryTime: 30
WaitTime: 30
Context: callback-dialer
Extension: s
Callerid: autodialer
Account: autodialer
Priority: 1
Разберем значения основных опций:
Channel: : Канал, который будет использоваться при наборе. MaxRetries: Количество повторных попыток набора. В нашем случае — если первая попытка окажется неудачной, Астериск повторит попытку ещё 1 раз. RetryTime: Количество секунд между попытками вызова. WaitTime: Количество секунд, которое Астериск ждёт ответа на вызов. Account: Поле account code в CDR. Context: Имя контекста, который обрабатывает вызов (в extensions.conf). Extension: Название экстеншена в указанном контексте. Priority: Номер операции экстеншена, с которого начинается обработка вызова после соединения.
Теперь идём в extensions.conf и добавляем контекст callback-dialer.
[callback-dialer]
exten => s,1,Answer()
exten => s,n,Wait(1)
exten => s,n,DISA(no-password,localphones)
exten => s,n,Hangup
Перечитываем диалплан (dialplan reload). На этом этапе Астериск ещё не умеет сам инициировать вызов, но уже можно проверить, что он дозванивается на мобильный и даёт возможность набрать номер также, как это делают внутренние абоненты. Для этого скопируем .call-файл в папку outgoing/
/var/spool/asterisk$ cp 89007654321.call outgoing/89007654321.call
Астериск обнаружит call-файл, найдёт в диалплане нужный контекст и совершит вызов. После поднятия трубки выполнится команда Answer(), затем Астериск подождет одну секунду, а следом включит функцию DISA(), т.е. в трубке появится гудок. В данном примере DISA не будет запрашивать пароль, а вызванный абонент окажется в том же контексте, что и внутренние телефоны и сможет осуществить набор по тем же правилам, что и все остальные абоненты. После завершения вызова Астериск удалит call-файл из папки outgoing/ (именно поэтому мы использовали cp, а не mv).
Теперь нам предстоит научить диалплан распознавать номер, на который нужно совершать обратный вызов. Эту функцию можно повесить на внутренний добавочный, но мы ведь не хотим платить даже за минуту в роуминге — поэтому в начало контекста, обрабатывающий входящие вызовы, вставим проверку А-номера. Если А-номер совпадает с заданным — функция GotoIf() перебросит вызов на экстеншен callback с номером операции 1, в котором Астериск через функцию System() выполнит копирование созданного заранее call-файла и завершит входящий вызов, параллельно начиная исходящий.
[default]
...
exten => 84951230001,1,GotoIf($[${CALLERID(num)}=89007654321]?callback,1)
...
exten => callback,1,System(cp /var/spool/asterisk/${CALLERID(num)}.call /var/spool/asterisk/outgoing/${CALLERID(num)}.call)
exten => callback,n,Hangup
Если же номер не совпал — продолжится его обычная обработка. А если для callback используется отдельный номер и нам не нужна дальнейшая обработка — можно вставить вторую метку и завершить звонок.
[default]
...
exten => 84951230001,1,GotoIf($[${CALLERID(num)}=89007654321]?callback,1:reject)
exten => 84951230001,n(reject),Hangup
...
exten => callback,1,System(cp /var/spool/asterisk/${CALLERID(num)}.call /var/spool/asterisk/outgoing/${CALLERID(num)}.call)
exten => callback,n,Hangup
В целом, схема не сложна в реализации, если мобильных номеров много — можно прикрутить использование базы данных или чтение А-номеров из файла, а копирование созданных заранее call-файлов заменить на их автоматическую генерацию.