Библиотека сайта rus-linux.net
Система Asterisk
Глава 1 из книги "Архитектура приложений с открытым исходным кодом", том 1.
Оригинал: Asterisk,
глава из книги "The Architecture of Open Source Applications" том 1.
Автор: Russell Bryant
Перевод: Н.Ромоданов
1.2. Компонентные абстракции системы Asterisk
Asterisk является приложением с высокой степенью модульности. Есть базовая часть приложения, которая собирается в каталоге исходного кода main/
. Но она, сама по себе, будет мало чем для вас полезной. Базовая часть приложения выступает, прежде всего, в роли реестра модулей. В базовой части также есть код, в котором указано, как соединять все абстрактные интерфейсы вместе для того, чтобы можно было пропускать через систему телефонные вызовы. Конкретные реализации этих интерфейсов будут регистрироваться модулями, загружаемыми на этапе выполнения программы.
Когда запускается базовая часть приложения, то по умолчанию загружаются все модули, найденные в предопределенных каталогах файловой системы. Этот подход был выбран как самый простой. Тем не менее, есть отдельный конфигурационный файл, в котором можно уточнить, какие модули и в каком порядке следует загружать. Из-за этого конфигурирование системы несколько усложняется и для такого способа настройки требует немного больше времени, но появляется возможность указывать, какие модули загружать не нужно. Преимущество этого подхода состояло, прежде всего, в экономии памяти, используемой приложением. Однако это также хорошо для соблюдения некоторого уровня безопасности. Лучше не загружать модуль, у которого есть возможность осуществлять соединения в сети, в том случае, если этот модуль в действительности не нужен.
После того, как модули будут загружены, в базовой части Asterisk происходит регистрация всех компонентных абстракций, реализованных в этих модулях. Есть большое количество типов интерфейсов, которые можно реализовать внутри модулей и зарегистрировать в базовой части Asterisk. С помощью модуля можно регистрировать столько различных интерфейсов, сколько необходимо. Обычно в один модуль группируются интерфейсы, функционально связанные друг с другом.
1.2.1. Драйверы каналов
Из всех интерфейсов, имеющихся в системе Asterisk, интерфейс драйверов каналов (channel driver) является наиболее сложным и наиболее важным. В API каналов системы Asterisk предоставляется абстракция телефонного протокола, что позволяет пользоваться всеми другими возможностями системы Asterisk независимо от того, какой конкретно используется телефонный протокол. На данный компонент возлагается обязанность осуществлять преобразование между абстракцией канала Asterisk и конкретными особенностями телефонной технологии, реализация которой скрыта с помощью этой абстракции.
Интерфейсом драйверов каналов Asterisk является интерфейс ast_channel_tech
. В нем определяется набор методов, которые должны быть реализованы в драйвере канала. Первым методом, который должен быть реализован в драйвере канала, является метод фабрики ast_channel
, который представляет собой метод requester
объекта ast_channel_tech
. Когда создается канал Asterisk для входящего или исходящего телефонного вызова, то с типом канала ассоциируется реализация объекта ast_channel_tech
, который для этого вызова должен создавать конкретный экземпляр объекта ast_channel
и осуществлять его инициализацию.
Когда объект ast_channel
создан, он будет ссылаться на объект ast_channel_tech
, с помощью которого он был создан. Есть много других операций, которые должны обрабатываться вполне конкретным способом, зависящем от технологических особенностей. Когда в канале ast_channel
должны выполняться такие операции, то их выполнение происходит через обращение к соответствующему методу в объекте ast_channel_tech
. На рис.1.2 показаны два канала в системе Asterisk. На рис.1.4 видно, как уровни абстракции и конкретные реализации вписываются в архитектуру Asterisk.
Рис.1.4: Слой технологической реализации канала и абстрактный слой канала
Наиболее важными методами в ast_channel_tech
являются следующие:
requester:
Эта функция обратного вызова используется для запроса драйвер канала для создания экземпляра объектаast_channel
и инициализировать его так, как это требуется для канала этого типа.call:
Эта функция обратного вызова используется для инициирования исходящего вызова к конечной точке, представленной в объектеast_channel
.Answer:
Этот метод вызывается, когда система Asterisk решает, что должна ответить на входящий вызов, связанный с данным объектомast_channel
.hangup:
Этот метод вызывается, когда система определяет, что нужно завершить вызов. После этого драйвер канала передаст конечному устройству сообщение в виде, соответствующему используемому протоколу, о том, что разговор завершен.indicate:
Когда поступает вызов, то может произойти ряд событий, о которых нужно просигнализировать конечному устройству. Например, если устройство переводит вызов в режим удержания, то вызывается эта функция обратного вызова, которая сообщает о возникшем состоянии. Может быть применен метод, соответствующему используемому протоколу, который указывает, что вызов находится на удержании, либо драйвер канала может в ожидающем устройстве просто начать воспроизведение музыки.send_digit_begin:
Эта функция вызывается с тем чтобы указать на начало набора тонального сигнала (DTMF) на устройстве по другую сторону канала.send_digit_end:
Эта функция вызывается с тем чтобы указать на завершение набора тонального сигнала (DTMF) на устройстве по другую сторону канала.read:
Эта функция вызывается базовой частью системы Asterisk с тем, чтобы повторить (ast_frame
), полученный от этого конечного устройства. (ast_frame
) яляется абстракцией в Asterisk, которая используется для инкапсуляции медиаданных (например, аудио или видео данных), а также для сигнализации о событиях.write:
Эта функция используется для отправки фреймаast_frame
к данному устройству. Драйвер канала возьмет данные и упакует их согласно телефонному протоколу, который реализован и используется для передачи данных в конечное устройство.Bridge:
Это функция обратного вызова нативного моста для канала данного типа. Как уже говорилось ранее, создание нативного моста происходит, когда драйвер канала может реализовать более эффективный мост для двух каналов одного и того же типа, а не направлять все сигналы и медиаданные через дополнительные ненужные слои абстракции. Это исключительно важно для повышения производительности.
После того, как вызов завершится, код абстрактного канала, который работает в базовой части Asterisk, обратится к функции обратного вызова ast_channel_tech hangup
и уничтожит объект ast_channel
.
1.2.2. Приложения планирования прохождения вызовов (dialplan)
Администраторы системы Asterisk настраивают маршруты прохождения вызовов с помощью плана Asterisk dialplan, который находится в файле /etc/asterisk/extensions.conf
. Dialplan состоит из наборов правил, которые называются расширениями (extensions). Когда в систему поступает новый телефонный вызов, набранный номер используется для того, чтобы найти в dialplan-е расширение, которое должно использоваться для обработки данного вызова. В расширении указывается список приложений dialplan, которые должны быть выполнены для данного канала. Приложения, доступные для выполнения в dialplan-е, регистрируются в реестре приложений. Этот регистр заполняется во время загрузки модулей в систему.
В состав Asterisk входит почти две сотни приложений. Определение приложения очень свободное. В приложениях для взаимодействия с каналами могут использоваться любые внутренние интерфейсы API, имеющиеся в системе Asterisk. Некоторые приложения выполняют одну задачу, например, приложение Playback
, которое для вызывающего проигрывает звуковой файл. Другие приложения вовлечены вовлечены в работу системы в большей степени и выполняют очень большое количество операций, как, например, приложение Voicemail
.
Благодаря тому, что используется Asterisk dialplan, несколько приложений можно объединять вместе для того, чтобы можно было выполнять специальную обработку вызовов. На случай, когда необходима более специализированная настройка, выходящая за рамки возможностей языка, предоставляемого в dialplan, есть скриптовые интерфейсы, которые позволяют выполнять специализированную обработку вызовов с использованием любого языка программирования. Даже в тех случаях, когда используются такие скриптовые интерфейсы с другими языками программирования, можно при взаимодействии с каналом продолжать обращаться к приложениям dialplan.
Прежде, чем мы перейдем к примеру, давайте посмотрим на синтаксис Asterisk dialplan, в котором обрабатываются вызовы с номером 1234
. Заметьте, что номер 1234
выбран произвольным образом. Здесь вызываются три приложения dialplan. Первое, отвечающее на вызов. Следующее, проигрывающее звуковой файл. Заключительное, завершающее вызов.
; Определение правил, используемых в случае набора номера 1234. ; exten => 1234,1,Answer() same => n,Playback(demo-congrats) same => n,Hangup()
Ключевое слово exten
используется для определения расширения. В правой части строки exten
цифры 1234
означают, что мы определяем правила для случая набора номера 1234
. Следующая 1
означает, что это первый шаг, который нужно сделать, когда будет набран данный номер. Наконец, Answer
указывает, что система должна ответить на вызов. Следующие две строки, которые начинаются с ключевого слова same
, являются правилами для последнего расширения, для которого было задано определения, в данном случае — для 1234
. Если кратко, то n
означает, что делается следующий шаг. В последнем элементе каждой из этих строк, определяется, какое действие должно быть выполнено.
Ниже приведен еще один пример использования Asterisk dialplan. В этом случае система ответит на входящий вызов. Будет воспроизведен звуковой сигнал (beep), а затем в переменной DIGITS
будет запомнено до четырех нажатых клавиш. Затем запомненные значения клавиш будут прочитаны и переданы вызывающей стороне. Наконец, вызов будет завершен.
exten => 5678,1,Answer() same => n,Read(DIGITS,beep,4) same => n,SayDigits(${DIGITS}) same => n,Hangup()
Как уже упоминалось ранее, определение приложения является весьма свободным – зарегистрированный прототип функции очень простой:
int (*execute)(struct ast_channel *chan, const char *args);
Однако в действительности, в реализациях приложений могут использоваться все интерфейсы API, которые есть в include/asterisk/
.
Продолжение статьи: Функции dialplan.