Звонить из роуминга дорого, поэтому мы заставим Астериск инициировать вызов на наш мобильный (вместе с которым мы греем ноги на пляже) и дать нам возможность позвонить «как будто мы дома». Хорошо, если наш тарифный план в роуминге дает возможность принимать входящие бесплатно, но сейчас речь не об этом.
Вводные данные: номер мобильного — 89007654321, номер Астериска — 84951230001, название провайдерского транка, с которого будет осуществлен обратный звонок — mytrunk1, название контекста, в котором находятся внутренние телефоны — localphones, название контекста, обрабатывающего входящие вызовы — default.
Для реализации используем проверку по условию GotoIf(), call-файлы и функцию DISA(). Call-файлы помещаются в /var/spool/asterisk/outgoing, но Астериск постоянно мониторит эту директорию и как только видит в ней файл с расширением .call — бросается его выполнять, поэтому создадим мы его в любой другой директории (в этом примере — в /var/spool/asterisk/). PS (у пользователя, от имени которого работает 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-файлов заменить на их автоматическую генерацию.