Asterisk. Пример 1 — вызов между двумя линиями SIP #
Первое, что хочется сделать сразу после установки системы, это совершить первый телефонный звонок, чтобы убедиться, что система действительно работает и ощутить то самое чувство, когда получилось!
В данной статье я постараюсь рассказать про основы работы Asterisk, каким образом вызов продвигается по системе, как настраиваются подсистемы и как они взаимодействуют между собой.
Если Вам не нужно погружаться в технические основы работы системы, если Вы не планируете глубоко изучать принципы работы, способы конфигурирования, если перед Вами стоит цель: настроить быстро, чтобы работало, и забыть, то я порекомендую Вам замечательные оболочки и сборки для удобной, простой и понятной настройки системы, такие как FreePBX, Elastix и т.п.
Disclamer #
Автор предупреждает читателей, о тонкой грани между допустимым использованием телефонных систем подобного рода и уголовной ответственностью, которая может наступить при неправильной маршрутизации телефонного трафика (рефайлинга). Пожалуйста, ознакомьтесь с законодательством Вашей страны, чтобы избежать проблем. Автор снимает с себя ответственность за любые действия читателя, в которых ему может помочь материал данной статьи и возлагает ее целиком и полностью на читателя данной статьи. Информация, приведенная в данной статье, является справочной и не носит практического характера.
Архитектура Asterisk #
Для начала нужно понять следующее: Система Asterisk строится из ядра и множества различных подсистем. Подсистемы делятся на 4 основные группы:
- Подсистема интерфейса каналов — в эту группу входят различные подсистемы для взаимодействия с источниками телефонного трафика и телефонных сигнализаций (SIP, IAX, PRI, Dongle и т.д.)
- Подсистема интерфейса приложений — в эту группу входят подсистемы, которые выполняют различные функции, такие как: конференцсвязь, голосовая почта, очередь вызовов, взаимодействие с jabber и т.д.
- Подсистема интерфейса кодеков — в эту группу входят транскодеры, которые выполняют функции перекодирования голосового потока из одной системы кодирования в другую (A-law, μ-law, GSM, G723, G729 и.д.)
- Подсистема файлов — подсистема управляет чтением и записью различных форматов файлов.
Ядро выполняет следующие функции:
- Коммутация между подсистемами взаимодействия с источниками телефонного трафика.
- Запуск внешних приложений (например для голосовой почты)
- Преобразователь кодеков (автоматически выбирает подсистемы транскодеров)
- Планировщик задач внутри системы
В данной статье будет рассмотрен простой пример коммутации между подсистемами интерфейса каналов.
Подсистема интерфейса каналов #
Важно понять следующее. Каждая такая подсистема может иметь множество каналов. Например подсистема SIP может иметь множество телефонных номеров, а подсистема Dongle может иметь множество GSM-модемов. Каждый телефонный номер или каждый модем в системе Asterisk является каналом и в пределах Asterisk называется пиром (peer). В конфигурационных файлах все параметры каждого пира заключаются в блок, которому присваивается имя. Это имя и есть имя пира (или имя канала). Имя пира может быть использовано для маршрутизации вызова. Еще одним важным понятием является context — правила обработки вызовов (extensions) группируются в контексты, имена которых указываются в пирах как обработчики входящих вызовов. Вызовы, поступающие от нескольких пиров, могут обрабатываться одним и тем же контекстом. Например, группа абонентов, которые имеют доступ к звонкам на межгород имеет один контекст, а все остальные имеют другой контекст.
В каждом конфигурационном файле есть блоки базовых настроек. Это либо блок [general]
, где указываются базовые настройки подсисиемы, либо блок [defaults]
, где указываются базовые настройки пиров. Если у всех пиров какой-то один параметр одинаковый, например тип или контекст, то можно просто вынести его в блок [defaults]
и не дублировать каждый раз в каждом пире. Есть и другие способы группировки пиров, но о них в следующий раз.
Небольшой пример для подсистемы SIP (часть файла sip.conf без блока базовых настроек):
[5000]
type = friend
username = 5000
secret = 1234
context = from-sip-lines
[5001]
type = friend
username = 5001
secret = 1234
context = from-sip-lines
В данном примере описаны два пира с номерами (extensions) 5000
и 5001
. Тип обоих пиров — friend
, что означает то, что данные пиры могут как принимать вызовы, так и совершать. Имя пользователя для подключения по протоколу SIP у этих пиров совпадает с их телефонными номерами — самый простой способ, чтобы не запутаться, однако можно назначать любое имя пользователя для пиров. Пароль у обоих пиров в данном примере: 1234. Последний параметр — контекст. Контекст, который будет обрабатывать входящие вызовы, у обоих пиров одинаковый from-sip-lines
.
Теперь, когда мы будем конфигурировать правила обработки вызовов в файле extensions.conf, мы учтем следующее: Сконфигурирем набор правил маршрутизации для обработки входящих вызовов (контекст) from-sip-lines
, а направлять вызовы будем в сторону подсистемы SIP к пирам 5000
и 5001
.
Пример организации маршрутизации вызовов внутри SIP #
Теперь на основании полученных знаний, постараемся скоммутировать вызовы от абонента 5000
к абоненту 5001
и наоборот. В следующем примере будет указаны явные правила, хотя на самом деле так никто не делает, а использует маски и переменные. Но для начала, чтобы понимать как работают правила маршрутизации, это будет только сбивать с толку.
Итак дано: подсистема SIP
. Пиры 5000
и 5001
. Контекст обоих пиров from-sip-lines
.
Цель: в контексте from-sip-lines
обработать принимаемые вызовы, если получен адрес (extension) 5000
, то направить вызов на подсистему SIP к пиру 5000
, если получен адрес (extension) 5001
, то направить вызов на ту же подсистему SIP, но к пиру 5001
. Приступим к написанию данных правил (фрагмент файла extensions.conf без блока базовых настроек):
[from-sip-lines]
exten => 5000,1,Dial(SIP/5000)
exten => 5000,n,Hangup()
exten => 5001,1,Dial(SIP/5001)
exten => 5001,n,Hangup()
Повторюсь еще раз: данный пример не является хорошим, так как он не универсален: придется добавлять по две строчки для каждого нового телефонного номера. Данный пример специально написан таким образом, чтобы наглядно понимать принцип работы правил маршрутизации.
Первая строка — название группы правил (название контекста). Это название указывается в конфигурации пиров как значение параметра context
. Все вызовы, поступающие со стороны пиров будут обработаны правилами, входящими в указанный контекст.
Далее идут правила. Все правила начинаются с exten =>
, после чего идет адрес (экстеншн), который будет проверяться на совпадение с адресом поступившего вызова. Если вы на SIP-телефоне наберете цифры 5001 и нажмете вызов, то этот вызов поступит в подсистему маршрутизации с адресом 5001. Подсистема будет производить поиск правил, которым максимально соответствует поступивший адрес. Следующее поле - это номер по порядку правил. В новых версиях Asterisk нужно нумеровать только первое правило, а в остальных можно поставить просто n
и система пронумерует их автоматически в порядке написания в конфигурации. Третий параметр — действие. В нашем случае произойдет следующее: как только будет найдено первое подходящее правило для вызова, то будет выполнено действие, которое соответствует данному правилу, затем после окончания выполнения действия поиск будет продолжен и будет выполнено действие в следующем найденном правиле с таким же exten
, причем порядковый номер такого правила должен быть на единицу больше предыдущего.
Предположим, что абонент с номером 5000 вызывает абонента с номером 5001. Последовательность действий в нашей задаче будет следующая: в подсистему маршрутизации вызова поступает вызов от подсистемы SIP. Данный вызов характеризуется адресом (экстеншеном) 5001
и должен быть обработан контекстом from-sip-lines
. Подсистема маршрутизации первым делом должна найти блок правил (контекст) from-sip-lines
. Затем подсистема маршрутизации будет производить поиск наиболее точно подходящего правила из данного контекста, анализируя адрес (5001) и сравнивая его с фильтрами каждого из правил с порядковым номером 1. Наиболее удовлетворяющее правило (в нашем случае единственное) будет:
exten => 5001,1,Dial(SIP/5001)
После чего будет выполнено действие — Dial
, т.е. вызов. В качестве параметра для действия Dial
указано SIP/5001
— это означает, что вызов необходимо направить подсистеме SIP пиру 5001. При выполнении данного действия происходит создание канала (channel
), к которому подключается подсистема. Производится посылка вызова в сторону вызываемого абонента, затем коммутация, затем отбой. Или просто посылка вызова и отбой по таймауту, если трубку никто не поднял. После чего действие данного правила заканчивается.
После окончания действия правила, подсистема маршрутизации продолжает выполнение правил. На этот раз будет произведен поиск правила с порядковым номером 2, максимально удовлетворяющее адресу 5001. Таким правилом будет следующее за первым:
exten => 5001,n,Hangup()
В конфигурационном файле вместо порядковых номеров можно указать просто n
и подсистема маршрутизации автоматически пронумерует эти правила. На самом деле, после загрузки правил в подсистему маршрутизации, вместо символов n
уже стоят порядковые номера, так что это правило внутри системы выглядит вот так:
exten => 5001,2,Hangup()
Действием этого правила является — Hangup
, т.е. отбой. Эта команда безусловно завершает вызов.
После выполнения этого правила будет произведен поиск следующего правила с порядковым номером 3. Так как такого правила нет, дальнейшая обработка вызова не производится. Вызов считается завершенным.
Использование масок (шаблонов) для фильтров экстеншенов #
На самом деле крайне редко бывает ситуация, когда маски не применимы. Практически всегда экстеншены в правилах маршрутизации указываются в виде масок. Например, одной маской можно указать все внутренние телефонные линии SIP, одной маской можно указать сразу все междугородние вызовы, либо масками разделить вызовы по направлениям (мобильным операторам).
Фильтр экстеншенов (адресов вызываемых абонентов) может быть диалпланом или планом набора, т.е. цифры номера вызываемого абонента или маски номера, а так же может быть специальным экстеншеном. Вот специальные экстеншены, которые можно использовать вмето диалплана:
i
(invalid) — ошибка в набореs
(start) — входящий вызов без адресаh
(hangup) — после отбояt
(timeout) — по таймаутуT
(absolute timeout) — по системному таймауту asterisk
Например, после отбоя необходимо напечатать в консоль фразу «Call complete». Дополним наши правила в том же блоке файла extenstions.conf строкой:
exten => h,1,Verbose("Call complete")
В данном случае в качестве экстеншена используется не диалплан, а специальный экстеншн h
, правила по которому срабатывает после завершения вызова. Действием на данное правило будет команда Verbose
, которая предназначена для отладки. При выполнении этой команды происходит вывод в консоль аргумента, указанного в этой команде.
Теперь о масках (шаблонах) #
Если экстеншн записывается в виде шаблона, то он должен начинаться с символа подчеркивания _
.
В масках используются следующие символы:
X
— любая одна цифра от 0 до 9Z
— любая одна цифра от 1 до 9N
— любая одна цифра от 2 до 9[13-5]
— только одна цифра из возможных: 1, 3, 4 или 5.
— любые возможные символы в любом количестве больше нуля
Теперь в нашем примере вместо двух экстеншенов можно указать один: _500X
или даже _5ХХХ
. В первом случае под фильтр попадут все экстеншены от 5000 до 5009, а во втором от 5000 до 5999.
Но если мы сократим правило до одного, используя такую маску, то возникает вопрос: на какой экстеншн подсистемы SIP направлять вызовы?
Немного о переменных #
Система asterisk поддерживает работу с переменными. Переменные могут быть пользовательскими и содержать необходимые пользовательские данные и системные, которые содержат различные данные о вызове. Переменные записываются следующим образом: ${имя_переменной}
.
В данной статье затронем только одну переменную, которая содержит экстеншн (адрес). Это переменная ${EXTEN}
.
При поступлении вызова в переменной ${EXTEN}
содержится номер вызываемого абонента (адрес). Это нам и нужно для написания одного единственного правила для осуществления вызовов между абонентами SIP нашей системы.
Изменим блок в файле extensions.conf, чтобы он выглядел следующим образом:
[from-sip-lines]
exten => _5XXX,1,Dial(SIP/${EXTEN})
exten => _5XXX,n,Hangup()
exten => h,1,Verbose("Call complete")
Теперь можно добавлять сколько угодно четырехзначных номеров SIP, которые начинаются на цифру 5, в нашу систему и не беспокоиться о том, что вызовы между ними не будут работать.
Данное правило справедливо для всех вызовов, в адресе которых цифры от 5000 до 5999. И команда Dial
направит вызов подсистеме SIP на номер, который хранится в переменной ${EXTEN}
, то есть на номер, который набрал абонент.
После отбоя сработает правило h
и выдаст в консоль фразу «Call complete».
На этом всё. В следующей статье будет описана работа с модемами GSM.