что такое dial plan
Наиболее важным для понимания Asterisk является план набора (dialplan). Все вызовы, будь-то очередь, конференция, меню автосекретаря или вызов телефона, определяются логикой и концепцией диалплана.
Введение в расширения (extensions) и контексты (context)
Каналам назначаются контексты. Контексты определяют правила набора для каналов
План набора состоит из одного или нескольких контекстов. Каждый контекст это просто набор расширений (екстеншенов). Каждый екстеншен в контексте имеет уникальное имя.
Контексты используются для выполнения основных функций АТС :
Что такое екстеншен?
Пример простого екстеншена
Этот екстеншен состоит из 4-х действий.
Например:
Использование приоритета ‘n’ позволяет легко редактировать отдельные строки не переписывая все приоритеты.
Набор номера
Чаще всего вызывается другой интерфейс. Вызов осуществляется командой Команда Asterisk Dial.
Этот пример иллюстрирует разные варианты действий в случае, если на вызов не ответили. Сначала вызывается канал DAHDI /1, если через 20 секунд никто не ответил вызов пренаправляется на VoiceMail() с объявлением «абонент не отвечает»(u100), Если же абонент занят, вызов перейдет на приоритет N+101, в нашем случае это приоритет 102.
Маршрутизация по CallerID
Пример маршрутизации по номеру вызывающего абонента.
Ещё один пример маршрутизации, теперь по отсутствию CallerID.
В данном примере если поступает звонок без CallerID, вызов блокируется с помощью приложения Zapateller()
Вызов группы телефонов
Часто требуется чтобы вызов по не ответу перешел на другой телефон. Рассмотрим как это сделать на примере «оператор».
Asterisk IVR
Голосовое меню как правило задается в собственном контексте.
Использование переменных
$ Текущий контекст.
$ Текущий екстеншен.
$ Текущий екстеншен с удалением первых цифр(где х кол-во удаляемых цифр)
$ Текущий приоритет
$ Текущий CallerID (имя и номер)
$ Текущий номер Caller ID
$ Текущее имя Caller ID
$ перенаправление DNIS
Глобальные переменные назначаются в секции [globals] диалплана. Рассмотрим следующий пример:
Организуя диалплан таким образом, можно быстро и легко переназначать физические интерфейсы для конкретных пользователей, часто используемых в контекстах.
Вложенные контексты
Один контекст может включать другие контексты, обрабатываемые в порядке перечисления. Смотри также Порядок выбора нужного екстеншена при использовании шаблонов.
Пример:
В этом примере контекст local_long включает два других контекста для городской и междугородней связи, а контекст ‘local_only’ только для городской.
Дневной / Ночной режимы. Маршрутизация по времени
Вложенные контексты можно использовать для реализации дневного, ночного и празничного режимов. Рассмотрим следующий пример:
В этом примере заданы дневной, ночной и праздничный режимы прихода звонков.
Исходящие вызовы
Направление исходящей связи можно реализовать определением короткого кода доступа (например ‘9’), или определить полностью шаблон набираемых номеров.
Конструкция ‘ignorepat ⇒ 9 ‘ говорит Астериску не отключать тон готовности после набора заданной цифры.
Шаблоны Patterns
Екстеншены могут сопоставляться шаблону, вместо однозначно заданных цифр.
Шаблон должен начинаться с символа подчеркивания _ и может использовать любой из следующих символов:
Резервные транки и LCR (выбор направления с наименьшей стоимостью)
Весьма полезно настроить LCR (Least Coast Routing) и перенаправление в случае отказа внешней линии.
Использование Макросов
Вам может потребоваться создать множество екстеншенов (расширений) очень похожих друг на друга. Чтобы упростить работу с диалпланом используются Макросы. Для создания макроса используется контекст имя которого начинается с «macro-» и далее уникальное имя макроса. Выполнение макроса начинается с ектеншена ‘s’. В макросах используются локальные переменные:
Когда макросы [macro-oneline] и [macro-twoline] созданы, в контексте [default] надо написать только одну сроку для выполнения нескольких стандартных действий.
Приложение Macro объявлено устаревшим, вместо него рекомендуется использовать GoSub.
Синтаксис Gosub
Запись разговоров Asterisk
Структура same ⇒ позволяет сократить код, избежав многочисленных повторений «exten ⇒ s,» в данном случае.
Asterisk Dialstatus
Команда GoTo(s-$
Основы диалплана
Всё должно быть изложено так просто, как только возможно,
Диалплан — это сердце вашей системы Asterisk. Он определяет как обрабатываются вызовы в вашей системе. Диалплан, как скриптовый язык содержит инструкции, которым следует Астериск, реагируя на внешние триггеры. В отличии от традиционных телефонных систем диалплан Астериска может полностью перенастраиваться.
Эта глава расскажет самую суть концепции диалплана. Изложенная здесь информация является критичной для понимания вами кода диалплана и является основой для любого диалплана, который вы напишите сами. Примеры, описанные ниже, следуют связанно друг за другом, и поэтому мы не рекомендуем пропускать слишком большую часть этой главы, потому что это является фундаментально важным для понимания Астериск. Просим не рассматривать также данную главу как исчерпывающий обзор всех возможностей, которые можно реализовать посредством диалплана; наша цель состоит в том, чтобы охватить только самое необходимое. Мы рассмотрим более расширенные возможности диалплана в последующих главах. Вам предлагается поэкспериментировать.
Синтаксис диалплана
Диалплан Астериска задаётся в конфигурационном файле extensions.conf.
Файл extensions.conf обычно расположен в директории /etc/asterisk, но его расположение может быть совершенно различным в зависимости от того как вы инсталлировали Астериск. Другие возможные места структуры Asterisk — /usr/local/etc/asterisk и /opt/etc/asterisk.
Диалплан состоит из четырёх основных концепций: контекст (context), расширения (extensions), приоритеты и приложения (applications). После объяснения роли каждого из этих четырёх элементов, работающих в диалплане, мы построим простой, но вполне функционирующий диалплан.
Примерный конфигурационный файл
Если вы инсталлировали примеры конфигурационных файлов, то скорее всего у вас уже существуюет файл extensions.conf. Вместо того, чтобы начинать разбираться с этим примером мы рекомендуем создать свой собственный extensions.conf с нуля. Начинать с изучения примерного файла конфигурации не самый хороший или лёгкий путь изучать построение диалплана.
Но хочется всё же заметить, что пример extensions.conf содержит фантастические ресурсы, он полон примеров и идей, которые вы можете использовать после того, когда изучите основные концепции. Если вы следовали инструкциям при инсталляции, то найдёте файл extensions.conf.sample в каталоге
/src/asterisk-complete/asterisk/11/configs (там же, где много и других примеров конфигурации).
Контекст
Диалплан разбит на секции, называемые контекстами. Контексты содержат различные части диалплана, сообщающиеся между собой. Расширение, определяемое в одном контексте полностью изолировано от других расширений в других контекстах, кроме разрешённых специфических соединений. (Мы рассмотрим как сообщаются контексты между собой в конце этой главы. См. «Вложения (инклюды)» на стр. для информации).
Названия/имя контекста должно быть не более 79 символов (80 символов минус один, нуль).
Когда вы определяете канал (что не делается в файле extensions.conf, но для этого используются такие файлы, как sip.conf, iax.conf, chan_dahdi.conf, и тд), одним из обязательных параметров в каждом определении канала является context. Контекст—это точка в диалплане, где будут начинаться соединения с этим каналом. Настройка контекста для канала — это способ подключения канала к диалплану. На Рисунке 6-1 показана связь между файлами конфигурации канала и контекстами в диалплане.
Рисунок 6-1. Связь между файлом конфигурации канала и контекстом в диал-плане
Это является одной из важнейших концепций для понимания как соотносятся между собой каналы и диал-план. Когда вы поймёте связь в определении контекста для канала, чтобы находить соответствие ему в диалплане, вы найдёте это лёгким и удобным для поиска проблем в прохождении вызовов через Asterisk-систему.
Наиболее важный смысл использования контекстов (а возможно и самый важный) — обеспечить безопасность. При правильном использовании контекстов вы можете дать определённым пользователям доступ к особым функциональным возможностям (таким как возможность совершать международные вызовы), которые недоступны простым пользователям. Если вы небрежно отнесётесь к построению своего диалплана, то можете несознательно дать возможность посторонним лицам использовать вашу систему в мошеннических целях. Пожалуйста, помните об этом при построении вашей Asterisk-системы; в Интернете уже существует множество специально написанных ботов для обнаружения и внедрения в небрежно настроенные Asterisk-системы.
Asterisk wiki содержит несколько шагов, которые необходимо предпринять для обеспечения безопасности Asterisk-системы. (Глава 26 этой книги также посвящена вопросам безопасности.) Жизненно важно прочесть и понять эту страницу. Если вы проигнорируете меры безопасности, изложенные там, вы можете в конечном итоге позволить кому-либо, и вообще всем, совершать междугородние или платные звонки за ваш счет!
Если Вы не воспринимаете безопасность вашей системы Asterisk всерьез, вы можете в конечном итоге дорого заплатить — в буквальном смысле. Пожалуйста, потратьте время и усилия, чтобы защитить вашу систему от мошенничества.
Расширения (Extensions)
В мире телекоммуникаций слово extension относится к внутреннему номеру абонента, набрав который услышим вызов, звонок телефона, (или системный ресурс типа голосовой почты или очереди). В Aterisk же понятие расширения (extension) намного мощнее, поскольку оно определяет уникальную серию шагов (каждый шаг содержит приложение), через которую Asterisk будет принимать этот вызов.
Внутри каждого контекста мы можем использовать множество (или несколько) расширений, сколько нам потребуется. Когда запрашивается обычное расширение (на входящем вызове или по набору цифр в канале), Asterisk выполняет последовательно шаги, указанные для этого расширения. Это расширение, таким образом, описывает то, что должно произойти с вызовом, который попадает по своему пути в соответствующий диалплан. Расширения могут, разумеется, использоваться как специфические телефонные внутренние номера в традиционном смысле (например — расширение 153 будет вызывать SIP-телефон на столе у Ивана), но в диалплане Asterisk они могут использоваться для гораздо большего.
Синтаксис процедур для расширений начинается со слова exten, затем следуют символы — знаки равно и больше, в виде стрелки вправо, как в примере ниже:
Далее следует имя (или номер) расширения. Если набирается в/из традиционных телефонных систем, мы предполагаем обработку вызываемого расширения как номера, который набирается чтобы послать вызов на другой телефонный аппарат. В Asterisk вы получаете несколько больше возможностей; например, имя в качестве расширения, которое может содержать как буквы, так и цифры. В рамках краткого курса в этой главе мы рассмотрим как цифровые, так и буквенно-цифровые расширения.
Назначение имён для расширений может быть выглядит слишком революционной концепцией, но если вы реализуете поддержку нескольки видов транспортных VoIP протоколов (даже активно используемых) набор имени или адреса электронной почты вместо цифр даст великолепное ощущение. Только одно это свойство уже делает Астериск гибким и мощным.
Каждый шаг в расширении имеет три компонента:
Эти три компонента разделяются запятыми, как например показано ниже:
Вот самый простейший пример как обрабатывается реальный внутренний номер:
В этом примере имя расширения (или внутренний номер) 123, приоритет 1, и приложение Answer().
Приоритеты
Каждое расширение может иметь несколько шагов, называемых приоритетами. Приоритеты нумеруются последовательно, начиная с 1, и каждый шаг выполняет одно специфическое действие. Например, следующее ниже расширение выполнит ответ на звонок (поднимет трубку на приоритете 1) и затем положит трубку (на приоритете 2):
Довольно очевидно, что этот код не делает ничего полезного. Мы ещё доберемся до него. Ключевым моментом здесь является то, что для конкретного расширения Asterisk следует приоритетам по порядку. Этот стиль синтаксиса диалплана все еще виден время от времени, хотя (как вы увидите скоро) он обычно больше не используется в новом коде:
exten => 123,2,делаем что-то
exten => 123,3,делаем что-то ещё
exten => 123,4,сделаем ещё одну вещь
Ненумерованные приоритеты
В старых релизах Asterisk нумерация приоритетов вызывала множество проблем. Представьте себе расширение, которое имеет 15 приоритетов, а затем нужно добавить что-то на шаге 2: все последующие приоритеты должны быть перенумерованы вручную. Asterisk не обрабатывает пропущенные шаги или неправильно пронумерованные приоритеты и отладка этих типов ошибок была удручающей.
Начиная с версии 1.2, разработчики Asterisk решили эту проблему: ввели использование приоритета n, который означает «next» (следующий). Каждый раз, когда Астериск встречает приоритет с именем n, он берет номер предыдущего приоритета и добавляет 1. Это упрощает внесение изменений в диал-план, так как вам не нужно изменять нумерацию всех шагов. Например, ваш диалплан может выглядеть примерно так:
exten => 123,n,делаем что-то
exten => 123,n,делаем что-то ещё
exten => 123,n,сделаем ещё одну вещь
Оператор same =>
В нескончаемых усилиях по упрощению кодинга была придумана новая конструкция, чтобы сделать создание расширений и управление ими еще проще. До тех пор, пока расширение остается тем же, вместо того, чтобы вводить полное расширение в каждой строке, вы можете просто ввести same =>, указывая далее приоритет и приложение:
same => n,делаем что-то
same => n,делаем что-то ещё
same => n,сделаем ещё одну вещь
Отступ не требуется, но это может облегчить чтение. Этот стиль диалплана также облегчит копирование кода из одного расширения в другое. Мы предпочитаем этот стиль сами, и очень рекомендуем его.
Метки приоритетов
Метки на приоритетах дают возможность назначить имя к определённому номеру приоритета для расширения. Таким образом вы можете перейти к определённому приоритету другим образом, чем просто его номер (который, как правило, неизвестен, учитывая что диалпланы теперь обычно используют ненумерованные приоритеты). Причина, по которой важно обратиться к определенному приоритету в расширении, состоит в том, что вы захотите передавать вызовы из других частей диалплана определенному приоритету в конкретном расширении. Мы поговорим об этом позже. Чтобы назначить текстовую метку приоритету, просто добавьте метку в круглых скобках после приоритета, как здесь:
Позже мы рассмотрим, как переключаться между различными приоритетами на основе логики диалплана. Вы увидите гораздо больше возможностей для меток приоритетов, и будете использовать их часто в своих диалпланах.
Наиболее распространённая ошибка при написании диалплана с метками — это указание метки после запятой, между n и скобкой (, как здесь:
exten => 123,n,(label),application() ;
Иногда вместо запятой в качестве разделителя аргументов может использоваться символ пайп ( | ). Начиная с Asterisk 1.6.0 поддержка пайпа в качестве разделителя была удалена (кроме некоторых разделов в voicemail.conf).
Приложения Answer(), Playback(), и Hangup()
Приложение Answer() используется для ответа на вызывающий канал. Оно производит начальную настройку на канале, который получает входящий вызов. Как мы упоминали ранее, Answer() не принимает аргументов. Answer() не всегда вообще требуется (фактически, в некоторых случаях он вообще нежелателен), но в остальных случаях он вполне годен, чтобы подключить канал прежде чем начать последующие действия.
Приложение Progress()
Иногда полезно иметь возможность передавать информацию обратно в сеть перед ответом на вызов. Приложение Progress() пытается предоставить исходному каналу информацию о ходе выполнения вызова. Некоторые операторы ожидают этого и таким образом Вы можете быть в состоянии решить странные проблемы сигнализации, вставив Progress() в диалплан куда поступают ваши входящие вызовы. С точки зрения биллинга, использование Progress() позволяет оператору знать, что вы обрабатываете вызов без запуска тарификации.
Астериск поставляется с большим количеством профессионально записанных звуковых файлов, которые находятся в каталоге звуков по умолчанию (обычно /var/lib/asterisk/sounds). При компиляции Asterisk можно выбрать установку различных наборов звуковых файлов, записанных на различных языках и в различных форматах. Мы будем использовать эти файлы во многих наших примерах. Некоторые из файлов в наших примерах взяты из дополнительного звукового пакета, поэтому, пожалуйста, найдите время, чтобы установить его (см. Главу 3). Вы также можете иметь свои собственные звуковые подсказки, записанные в тех же голосах, что и стоковые подсказки, посетив http://www.theivrvoice.com. Далее в книге мы поговорим о том, как использовать телефонный аппарат и диалплан для создания собственных системных записей и управления ими.
Чтобы использовать Playback() укажите имя файла (без расширения) в качестве аргумента. Например, Playback(filename) воспроизведёт файл filename.wav, предполагая, что он расположен в дефолтной для звуковых файлов директории. Заметим, что можно также включать полный путь к файлу, если необходимо, как указано ниже:
В приведённом примере мы воспроизвели filename.wav из директории /home/john/sounds.
Можно также использовать относительные пути к именам файлов относительно к основной директории звуковых файлов, как например ниже:
Приложение Hangup() делает именно то, что отражено в его названии: закрывает активный канал. Необходимо использовать его в конце контекста, если хотите завершить текущий канал, чтобы быть уверенным, что действия, которые, возможно, и не предполагались, в активном канале не продолжатся. Приложение Hangup() не требует аргументов, но, если хотите, в него можно передать ISDN код завершения, например Hangup(16).
В процессе работы над книгой мы познакомим вас со многими приложениями Астериск.
Простой диал-план.
OK, хватит теории. Откройте в редакторе файл /etc/asterisk/extensions.conf, и посмотрите на ваш первый диалплан (который был создан в предыдущей Главе 5). Мы будем дополнять его.
Hello World
Наиболее типичным примером для многих книг по технологиям (точнее — книг по программированию) является первый пример под названием «Привет, мир!» (“Hello World!”).
Первым приоритетом нашего расширения мы отвечаем на вызов. Затем, на втором шаге мы воспроизводим файл с названием hello-world и затем, третьим шагом мы просто кладём трубку завершая вызов. Интересующий нас код для этого примера выглядит вот так:
Если вы прошли Главу 5 вы уже получили сконфигурированный один или два канала, а также пример диалплана, содержащий наш код. Если нет, то всё, что вам нужно — просто добавить в файл extensions.conf в директории /etc/asterisk следующий код:
[LocalSets] ; это название контекста
exten => 100,1,Dial(SIP/0000FFFF0001) ; замените 0000FFFF0001 на имя вашего
exten => 101,1,Dial(SIP/0000FFFF0002) ; замените 0000FFFF0002 на имя вашего
Если у вас ещё нет сконфигурированных к этому моменту каналов, то сейчас самое время сделать это. Существует реальное удовлетворение, которое приходит от вашего первого вызова в диалплан в Asterisk-системе, которую вы построили с нуля. Люди обычно ощущают забавную ухмылку на своих лицах, поскольку они понимают, что только что создали телефонную систему. Это удовольствие может быть получено и вами, поэтому, пожалуйста, не двигайтесь дальше, пока не сделаете это небольшое задание по диалплану. Если при этом вы столкнётесь с какими-то проблемами, вернитесь к Главе 5 и проработайте примеры оттуда.
Если у вас ещё нет этого кода в диалплане, пора его вставить и применить через перезагрузку диал-плана командой CLI:
*CLI> dialplan reload
или из командной оболочки:
Вызов расширения 200 с преднастроенного телефона даст возможность услышать голос Элиссон Смит, которая скажет “Hello, world!”
Если это не работает, смотрите в консоль Астериска на предмет сообщений об ошибках, и убедитесь в том, что ваш канал привязан к контексту LocalSets.
Мы не рекомендуем двигаться дальше по этой главе, прежде чем вы не проверите следующее:
Несмотря на то, что этот пример очень короткий и простой, он подчеркивает основные понятия контекстов, расширений, приоритетов и приложений. Теперь у вас есть фундаментальные знания, на которых строятся все диалпланы.
Построение интерактивного диал-плана
Диал-план, который мы только что построили является статическим; его результат исполнения будет тот же при каждом звонке. Тем не менее множество диал-планов требуют логически совершать разные действия в зависимости от введённых пользователем данных, которые мы сейчас и рассмотрим.
Приложения Goto(), Background() и WaitExten()
Как понятно из названия, приложение Goto() используется для отсылки вызова в другой участок диалплана. Синтаксис приложения Goto() потребует от нас указать данные: контекст назначения, расширение и приоритет в качестве аргументов, как указано ниже:
Давайте создадим новый контекст TestMenu и укажем ещё одному расширению в нашем контексте LocalSets перенаправить вызовы туда через Goto():
exten => 201,1,Goto(TestMenu,start,1) ; добавим эту строку в конце
Теперь, если любое устройство в контексте LocalSets наберёт 201 вызов перенаправится на расширение start в контексте TestMenu (в котором пока ещё нет ничего интересного, ибо его код мы напишем позже).
Мы используем расширение start в этом примере, хотя можно использовать вообще любое имя в качестве расширения, включая цифры и буквы. Мы предпочитаем использовать буквенные расширения, хотя их и не набрать с цифровой панели телефона, но зато это даёт более читаемый диалплан. В нашем примере мы могли бы использовать 123 или xyz123, или же 99luftballons или вообще что угодно вместо выбранного нами start. Само слово “start” ничего специально не означает в диалплане; это просто произвольное название расширения.
Чаще всего приложение Background() используется для создания голосовых меню (часто называемых автосекретарями 8 или телефонными деревьями). Многие компании используют голосовые меню, чтобы направить абонентов в соответствующие отделы, тем самым избавляя операторов от необходимости отвечать на каждый вызов.
Background() имеет такой же самый синтаксис как и Playback():
Если хотите, чтобы Asterisk ожидал донабор от позвонившего после приветствия, то можно использовать WaitExten(). Приложение WaitExten() ожидает от позвонившего сигналы DTMF (нажатие цифр) и указывается сразу за приложением Background() как указано ниже:
Если необходимо, чтобы приложение WaitExten() ожидало ввода только в течение определённого количества секунд (вместо дефолтного значения таймаута) 9 просто укажите эту цифру в скобках в качестве аргумента в WaitExten() как ниже:
same => n,WaitExten(5) ; Мы всегда передаём аргумент в приложение WaitExten()
Оба приложения — Background() и WaitExten() позволяют вводить цифры в виде донабора DTMF. После чего Астериск пытается найти расширение в текущем контексте, соответствующее введённым цифрам. Если такое совпадение найдено, Asterisk посылает вызов согласно этому расширению. Давайте продемонстрируем это добавлением нескольких строк в нашем примере диалплана:
После выполнения этих изменений нужно сохранить и перезагрузить диалплан:
*CLI> dialplan reload
Если вы звоните на номер 201 вы должны услышать приветствие “Введите внутренний номер сотрудника чтобы соединиться с ним.” Система будет ожидать ввода цифр в течение 5 секунд. Если вы нажмёте 1 или 2, то Астериск найдёт соответствующее расширение и прочитает его вам. Так как мы не прописали там никаких других инструкций к выполнению, то наш вызов на этом завершится. Вы также можете попробовать вводить другие цифры (например 3), которых нет в диалплане и, потому, он не будет выполняться.
Давайте немного приукрасим эти вещи. Мы сделаем возврат на начало при помощи приложения Goto() чтобы наше приветствие повторялось после воспроизведения цифр донабора:
same => n,Goto(TestMenu,start,1)
same => n,Goto(TestMenu,start,1)
Эти новые строки в диалплане передают управление на расширение start после воспроизведения выбранной цифры. В общем случае это выглядит более дружественно, чем просто завершение вызова.
Если вы рассмотрите внимательно возможности приложения Goto(), то увидите возможность передавать вызов в это приложение с одним, двумя и тремя аргументами. Если передаётся один аргумент, то Asterisk предположит что это приоритет назначения в текущем расширении. Если передаётся два аргумента, то Астериск будет рассматривать их как расширение и приоритет для перехода в текущем контексте.
В этом примере мы передали все три аргумента для ясности, но передача только расширения и приоритета имела бы тот же эффект, поскольку контекст назначения совпадает с исходным контекстом.
Обработка неверных значений и Таймаутов
После того, как мы создали вместе наше первое голосовое интерактивное меню, давайте добавим в него некоторые дополнительные специальные расширения. Для начала нам нужно расширение для обработки неверных, несуществующих расширений. Asterisk получив в контексте запрос на обработку несуществующего в текущем контексте расширения (например – нажатие 9 в примере выше), перенаправит вызов в расширение i. Нам также понадобится специальное расширение для обработки ситуаций, когда позвонивший вообще ничего не нажал в течение определённого времени (дефолтный таймаут 10 секунд). Вызов так же будет перенаправлен в расширение t если абонент слишком поздно нажал что-то после WaitExten() при вызове. Посмотрите как будет выглядеть наш диалплан после того, как мы добавим эти два расширения:
exten => i,1,Playback(pbx-invalid)
same => n,Goto(TestMenu,start,1)
exten => t,1,Playback(vm-goodbye)
same => n,Hangup()
Использование расширений i 10 и t делает наше меню более надежным и дружественным по отношению к пользователям. Тем не менее, оно все еще довольно ограничено, потому что внешние абоненты по-прежнему не имеют возможности связаться с живым человеком. Для этого нам нужно узнать о другом приложении, называемом Dial().
Использование приложения Dial()
Одной из наиболее ценных функций Asterisk является возможность соединения разных абонентов друг с другом. Это особенно полезно, когда абоненты используют различные методы связи. Например, абонент А может общаться по традиционной аналоговой телефонной сети, в то время как пользователь Б может сидеть в кафе на другом конце света и говорить по IP-телефону. К счастью, Asterisk берёт на себя большую часть тяжелой работы по соединению и трансляции вызовов между разрозненными сетями. Все что вам нужно сделать, это научиться использовать приложение Dial().
Синтаксис приложения Dial() более сложен, чем другие приложения, которые мы использовали до сих пор, но это не должно вас пугать. В приложение Dial() передаётся до четырёх аргументов, которые мы рассмотрим ниже.
Аргумент 1: назначение
Первый аргумент – это назначение: т.е. куда вы хотите позвонить, который (в простой форме) содержит технологию (или транспорт), посредством которой выполняется вызов, далее знак слэш — / и адрес удалённой конечной точки или ресурса. Наиболее типичные примеры технологий включают в себя DAHDI (для аналоговых и цифровых T1/E1/J1, PRI & BRI каналов), SIP и IAX2.
Можно также делать одновременный вызов нескольких каналов, разделяя назначения знаком амперсанд (&), как показано ниже:
Приложение Dial() также даёт возможность установить соединение с удалённым конечным VoIP-устройством, даже не указанным ранее в конфигурационных файлах соответствующего канала. Полный синтаксис команды имеет вид:
В качестве примера вы можете позвонить на демонстрационный сервер компании Digium используя протокол IAX2 и следующее расширение:
Полный синтаксис приложения Dial() несколько отличается для каналов DAHDI:
Например, если вы набираете номер 1-800-555-1212 через DAHDI канал под номером 4 13 :
Аргумент 2: тайм-аут
Второй аргумент приложения Dial() — это тайм-аут, указываемый в секундах. Если тайм-аут задан, приложение Dial() будет пытаться вызывать назначение указанное количество секунд до поднятия трубки, после чего перейдёт на следующий приоритет набранного расширения.
Если тайм-аут не указан, Dial() будет продолжать звонить на указанные каналы до тех пор, пока кто-либо не поднимет трубку. Давайте добавим 10-ти секундный тайм-аут в наше расширение:
Если абонент ответит до истечения таймаута, то каналы соединяются и диалплан на этом закончится. Если же абонент просто не отвечает, занят, или даже недоступен по каким-то причинам, Asterisk устанавливает это значение в переменной DIALSTATUS и продолжает выполнение следующего приоритета в текущем расширении.
Давайте соорудим сейчас то, что мы изучили в следующем примере:
same => n,Playback(vm-nobodyavail)
same => n,Hangup()
Как мы видим в этом примере, звуковой файл vm-nobodyavail.gsm будет воспроизведён в случае, если вызов не отвечен.
Аргумент 3: опции
Третий аргумент в Dial() — строка опций. Она может содержать один или больше знаков, которые модифицируют поведение приложения Dial(). Список всех возможных опций слишком огромен, чтобы рассматривать его в рамках этого раздела. Например, одна из популярных опций – m. Если букву m указать третьим аргументом, вызывающая сторона будет слышать музыку вместо гудков вызова, который совершается в этот момент вызываемой стороне (разумеется мы предполагаем, что музыка на удержание у нас уже правильно сконфигурирована). Добавим опцию m в наш последний пример, чуть изменив первую строчку:
exten => 502,1,Dial(DAHDI/1,10,m)
Аргумент 4: URI
Четвёртый и последний аргумент в приложении Dial() — это URI. Если канал назначения поддерживает приём вызовов по URI, то указанный URI будет передаваться (например, если у вас есть IP-телефон, поддерживающий приём URI, то он появится на экране телефона; в случае использования софтфона URI может появиться в виде всплывающего окна на экране компьютера). Этот аргумент очень редко используется.
Обновление диалплана
Давайте изменим расширения 1 и 2 в нашем меню, где используем приложение Dial():
exten => 1,1,Dial(SIP/0000FFFF0001,10) ; Замените 0000FFFF0001 на имя своего
exten => 2,1,Dial(SIP/0000FFFF0002,10) ; Замените 0000FFFF0002 на имя своего
Пустые аргументы
Заметим, что второй, третий и четвёртый аргументы могут быть пустыми; обязательным является только первый аргумент. Например, если требуется указать строковую опцию, но без таймаута, просто оставьте аргумент тайм-аут незаполненным, как указано ниже:
Использование переменных
Переменные могут использоваться в диалплане Asterisk чтобы уменьшить набор строк кода, увеличить понимание или добавить логику. Если у вас есть опыт по программированию, то вы уже понимаете что такое переменные. Если нет – мы кратко расскажем что такое переменные и как они используются. Переменные являются жизненноважной концепцией диалплана Asterisk (и вы не найдете их в диалплане любой проприетарной АТС).
Переменная — это именованный контейнер, который может содержать некоторое значение. Преимущество переменной заключается в том, что её содержимое может изменяться, но её имя не меняется, то есть можно написать код, который ссылается на имя переменной и не беспокоиться о её содержимом. Например, мы можем создать переменную JOHN и присвоить ей значение DAHDI/1. И, когда мы пишем наш диалплан, мы можем указать канал John по имени, вместо того, чтобы помнить, что John использует канал с именем DAHDI/1. Если в какой-то момент мы изменим канал John на что-то другое, нам не придется менять код, ссылающийся на переменную JOHN, нам нужно только изменить значение, присвоенное переменной.
Помните, что названия переменных чувствительны к регистру. Переменная LEIF совсем не та же, что с названием Leif. Для большей читабельности все наши переменные в примерах мы будем писать в верхнем регистре. Вам надо также в дальнейшем знать, что все переменные в Asterisk будут также в верхнем регистре. Некоторые переменные, такие как CHANNEL и EXTEN, зарезервированы в Asterisk. Не пытайтесь назначить какие-то значения этим переменным. Распространённым также является запись глобальных переменных в верхнем регистре, а канальных переменных в формате языков Pascal/Camel.
Можно использовать три типа переменных в нашем диал-плане: глобальные переменные, канальные переменные и переменные окружения. Рассмотрим каждый из них.
Глобальные переменные
Как следует из самого названия, глобальные переменные всегда доступны всем каналам. Глобальные переменные полезны тем, что их можно использовать в любом месте диалплана для повышения удобочитаемости и управляемости. Представьте на мгновение, что у вас есть большой диалплан и несколько сотен обращений к каналу SIP/0000FFFF0001. Теперь вообразите, что вы передвигаетесь по диалплану и меняете все ссылки на SIP/0000FFFF0002. Это будет долгим процессом, и не без ошибок, как минимум.
Другим образом, вы могли бы определить глобальную переменную, содержащую значение SIP/ 0000FFFF0001 в начале диалплана и ссылаться на неё, вместо того чтобы изменять значения по всему диалплану теперь достаточно изменить всего одну строку кода, чтобы изменить действие во всех местах диалплана, где используется этот канал.
Глобальные переменные декларируются в контексте [globals] в самом начале файла extensions.conf. Например, мы создадим глобальную переменную с именем LEIF и значением SIP/0000FFFF0001. Эта переменная устанавливается каждый раз, когда Asterisk перечитывает диалплан:
Канальные переменные
Переменная канала, или канальная переменная – это переменная, ассоциированная только с обычными вызовами. В отличии от глобальных переменных эта переменная действует только в течение текущего звонка, и доступна только для использования в этом звонке.
Имеется множество предопределённых переменных канала для использования их в диалплане, они описаны подробно в Asterisk wiki. Канальные переменные устанавливаются через приложение Set():
Вы можете увидеть и другие различные канальные переменные. Почитайте!
Переменные среды
Добавление переменных в ваш диал-план
Теперь, когда мы изучили переменные, давайте мы заставим их работать в нашем диалплане. Мы начнём с добавления трёх глобальных переменных, ассоциированных с их канальными именами:
exten => 201,1,Goto(TestMenu,start,1) ; доступ к контексту TestMenu
В нашем тестовом меню мы просто укажем несколько различных конечных устройство для набора, как DAHDI/1 и SIP/Jane. Они могут быть заменены на любые конечные устройства, какие мы пожелаем. В нашем контексте TestMenu, который мы создаем, чтобы иметь представление как выглядит диалплан Asterisk, может дать вам идеи как это лучше сделать.
Совпадение по шаблонам
Если мы хотим, чтобы люди могли звонить через Asterisk, который соединяет их с внешними ресурсами, нам нужен способ к распознаванию любого возможного номера телефона, который может набрать абонент. В подобных ситуациях Asterisk предлагает сопоставление по шаблонам. Сравнение/сопоставление с шаблоном позволяет создать в вашем диалплане всего одно расширение, соответствующее множеству различных номеров. Это чрезвычайно полезно.
Синтаксис сравнения по шаблонам
При использовании сопоставления, определённые конкретные буквы и символы представляют то, с чем мы сравниваем. Шаблон всегда начинается с подчёркивания (_). Это сообщает Asterisk, что мы собираемся сравнивать с шаблоном, а не ожидаем точное имя расширения.
Если вы забыли поставить знак подчёркивания в начале шаблона, то Asterisk предполагает, что это просто именное расширение, и не пытается сравнивать с ним набор как с шаблоном. Это одна из наиболее общих ошибок людей, которые начинают изучать Астериск.
После подчёркивания можно использовать следующие одну или несколько букв:
Совпадение одной цифры от 0 до 9.
Совпадение одной цифры от 1 до 9.
Совпадение одной цифры от 2 до 9.
Другая распространённая ошибка – использование букв X, Z, и N в словах, составляющих шаблон совпадения; чтобы это обойти – используйте эти буквы в квадратных скобках (чувствительны к регистру), например _[n]o[x]ious-XXX.
Совпадение одного знака из указанного диапазона цифр. В данном случае совпадение будет найдено при цифре 1, а также других цифрах в диапазоне 5, 6, 7.
Свободное совпадение по шаблону; совпадёт один или более символов, независимо от того, что они представляют.
Если вы не очень заботитесь о точности, свободный шаблон с точкой даст непредсказуемое поведение в вашем диалплане (например – совпадение встроенных специальных расширений, таких как i или h). Нужно использовать точку в шаблонах после одной или нескольких цифр, которые найдены, если возможно, сравнением набранного номера с шаблоном. Например, вот такой шаблон никогда не должен использоваться:
Или такой пример, отвечает на совпадение любой цифры или буквы:
Подстановочный знак соответствия; соответствует нулю или более символов, независимо от того, что они представляют.
Для использования шаблонов в вашем диалплане просто поместите шаблон в качестве имени (или номера) расширения:
В этом примере с шаблоном сравнивается любой трёхзначный внутренний номер от 200 до 999 (буква N определяет цифры от 2 до 9, а каждая X определяет цифры от 0 до 9). Тем самым мы говорим, что любой, кто наберёт трёхзначный номер от 200 до 999 в этом контексте, услышит аудио файл auth-thankyou.gsm.
Ещё одно важное дополнение для понимания как набранный номер сопоставляется с шаблоном, если Asterisk нашёл более чем один шаблон для набранного номера. В таком случае будет использоваться наиболее конкретный (просчитывая сравнение слева направо). Скажем, вы указали следующие два шаблона, и абонент набрал 555-1212:
Примеры совпадения по шаблонам
Следующий шаблон соответствует любому семизначному номеру, если первая цифра равна 2 или больше:
Приведённый выше шаблон описывает все семизначные локальные номерные планы в Северной Америке.
В региональных 10-значных кодах этот шаблон будет выглядеть следующим образом:
Обратите внимание, что ни один из этих двух шаблонов не будет обрабатывать междугородние вызовы. Мы рассмотрим их в ближайшее время.
NANP и мошенничество с тарифами
Североамериканский номерной план (NANP) является открытой схемой телефонной нумерации, охватывающей 19 стран Северной Америки и Карибского архипелага. Все эти страны имеют международный код 1.
В Соединённых Штатах и Канаде правила регуляции в области телекоммуникаций схожи (и рациональны) и достаточны для совершения международных вызовов в страны с кодом 1 и ожидаемой адекватной стоимостью звонка. Однако большинство людей в 17 странах (кроме США и Канады) не реализуют возможности, заложенные правилами регуляции, которые сильно отличаются в этих странах. Смотрите правила NANP.
Одна из популярных афер использования NANP — попытка обмануть наивных Североамериканцев для вызовов по дорогим поминутным тарифам на номера в Карибские страны; абоненты считают, что, поскольку они набрали номер 1-NPA-NXX-XXXX, то они платят по стандартному национальному международному тарифу. Поскольку данная страна может иметь правила, которые позволяют эту форму вымогательства, абонент сам несет ответственность за стоимость звонка.
Единственный способ предотвратить подобные действия — блокировать вызовы определенных региональных кодов (например, 809) и снимать ограничения только по мере необходимости.
Рассмотрим ещё один:
Обратите внимание на точку в конце шаблона. Он описывает все номера, которые начинаются с 011 и далее одну или более цифр. В зоне действия NANP будет определяться как иностранный номер. (Мы будем использовать этот шаблон в следующем разделе при добавлении возможностей исходящих вызовов в нашем диалплане.)
Шаблоны, используемые в других странах
В этой секции показаны шаблоны ориентированные на NANP, но базирующиеся на логике применения в любой стране. Ниже даны примеры для некоторых стран (обратите внимание, что мы не проверяли их, и они почти наверняка неполные):
; UK, Германия, Италия, Китай и т.д.
_00. ; международный телефонный код
_0. ; национальный префикс набора
_0011. ; международный телефонный код
_0. ; национальный префикс набора
Это никоим образом не является всеобъемлющим, но должно дать вам общее представление о шаблонах, которые вы можете применять для своей собственной страны.
В этом примере приложение SayDigits() прочитает нам набранный трёхзначный номер.
В этом примере приложение SayDigits() стартует со второй цифры и проговорит только две последние цифры из набранного внутреннего номера.
Продвинутые возможности манипуляций с цифрами
Включения (инклюды)
Asterisk содержит важную возможность добавления расширений, доступных в одном контексте, в другой контекст. Это доступно через директиву include. Директива include даёт нам возможность контролировать доступ к другой секции диалплана.
Оператор include имеет следующую форму, где context – название другого контекста, который мы включаем в текущий контекст:
Включение одного контекста в другой даёт возможность набора расширений включенного контекста в текущем.
Когда мы включаем другие контексты в текущий, мы должны помнить о порядке, в котором мы их включаем. Asterisk сначала попытается найти совпадение набранного номера с расширениями в текущем контексте. В случае неудачи он попробует первый включенный контекст (включая любые контексты, включенные в этот контекст), а затем продолжит поиск в других включенных контекстах в том порядке, в котором они были включены.
Мы продолжим разговор о директиве include дальше в Главе 7.
Вывод
И наконец у вас есть он — простой, но вполне функционирующий диалплан. Есть ещё многие вещи, которые мы не рассмотрели пока, но у вас уже есть все фундаментальные основы. В следующих главах мы продолжим строить на этих основах.
Если отдельные части этого диалплана недостаточно осмыслены, можно вернуться назад и перечитать раздел ещё раз или два, прежде чем перейти к следующей главе. Крайне важно, чтобы вы понимали эти принципы и как их применять, поскольку следующие главы основываются на этой информации.
1Автоответчики рассматриваются в Главе 15.
2Это очень важное соображение. По сравнению с традиционными УАТС, где, как правило, существует набор значений по умолчанию для таких отделов, как приёмная (что означает — если вы забудете определить эти значения, то они, вероятно, будут работать в любом случае). В Астериск верно обратное: если вы не укажете Астериск как обрабатывать каждую ситуацию и он столкнется с чем-то, что он не сможет обработать, вызов, как правило, будет отклонен. Мы рассмотрим некоторые лучшие примеры из практики, которые помогут убедиться, что этого не произойдет, позже. Дополнительные сведения см. в разделе «Обработка неверных записей и таймаутов» на стр. 133.
3Заметим, что пробелы не входят в список допустимых символов. Не используйте имена контекстов с пробелами — ибо результат этого вам совсем не понравится!
4Астериск допускает простую арифметику в пределах приоритета, например n+200 и приоритет s (для same), но их использование несколько устарело из-за существования меток приоритета. Обратите внимание, что расширение s и приоритет s — это два разных понятия.
5Это будет другое приложение называемое Background(), которое почти идентично Playback() кроме того, что разрешает входящий аудиопоток от абонента. Вы можете более подробно прочесть об этом приложении в Главах 15 и 17.
6Asterisk выбирает лучший файл с точки зрения издержек трансляции кодеков (транскодинга) — таким образом затрачиваются наименьшие ресурсы по загрузке ЦПУ при конвертации в родной аудио-формат. Когда запускается Asterisk, вычисляются издержки трансляции между различными форматами аудио (они часто различаются в различных системах). Вы можете увидеть это набрав в командной строке своего Asterisk core show translation. Цифры в таблице показывают скорость перекодирования (в миллисекундах) односекундного аудио. Мы поговорим больше о различных аудио форматах (более известных как кодеки) в разделе «Кодеки» в Приложении B.
7Следует отметить, что некоторые люди ожидают что Background() из-за его имени, продолжит движение вперед, следуя шагам в диалплане во время воспроизведения звука. На самом деле его имя относится к тому, что он играет звук в фоновом режиме, ожидая DTMF на переднем плане.
8Дополнительную информацию об автосекретаре вы найдёте в Главе 15.
9Загляните в функцию диалплана TIMEOUT() чтобы узнать как можно изменить значение таймаутов по умолчанию. См. Главу 10 по списку всех функций диалплана.
10Расширение i для обработки несуществующих назначений поддерживается в основном для таких приложений как Background(). Оно не используется для обработки неверно набранных расширений или не попадающих в шаблон расширений.
11Если это рабочая конфигурация (а не тестовый пример) то не очень удачное название для этого устройства. Если вы добавите больше чем один софтфон (или планируете это в будущем) – как вы будете их различать?
12Мы рассмотрим переменные в разделе Использование переменных. В следующей главе мы обсудим как задавать выполнение диалплана основываясь на значениях DIALSTATUS.
13Подразумевается некоторые понимание того, что выбранный канал знает как добраться до внешних номеров.
14Мы рассмотрим функции диалплана позже. Не беспокойтесь о слишком многих переменных среды прямо сейчас. Это не так важно для понимания диалплана.
15Если вы выросли в Северной Америке, то можете поверить, что 1, которую вы набираете перед междугородным звонком, — это «междугородный код». Это неверно. Цифра 1 — это международный код страны для NANP. Имейте это в виду, если Вы пришлете свой номер телефона кому-то в другой стране, получатель может не знать ваш код страны и, таким образом, не сможет позвонить вам только с вашим кодом города и номером телефона. Ваш полный номер телефона с кодом страны +1 NPA NXX XXXX (где NPA-ваш код города) — например, +1 416 555 1212.