Asterisk Dialplan - extensions.conf
Диалплан направляет каждый звонок от его источника, с помощью приложений (Dial, Voicemail, Background, ConfBridge и тд), в пункт назначения.
Наиболее важным для понимания Asterisk является план набора (dialplan). Все вызовы, будь-то голосовая почта, конференция, меню автосекретаря или вызов телефона, определяются логикой и концепцией диалплана.
Настройка производится в файле /etc/asterisk/extensions.conf .
Введение в расширения (extensions) и контексты (context)
Каналам назначаются контексты. Контексты определяют правила набора для каналов
План набора состоит из одного или нескольких контекстов. Каждый контекст это просто набор расширений (екстеншенов). Каждый екстеншен в контексте имеет уникальное имя.
Контексты ипользуются для выполнения основных функций АТС:
- Безопасность: Можно разрешить междугородные/международные вызовы только конкретным абонентам.
- Маршрутизация вызовов: Маршрутизация вызовов в зависимости от номера абонента.
- Автосекретарь: Проигрывание приветствия и приглашение ввести добавочный номер.
- Многоуровневые голосовые меню: Голосовые меню для службы поддержки, отдела продаж и т.д.
- Авторизация: Запрос пароля для доступа к некоторым екстеншенам.
- Обратный вызов: Позволяет уменьшить затраты на междугородние/международные вызовы.
- Списки доступа: Занесение в черные списки надоедливых абонентов, не давая им возможности связаться с Вами.
- Виртуальные АТС: Вы можете создать «виртуальную АТС» в пределах Вашей основной АТС.
- Дневной/Ночной режим работы: Вы можете изменять поведение Вашей АТС в зависимости от времени суток.
- Макросы: Можно создавать скрипты для решения повторяющихся задач в плане набора.
Что такое екстеншен?
В традиционных АТС екстеншен связан с интерфейсом (портом). В Asterisk екстеншен определяется как перечень приложений (applications) и их аргументов, выполняемых в определённом порядке, Порядок выполнения определяется приоритетами (priority). Когда екстеншен набран приоритеты выполняются до разъединения вызова, или перенаправления на другой екстеншен. Каждый шаг записывается следующим образом:
exten => <exten>,<priority>,<application>, [(<args>)]
Пример простого екстеншена
exten => 100,1,Wait(5) exten => 100,2,Answer exten => 100,3,Playback(demo-congrats) exten => 100,n,Hangup
Этот екстеншен состоит из 4-х действий.
Первым выполняется приложение Wait c приоритетом 1 - ждать 5 секунд (время задаётся аргументом (5).
Вторым приложение Answer - поднять трубку.
Затем Playback - проиграть звуковой файл; аргумент задает имя файла (demo-congrats) в директории по умолчанию.
Последним выполняется приложение Hangup - повесить трубку. Приоритет 'n' означает next (следующий) и может использоваться вместо любого приоритета кроме 1-го.
Например:
[default] exten => 100,1,Wait(5) exten => 100,n,Answer exten => 100,n,Playback(demo-congrats) exten => 100,n,Hangup
Использование приоритета 'n' позволяет легко редактировать отдельные строки не переписывая все приоритеты.
Набор номера
Чаще всего вызывается другой интерфейс. Вызов осуществляется командой Dial.
[default] exten => 100,1,Dial(DAHDI/1,20) exten => 100,2,Voicemail(u100@default) exten => 100,102,Voicemail(b100@default)
Этот пример иллюстрирует разные варианты действий в случае, если на вызов не ответили. Сначала вызывается канал DAHDI/1, если через 20 секунд никто не ответил вызов пренаправляется на VoiceMail()с объявлением «абонент не отвечает»(u100), Если же абонент занят, вызов перейдет на приоритет N+101, в нашем случае это приоритет 102.
Маршрутизация по CallerID
Пример маршрутизации по номеру вызывающего абонента.
[default] exten => 100/1234567,1,Congestion exten => 100,1,Dial(DAHDI/1,20) exten => 100,2,Voicemail(u100) exten => 100,102,Voicemail(b100)
Если вызывается екстеншен 100 вызов направляется на интерфейс DAHDI/1, кроме случая если вызов осуществляет абонент 1234567. В этом случае вызов отклоняется. На примере видно, что идентификатор вызывающего абонента задается формой '/1234567'.
Ещё один пример маршрутизации, теперь по отсутствию CallerID.
[default] exten => 100/,1,Zapateller exten => 100,1,Wait(0) exten => 100,2,Dial(DAHDI/1)
В данном примере если поступает звонок без CallerID, вызов блокируется с помощью приложения Zapateller()
Вызов группы телефонов
Часто требуется чтобы вызов по неответу перешел на другой телефон. Рассмотрим как это сделать на примере «оператор».
[operator] exten => 0,1,Dial(DAHDI/1,15) exten => 0,2,Dial(DAHDI/1&DAHDI/2&DAHDI/3,15) exten => 0,3,Playback(companymailbox) exten => 0,4,Voicemail(100) exten => 0,5,Hangup
Вызов поступает на DAHDI/1, в случае если телефон занят или не отвечает в течении 15 секунд, звонок переходит на группу телефонов, включая и DAHDI/1. Если и на этот раз никто не поднимает трубку, вызов переходит на голосовую почту.
Интерактивное Голосовое меню
Голосовое меню как правило задается в собственном контексте.
[sales] exten => s,1,Background(welcome-sales) exten => 1,1,Goto(default,100,1) exten => 2,1,Goto(default,101,1) [mainmenu] exten => s,1,Background(welcome-mainmenu) exten => 1,1,Goto(sales,s,1) exten => 2,1,Dial,DAHDI/2 exten => 9,1,Directory(default) exten => 0,1,Dial,DAHDI/3
Объявление проигрывается на расширении 's' (смотри Стандартные расширения). В объявлении предлагается набрать '1' для вызова отдела продаж (производится переход в контекст 'sales'). Набрать '2' - вызов DAHDI/2. Набор '9' - вызов каталога (смотри Directory ) и '0' вызов DAHDI/3
Использование переменных
В Asterisk существуют глобальные и специфичные для каналов переменные, используемые в качестве аргументов для команд. Переменные записываются в диалплане в виде ${foo}, где 'foo' это имя переменной. Имена должны начинаться с буквы и могут состоять из любых цифр и букв, но существуют предопределенные имена, вот некоторые из них:
${CONTEXT}Текущий контекст.
${EXTEN}Текущий екстеншен.
${EXTEN:x}Текущий екстеншен с удалением первых цифр(где х кол-во удаляемых цифр)
${PRIORITY}Текущий приоритет
${CALLERID}Текущий CallerID (имя и номер)
${CALLERIDNUM}Текущий номер Caller ID
${CALLERIDNAME}Текущее имя Caller ID
${RDNIS}перенаправление DNIS
Глобальные переменные назначаются в секции [globals] диалплана. Рассмотрим следующий пример:
[globals] MARK => DAHDI/1 GREG => DAHDI/2&SIP/telephone WIL => DAHDI/3 JUDY => DAHDI/4 [mainmenu] exten => 1,1,Dial(${GREG}&${MARK}) exten => 2,1,Dial(${WIL}&${JUDY}) exten => 3,1,Dial(${JUDY}&${MARK})
Организуя диалплан таким образом, можно быстро и легко переназначать физические интерфейсы для конкретных пользователей, часто используемых в контекстах.
смотри подробнее Использование переменных в плане набора Asterisk
Вложенные контексты
Один контекст может включать другие контексты, обрабатываемые в порядке перечисления. Смотри также Порядок выбора нужного екстеншена при использовании шаблонов.
include => <context>[|<hours>|<weekdays>|<monthdays>|<months>]Где <context> - включаемый контекст
опционально:
<hours> - часы в которые действителен контекст (например рабочее время 9:00-17:00)
<weekdays> -дни недели (mon-fri)
<monthdays> - дни
<month> - месяцы
Пример:
[local] exten => _[0-79].,1,Dial(SIP/trunk/${EXTEN}) [long] exten => _8.,1,Dial(SIP/trunk/${EXTEN}) [local_long] include => local include => long [local_only] include => localВ этом примере контекст 'local_long'' включает два других контекста для городской и междугородней связи, а контекст 'local_only' только для городской.
Дневной / Ночной режимы. Маршрутизация по времени
Вложенные контексты можно использовать для реализации дневного, ночного и празничного режимов. Рассмотрим следующий пример:
[newyears] exten => s,1,Playback(happy-new-years) [daytime] exten => s,1,Dial(DAHDI/1,20) [nighttime] exten => s,1,Playback(after-hours-msg) [default] include => newyears||||1|jan include => daytime|9:00-17:00|mon-fri include => nighttimeВ этом примере заданы дневной, ночной и праздничный режимы прихода звонков.
Исходящие вызовы
Направление исходящей связи можно реализовать определением короткого кода доступа (например '9'), или определить полностью шаблон набираемых номеров.
[international] ignorepat => 9 exten => _9810.,1,Dial(DAHDI/g2/${EXTEN:1}) exten => _9810.,2,Congestion include => longdistance [longdistance] ignorepat => 9 exten => _98[02-9]XXXXXXXXX,1,Dial(DAHDI/g2/${EXTEN:1}) exten => _98[02-9]XXXXXXXXX,2,Congestion include => local [local] ignorepat => 9 exten => _9[02-79]XXXXXX,1,Dial(DAHDI/g2/${EXTEN:1}) exten => _9[02-79]XXXXXX,2,Congestion include => default
В этом примере рассматриваются 3 контекста с различными правами доступа к Телефонной сети Общего Пользования .
Конструкция 'ignorepat ⇒ 9 ' говорит Астериску не отключать тон готовности после набора заданной цифры.
- Контекст [international] позволяет набрать международный номер с любым количеством цифр.
- Контекст [longdistance] - междугородний номер до 11-ти цифр.
- Контекст [local] - городской номер длинной до 7-ми цифр.
Переменная ${EXTEN:1} удаляет префикс:
${123456789:1} - возвращает строку 23456789 ${123456789:-4} - возвращает строку 6789 ${123456789:0:3} - возвращает строку 123 ${123456789:2:3} - возвращает строку 345 ${123456789:-4:3} - возвращает строку 678
Шаблоны Patterns
Екстеншены могут сопоставляться шаблону, вместо однозначно заданных цифр. Шаблон должен начинаться с символа подчеркивания ( _ ) и может использовать любой из следующих символов:
- X– любая цифра от 0-9
- Z– любая цифра от 1-9
- N– любая цифра от 2-9
- [14-6]– цифры 1,4, 5 и 6
- .– любые возможные символы.
Резервные транки и LCR (выбор направления с наименьшей стоимостью)
Весьма полезно настроить LCR (Least Coast Routing) и перенаправление в случае отказа внешней линии.
[tolllongdistance] exten => _98XXXXXXXXXX,1,Dial(DAHDI/g2/${EXTEN:1}) exten => _98XXXXXXXXXX,2,Congestion [low_rate_moscow] exten => _98495XXXXXXX,1,Dial(IAX/trunk/${EXTEN:1}) exten => _98495XXXXXXX,2,Dial(DAHDI/g2/${EXTEN:1}) exten => _98495XXXXXXX,3,Congestion [longdistance] include => low_rate_moscow include => tolllongdistance
В этом примере междугородние вызовы направляются на DAHDIинтерфейс, но звонки в Москву направляются через более выгодного провайдера на IAXтранк. В случае же недоступности IAXтранка, вызовы перенаправляются через DAHDI.
Использование Макросов
Вам может потребоваться создать множество екстеншенов (расширений) очень похожих друг на друга. Чтобы упростить работу с диалпланом используются Макросы. Для создания макроса используется контекст имя которого начинается с «macro-» и далее уникальное имя макроса. Выполнение макроса начинается с ектеншена 's'. В макросах используются локальные переменные:
${MACRO_EXTEN} – Екстеншен вызываемый макросом ${MACRO_CONTEXT} – Контекст вызываемый макросом ${MACRO_PRIORITY} – активный приоритет вызываемый макросом ${MACRO_OFFSET} – если установлено вызывает смещение n + ${MACRO_OFFSET} ${ARGn} – аргумент 'n' в макросе.
[macro-oneline] ; ; Однолинейный телефон ; ; ${ARG1} – Телефон ; exten => s,1,Dial(${ARG1},20) exten => s,2,Voicemail(u${MACRO_EXTEN}) exten => s,3,Hangup exten => s,102,Voicemail(b${MACRO_EXTEN}) exten => s,103,Hangup [macro-twoline] ; ; Двухлинейный телефон ; ; ${ARG1} – Телефон (линия) 1 ; ${ARG2} – Телефон (линия) 2 ; exten => s,1,Dial(${ARG1},20) exten => s,2,Voicemail(u${MACRO_EXTEN}) exten => s,102,Dial(${ARG2},20) exten => s,103,Voicemail(b${MACRO_EXTEN}) [default] exten => 1000,1,Macro(oneline,DAHDI/1) exten => 1001,1,Macro(oneline,SIP/1001) exten => 1002,1,Macro(twoline,DAHDI/3,DAHDI/4)
Когда макросы [macro-oneline] и [macro-twoline] созданы, в контексте [default] надо написать только одну сроку для выполнения нескольких стандартных действий.
[from-phones1] exten => _X.,1,Dial(SIP/sip_trunk/${EXTEN},180,) exten => _X.,n,Macro(dialstatus,s,1) exten => _X.,1,Dial(DAHDI/g2/${EXTEN},180,) exten => _X.,n,Macro(dialstatus,s,1) [macro-dialstatus] exten => s,1,Answer exten => s,n,Goto(s-${DIALSTATUS},1) exten => s-NOANSWER,1,Hangup exten => s-CONGESTION,1,Congestion exten => s-CANCEL,1,Hangup exten => s-BUSY,1,Playtones(425/375,0/375) exten => s-BUSY,n,Busy(7) exten => s-BUSY,n,Hangup exten => s-CHANUNAVAIL,1,Hangup
Приложение Macro объявлено устаревшим, вместо него рекоммендуется использовать GoSub.
Синтаксис Gosub
Gosub([[context,]exten,]priority[(arg1[,...][,argN])])
[sub-test] exten => _X.,1,Dial(${ARG1}/${ARG2},20,) exten => _X.,n,Playback(tt-weasels) exten => _X.,n,Hangup [test] exten => _X.,1,Gosub(sub-test,${EXTEN},1(SIP/trunk,${EXTEN}))
Запись разговоров
[macro-mixmonitor] exten => s,1,Set(RECORD_FILENAME=${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${CALLERID(num)}) same => n,MixMonitor(${RECORD_FILENAME}.wav,b) same => n,Dial(${ARG1},180,) [outbound_route1] exten => _9.,1,Macro(mixmonitor,PJSIP/sipprovider/${EXTEN:1})
В данном примере вызов с префиксом '9', должен быть скоммутирован через SIPтранк ITSP. Разговор будет записан в формате 'wav' и сохранен в директорию по умолчанию «/var/lib/asterisk/monitor/ГодМесяцДень-ЧасыМинутыСекунды-НомерВызывающего Абонента.wav
Структура same ⇒ позволяет сократить код, избежав многочисленных повторений «exten ⇒ s,» в данном случае.
Хорошая мысль поэкспериментировать и с другими переменными в имени файла, например ${UNIQUEID}.