Глава 15

Внешние службы

Поправьте меня, если я ошибаюсь – эта штуковина подключена

к флинфлангу, подключенному к ватзи, ватзи,

связанному с ду-папой, подключенным к

дин-донгу.

– Патрик Б. Олифант.

Asterisk довольно изящен сам по себе, но один из самых мощных, меняющихся в отрасли, революционных аспектов Asterisk – это огромное количество замечательных способов подключения к внешним приложениям и службам. Это поистине беспрецедентно в мире телекоммуникаций. В этой главе мы рассмотрим некоторые популярные сервисы и приложения, которые можно интегрировать с системой Asterisk. Вот некоторые из внешних связей, которые мы решили охватить (Asterisk может больше, но наш редактор ждет нас, чтобы закончить это издание, которое уже является самой большой книгой Asterisk):

  • Если вы используете Lightweight Directory Access Protocol (LDAP) в вашей сети (например, с Active Directory) мы покажем вам как загружать пользователей SIP из ваших служб LDAP.
  • Для человека, находящегося в пути с динамически изменяющимся календарем, мы попробуем некоторые идеи того, как вы можете интегрировать Asterisk с сервером календаря (что позволяет автоматически перенаправлять вызовы в зависимости от вашего текущего статуса).
  • Если вы фанат обмена мгновенными сообщениями – есть раздел о том, как общаться с Asterisk по протоколу XMPP (Jabber).
  • Если вы хотите привязать свою голосовую почту к вашему серверу Internet Message Access Protocol (IMAP) мы познакомим вас с основами.
  • Хотите научить свою телефонную систему читать? Мы рассмотрим основы преобразования текста в речь.

Есть еще много внешних сервисов, к которым Asterisk может подключиться, но мы полагаем, что именно они помогут вам лучше понять, как интегрировать внешние службы с Asterisk.

Интеграция календаря

Asterisk может быть интегрирован с несколькими различными типами форматов календаря, такими как iCal, CalDAV, MS Exchange (Exchange 2003) и веб-службы MS Exchange (Exchange 2007 и более поздние версии). Интеграция Asterisk с вашим календарем дает возможность управлять маршрутизацией вызовов на основе текущей информации календаря. Например, если вы не собираетесь находиться в офисе днем, возможно, имеет смысл направить абонентов, звонящих на ваш настольный телефон, прямо на вашу голосовую почту.

Еще одним преимуществом интеграции календаря является возможность инициировать вызовы на основе информации календаря. Например, если вы назначаете собрание на своем сервере конференции, то можете организовать напоминание за пять минут до начала собрания, после чего вы попадете в конференц-зал. Мы думаем, что этот тип гибкости и интеграции довольно изящен и весьма полезен.

Компиляция поддержки календаря в Asterisk

Поскольку существует несколько модулей для поддержки календаря (что позволяет нам предоставлять поддержку для различных бэкэндов, таких как MS Exchange, CalDAV, iCal и т.д.), Вам необходимо установить зависимости для бэкэндов, которые вы хотите поддерживать. Эта модульная установка имеет преимущество, поскольку вам нужно устанавливать зависимости только для тех модулей, которые вам нужны; кроме того, другие бэкэнды могут быть легко интегрированы с основным бэкэндом календаря в будущем.

Из-за различных зависимостей каждого модуля нам нужно проверить menuselect на предмет того, что необходимо установить для каждого из модулей календаря, которые мы хотим поддерживать. Все модули требуют библиотеку разработки neon. Для res_calendar_ews (веб-службы Exchange) требуется версия 0.29 или более поздняя, что означает, что в некоторых дистрибутивах вам потребуется компилировать библиотеку neon из исходного кода вместо использования предварительно скомпилированного пакета, доступного в дистрибутиве.

Хотя конфигурация для всех модулей календаря схожа, мы будем обсуждать интеграцию CalDAV специально, поскольку она широко поддерживается рядом программных средств и серверов календаря.1

Зависимости RHEL

Поскольку для всех модулей требуется библиотека neon, сначала мы установим ее:

$ sudo yum install neon-devel

Если вы планируете скомпилировать модуль res_calendar_ews вам потребуется neon версии 0.29 или новее. В настоящее время RHEL 6.x поставляется с 0.29. Если вы используете более старую версию RHEL, то придется скомпилировать библиотеку neon и сделать ссылку на нее из скрипта configure. Это можно сделать через ./configure –with-neon29=<путь к neon>.

Следующим шагом является установка зависимости libical-devel:

$ sudo yum install libical-devel

Версии RHEL до 6.x требуют стороннего репозитория (см. “Сторонние репозитории” в Главе 3). В этом случае для старых версий RHEL необходимо установить libical-devel из репозитория EPEL (Extra Packages for Enterprise Linux):

$ sudo yum –enablerepo=epel install libical-devel

После установки наших зависимостей мы можем запустить скрипт configure в нашем каталоге исходников Asterisk и включить оба модуля res_calendar и res_calendar_caldav в разделе Resource Modules из menuselect.

Зависимости Ubuntu

Поскольку для всех модулей требуется библиотека разработки neon, нам необходимо сначала установить ее. Мы собираемся установить последнюю доступную нам версию:

$ sudo apt-get install libneon27-dev

Если вы планируете скомпилировать модуль res_calendar_ews вам потребуется neon 0.29 или выше. В настоящее время Ubuntu поставляется с 0.27, поэтому вам придется скомпилировать библиотеку neon и сделать ссылку на нее из скрипта configure. Это можно сделать через ./configure –with-neon29=<путь к neon>.

С установленной libneon теперь мы можем установить пакет libical-dev и его зависимости через apt-get:

$ sudo apt-get install libical-dev

После установки наших зависимостей мы можем запустить скрипт configure в нашем каталоге исходников Asterisk и включить оба модуля res_calendar и res_calendar_caldav из раздела Resource Modules menuselect.

Настройка поддержки календаря для Asterisk

В этом разделе мы обсудим как подключить систему Asterisk к календарю Google. Мы используем календари от Google по той простой причине, что им не требуются никакие другие настройки (например, настройка сервера календарей), что позволит нам быстрее запуститься и работать. Конечно, как только вы освоите настройку поддержки календарей в Asterisk, вы можете подключить ее к любому календарному серверу, который пожелаете.

Первый шаг – убедиться, что у вас есть аккаунт Gmailу Google, который даст вам доступ к серверу календаря. После того, как вы вошли в свою учетную запись Gmail, в верхнем левом углу (возможно уже в другом месте – прим. переводчика) должна быть ссылка на ваш календарь. Нажмите на ссылку Календарь и вставьте пару элементов, происходящих в течение следующего часа или двух. Когда мы будем настраивать наш calendar.conf, то будем инструктировать Asterisk проверять наличие новых событий каждые 15 минут и получать данные за 60 минут.

Не забудьте проверить время на вашем сервере. Если время не синхронизировано с остальным миром – например, если оно не обновляется через Network Time Protocol (NTP) – ваши события могут не отображаться или могут появляться в неправильное время. Этот совет является результатом столкновения с этой самой проблемой при тестировании и документировании. 🙂

Следующим шагом является настройка файла calendar.conf для опроса календарного сервера.

В файле calendar.conf.sample есть несколько примеров серверов календарей, например, серверы календарей на базе Microsoft Exchange, iCal и CalDAV.

Следующая конфигурация будет подключаться к серверу календаря Google и каждые 15 минут опрашивать новые события, получая данные за 60 минут. Не стесняйтесь изменять эти настройки по мере необходимости, но помните, что получение большего количества данных (особенно если у вас есть несколько календарей для сотрудников вашей компании) будет использовать больше памяти:

$ cat >> calendar.conf

[myGoogleCal]

type=caldav

url=https://www.google.com/calendar/dav/<Gmail Email Address>/events/

user=<Gmail Email Address>

secret=<Gmail Password>

refresh=15

timeframe=60

Ctrl+D

Если calendar.conf настроен, давайте загрузим модули календаря в Asterisk. Сначала мы загрузим модуль res_calendar.so в память, а затем проследим за ним, выполнив module reload, которая загрузит дочерние модули (например, res_calendar_caldav.so) правильно:2

$ asterisk -r

*CLI> module load res_calendar.so

*CLI> module reload

После загрузки модулей мы можем убедиться, что наш календарь подключен к серверу и правильно загружен в память, выполнив calendar show calendars:

*CLI> calendar show calendars

Calendar Type Status

——– —- ——

myGoogleCal caldav busy

Наш статус в настоящее время установлен на busy (что не имеет никакого отношения к нашей абонентской группе на данный момент, это просто означает, что у нас есть событие, которое пометило нас в календаре как занятого) и мы можем увидеть загруженные в данный момент события для нашего временного диапазона, запустив calendar show calendar <myGoogleCal> из консоли Asterisk:

*CLI> calendar show calendar <myGoogleCal>

Name : myGoogleCal

Notify channel :

Notify context :

Notify extension :

Notify applicatio :

Notify appdata :

Refresh time : 15

Timeframe : 60

Autoreminder : 0

Events

——

Summary : Awesome Call With Russell

Description :

Organizer :

Location :

Cartegories :

Priority : 0

UID : hlfhcpi0j360j8fteop49cvk68@google.com

Start : 2010-09-28 08:30:00 AM -0400

End : 2010-09-28 09:00:00 AM -0400

Alarm : 2010-09-28 04:20:00 AM -0400

Первое поле в верхнем разделе – это название нашего календаря. После этого есть несколько полей Notify, которые используются для набора адресата в начале собрания, которое мы обсудим более подробно в ближайшее время. Поля Refresh time и Timeframe являются значениями, которые мы сконфигурировали для частоты проверки наличия новых событий и долготы просмотра диапазона данных, соответственно. Поле Autoreminder определяет, за сколько до события мы должны выполнять опции Notify .

Если вы не настроили ни один из параметров Notify, но в календаре установлено оповещение, вы можете получить следующее WARNING сообщение:

WARNING[5196]: res_calendar.c:648 do_notify: Channel should be in

form Tech/Dest (was ”)

Предупреждение вызвано тем, что для уведомления о начале собрания было установлено оповещение, но Asterisk не удалось сделать вызов из-за значений, не настроенных для совершения вызова. Это предупреждение можно проигнорировать, если вы не планируете выполнять вызовы для уведомлений о событиях.

Остальная часть вывода на экран – это список событий, доступных на нашем Timeframe вместе с информацией о событиях. Далее мы посмотрим на некоторые примеры диалплана, которые можем выполнить сейчас, когда у нас есть информация календаря в Asterisk, и настроим уведомления о вызовах для напоминаний о предстоящих встречах.

Запуск напоминаний календаря на вашем телефоне

В этом разделе мы обсудим, как настроить файл calendar.conf для выполнения некоторого простого диалплана, который будет звонить на ваш телефон до события календаря. Хотя представленный нами диалплан может быть не готов к полноценной работе, он, безусловно, предлагает обзор возможностей для совершения вызова на основе события календаря.

Запуск вызова будильника

В нашем первом примере мы собираемся вызвать устройство и воспроизвести напоминание для определенного события календаря. Может быть полезно получить напоминания такого типа, если вы, вероятно, дремлете за столом в то время, когда проходит еженедельная встреча в понедельник. Чтобы настроить напоминание о пробуждении, нам просто нужно добавить следующие строки в конфигурацию нашего календаря в calendar.conf:

channel=SIP/0000FFFF0001

app=Playback

appdata=this-is-yr-wakeup-call

В календаре необходимо убедиться, что с добавляемым событием связан сигнал тревоги или напоминание. В противном случае Asterisk не будет пытаться создать вызов.

После внесения этого изменения перезагрузите модуль res_calendar.so из консоли Asterisk:

*CLI> module reload res_calendar.so

Когда событие наступит Asterisk сгенерирует вам звонок и воспроизведет звуковой файл this-is-yr-wakeup-call. Вывод в консоль будет выглядеть следующим образом:

— Dialing SIP/0000FFFF0001 for notification on calendar myGoogleCal

== Using SIP RTP CoS mark 5

— Called 0000FFFF0001

— SIP/0000FFFF0001-00000001 is ringing

— SIP/0000FFFF0001-00000001 connected line has changed, passing it to

Calendar/myGoogleCal-5fd3c52

— SIP/0000FFFF0001-00000001 answered Calendar/myGoogleCal-5fd3c52

— <SIP/0000FFFF0001-00000001> Playing ‘this-is-yr-wakeup-call.ulaw’

(language ‘en’)

Если вы измените событие календаря таким образом, что оно начнется всего через пару минут в будущем, вы можете быстро инициировать события, выгрузив, а затем загрузив модуль res_calendar_caldav.so из консоли Asterisk. Сделав это, вы заставите Asterisk немедленно сгенерировать вызов.

Помните, что наша частота обновления установлена на 15 минут и мы собираем события за 60 минут. Возможно, вам придется изменить эти цифры, если вы захотите проверить это на своем сервере.

Планирование вызовов между двумя участниками

В этом примере мы покажем, как можно использовать комбинацию простого диалплана и функции CALENDAR_EVENT() для создания вызова между двумя участниками на основе информации в поле местоположения. Мы собираемся заполнить поле местоположение как 0000FFFF0002, которое является SIP-устройством, которое мы хотим вызвать после ответа на наше напоминание.

Мы не указали SIP/0000FFFF0002 непосредственно в событии календаря, потому что мы хотим быть более осторожными с тем, что принимаем. Поскольку мы будем отфильтровывать все, кроме буквенно-цифровых символов, мы не сможем принять косую черту в качестве разделителя между технологией и местоположением (например, SIP/0000FFFF0001). Мы могли бы, конечно, позволить это, но подвергаемся риску совершения людбми дорогих исходящих звонков, особенно если пользователь открывает свой календарь публично или если он был скомпрометирован. С помощью метода, который собираемся использовать, мы просто ограничиваем наш риск.

Добавим следующий диалплан в наш extensions.conf:

[AutomatedMeetingSetup]

exten => start,1,Verbose(2,Triggering meeting setup for two participants)

same => n,Set(DeviceToDial=${FILTER(0-9A-Za-z,${CALENDAR_EVENT(location)})})

same => n,Dial(SIP/${DeviceToDial},30)

same => n,Hangup()

Когда время события наступит – наше устройство получит вызов и при ответе на этот вызов другой вызов будет направлен на конечную точку, с которой мы хотим провести нашу встречу. Вывод в консоль выглядит следующим образом:

Здесь наш календарь запускает вызов на наше устройство

— Dialing SIP/0000FFFF0001 for notification on calendar myGoogleCal

== Using SIP RTP CoS mark 5

— Called 0000FFFF0001

— SIP/0000FFFF0001-00000004 is ringing

И вот мы ответили на звонок Астериска, вызванный событием

— SIP/0000FFFF0001-00000004 connected line has changed, passing it to

Calendar/myGoogleCal-347ec99

— SIP/0000FFFF0001-00000004 answered Calendar/myGoogleCal-347ec99

После ответа мы инициируем некоторый диалплан, который ищет оконечную точку для вызова

— Executing

[start@AutomatedMeetingSetup:1]

Verbose(“SIP/0000FFFF0001-00000004”, “2,

Triggering meeting setup for two participants”) in new stack

== Triggering meeting setup for two participants

Здесь мы использовали CALENDAR_EVENT(location) для удаленного устройства

— Executing

[start@AutomatedMeetingSetup:2]

Set(“SIP/0000FFFF0001-00000004”,

“DeviceToDial=0000FFFF0002”) in new stack

И теперь мы вызываем эту конечную точку

— Executing

[start@AutomatedMeetingSetup:3]

Dial(“SIP/0000FFFF0001-00000004”,

“SIP/0000FFFF0002,30”) in new stack

== Using SIP RTP CoS mark 5

— Called 0000FFFF0002

— SIP/0000FFFF0002-00000005 is ringing

Другой конец ответил на звонок и Asterisk соединил нас вместе

— SIP/0000FFFF0002-00000005 answered SIP/0000FFFF0001-00000004

— Locally bridging SIP/0000FFFF0001-00000004 and SIP/0000FFFF0002-00000005

Конечно, диалплан мог бы быть расширен, чтобы заставить первоначального абонента подтвердить готовность к встрече до вызова другого участника. Аналогично, мы могли бы добавить диалплан, который воспроизводит подсказку для другого абонента, которая сообщает ему что он запланировал встречу и если он нажмет 1, то будет немедленно соединен с другой стороной. Мы могли бы даже создать диалплан, который позволил бы исходной стороне записать сообщение для воспроизведения другому абоненту.

Просто для удовольствия мы покажем вам пример функциональности, которую мы только что описали. Не стесняйтесь изменять его в соответствии с вашими пожеланиями:

[AutomatedMeetingSetup]

exten => start,1,Verbose(2,Triggering meeting setup for two participants)

; *** Эта строка не должна содержать разрывов

same => n,Read(CheckMeetingAcceptance,to-confirm-wakeup&press-1&otherwise

&press-2,,1)

same => n,GotoIf($[“${CheckMeetingAcceptance}” != “1”]?hangup,1)

same => n,Playback(silence/1&pls-rcrd-name-at-tone&and-prs-pound-whn-finished)

; Мы устанавливаем случайное число и присваиваем его по окончанию записи,

; чтобы у нас было уникальное имя файла, если оно используется

; несколькими людьми одновременно.

;

; Мы также добавили префикс – двойное подчеркивание, потому что канальная

; переменная также должна быть доступна каналу, который мы собираемся вызвать

;

same => n,Set(__RandomNumber=${RAND()})

same => n,Record(/tmp/meeting-invite-${RandomNumber}.ulaw)

same => n,Set(DeviceToDial=${FILTER(0-9A-Za-z,${CALENDAR_EVENT(location)})})

same => n,Dial(SIP/${DeviceToDial},30,M(CheckConfirm))

same => n,Hangup()

exten => hangup,1,Verbose(2,Call was rejected)

same => n,Playback(vm-goodbye)

same => n,Hangup()

[macro-CheckConfirm]

exten => s,1,Verbose(2,Allowing called party to accept or reject)

same => n,Playback(/tmp/meeting-invite-${RandomNumber})

; *** Эта строка не должна содержать разрывов

same => n,Read(CheckMeetingAcceptance,to-confirm-wakeup&press-1&otherwise

&press-2,,1)

same => n,GotoIf($[“${CheckMeetingAcceptance}” != “1”]?hangup,1)

exten => hangup,1,Verbose(2,Call was rejected by called party)

same => n,Playback(vm-goodbye)

same => n,Hangup()

Мы надеемся, что вы Вы сможете использовать этот простой пример диалплана в качестве отправной точки. С небольшим творческим потенциалом и некоторыми навыками диалплана, возможности безграничны!

Вызов участников собрания и размещение их в конференции

Чтобы расширить функциональные возможности, описанные в предыдущем разделе, мы рассмотрим логическую проблему размещения нескольких участников собрания. Наша цель состоит в том, чтобы использовать наш календарь для вызовов нам когда планируется начать собрание, а затем, когда мы отвечаем, делать звонки всем другим участникам конференции. По мере того как другие участники будут отвечать на телефонные звонки, они будут помещены в виртуальный конференц-зал, где станут ждать присоединения организатора собрания. После того, как все участники были вызваны и ответили (или, возможно, не ответили), будет вызван организатор, после чего начнется собрание.

Этот тип функциональности увеличивает вероятность того, что собрание начнется вовремя, и это означает, что организатору собрания не нужно постоянно выполнять перекличку, поскольку новые участники продолжают присоединяться после того, как вызов должен начаться (что неизменно происходит с людьми, чьи графики обычно довольно загружены).

Диалплан, который мы покажем вам, не обязательно является отлаженной, готовой к продакшену установкой (например, данные, возвращаемые из календаря, поступающие из поля описания, имеют дело только с именами устройств и предполагают технологию SIP). Тем не менее, мы проделали тяжелую работу для вас, разработав использование локального канала вместе с использованием флага M() (макроса) с Dial(). После некоторого тестирования и настроек этот код, безусловно, можно было бы доработать более полно для вашей конкретной конфигурации, но мы придерживались его общего порядка, чтобы он мог использоваться для большего количества людей в более сложных ситуациях. Пример диалплана выглядит следующим образом:

[AutomatedMeetingSetup]

exten => start,1,Verbose(2,Calling multiple people and placing into a conference)

; Получить информацию из календаря и сохранить ее. Префикс CalLocation с

; подчеркиванием чтобы он был доступен локальному каналу (наследование

; переменных).

;

same => n,Set(CalDescription=${CALENDAR_EVENT(description)})

same => n,Set(_CalLocation=${CALENDAR_EVENT(location)})

same => n,Set(X=1)

; Наш разделитель это карет (^), поэтому описание будет в формате:

; 0000FFFF0001^0000FFFF0002^итд…

;

same => n,Set(EndPoint=${CUT(CalDescription,^,${X})})

; Этот цикл используется для построения переменной ${Toroidal}, которая

; содержит список локальных каналов для набора, тем самым вызывая несколько

; действий Originate() одновременно, а не линейно

;

same => n,While($[${EXISTS(${EndPoint})}])

; Этот оператор должен находиться в одной строке

same => n,Set(ToDial=${IF($[${ISNULL(${ToDial})}]?

:${ToDial}&)}Local/${EndPoint}@MeetingOriginator)

same => n,Set(X=$[${X} + 1])

same => n,Set(EndPoint=${CUT(CalDescription,^,${X})})

same => n,EndWhile()

; Если никакие значения не возвращаются, то не утруждайте себя набором номера

same => n,GotoIf($[${ISNULL(${ToDial})}]?hangup)

same => n,Dial(${ToDial})

; После возврата оператора Dial() нас следует поместить в конференц-зал.

; Мы маркированы, поэтому конференция может начаться

; (что обозначается флагом ‘A’ в MeetMe).

;

same => n,MeetMe(${CalLocation},dA)

same => n(hangup),Hangup()

[MeetingOriginator]

exten => _[A-Za-z0-9].,1,NoOp()

same => n,Set(Peer=${FILTER(A-Za-z0-9,${EXTEN})})

; Originate вызывает пира, переданного из канала Local. После ответа

; вызываемая сторона должна выполнить диалплан, расположенный в расширении

; _meetme-XXXX, где XXXX номер конференц-зала.

;

same => n,Originate(SIP/${Peer},exten,MeetingOriginator,meetme-${CalLocation},1)

same => n,Hangup()

; Присоединиться к собранию; используя флаг ‘w’, что означает

; ‘ждать присоединения маркированного пользователя для начала’

;

exten => _meetme-XXXX,1,Verbose(2,Joining a meeting)

same => n,Answer()

same => n,MeetMe(${EXTEN:7},dw)

same => n,Hangup()

Управление вызовами на основе информации календаря

Иногда полезно автоматически перенаправлять вызовы, например, когда вы находитесь на собрании или в отпуске. В этом разделе мы будем использовать функцию диалплана CALENDAR_BUSY(), которая позволяет нам проверять текущее состояние нашего календаря чтобы определить заняты мы или нет. Простым примером этого может быть отправка всех вызовов на голосовую почту с использованием сообщения «занято», когда запланировано событие, которое помечает нас как «занятых».

В следующем диалплане показан простой пример, в котором мы проверяем наш календарь на занятость перед отправкой вызова на устройство. Обратите внимание, что большая часть информации в этом примере является статической; потребовалось бы больше усилий, чтобы сделать её динамической и пригодной для продакшена:

exten => 3000,1,Verbose(2,Simple calendar busy check example)

same => n,Set(CurrentExten=${EXTEN})

same => n,Set(CalendarBusy=${CALENDAR_BUSY(myGoogleCal)})

same => n,GotoIf($[“${CalendarBusy}” = “1”]?voicemail,1)

same => n,Dial(SIP/0000FFFF0002,30)

same => n,Goto(voicemail,1)

exten => voicemail,1,Verbose(2,Caller sent to voicemail)

; *** Эта строка не должна содержать разрывов

same => n,GotoIf($[“${DIALSTATUS}” = “BUSY” |

“${CalendarBusy}” = “1”]?busy:unavail)

same => n(busy),VoiceMail(${CurrentExten}@shifteight,b)

same => n,Hangup()

same => n(unavail),VoiceMail(${CurrentExten}@shifteight,u)

same => n,Hangup()

А вот немного более сложный раздел диалплана, в котором используются некоторые из инструментов, которые мы изучили на протяжении всей книги, включая функции DB_EXISTS(), GotoIf() и IF():

exten => _3XXX,1,Verbose(2,Simple calendar busy check example)

same => n,Set(CurrentExten=${EXTEN})

same => n,GotoIf($[${DB_EXISTS(extension/${CurrentExten}/device)}]?

:no_device,1)

same => n,Set(CurrentDevice=${DB_RESULT})

same => n,GotoIf($[${DB_EXISTS(extension/${CurrentExten}/calendar)}]?

:no_calendar)

same => n,Set(CalendarBusy=${CALENDAR_BUSY(${DB_RESULT})})

same => n,GotoIf($[${CalendarBusy}]?voicemail,1)

same => n(no_calendar),Verbose(2,No calendar was found for this user)

same => n,Dial(SIP/${CurrentDevice},30)

same => n,Goto(voicemail,1)

exten => voicemail,1,Verbose(2,Sending caller to voicemail)

; *** Эта строка не должна содержать разрывов строк

same => n,GotoIf($[${DB_EXISTS(extension/${CurrentExten}/voicemail_context)}]

?:no_voicemail)

same => n,Set(VoiceMailContext=${DB_RESULT})

; *** Эта строка не должна содержать разрывов строк

same => n,Set(VoiceMailStatus=${IF($[“${DIALSTATUS}” = “BUSY” |

0${CalendarBusy}]?b:u)})

same => n,VoiceMail(${CurrentExten}@${VoiceMailContext},${VoiceMailStatus})

same => n,Hangup()

same => n(no_voicemail),Playback(number-not-answering)

same => n,Hangup()

exten => no_device,1,Verbose(2,No device found in the DB)

same => n,Playback(invalid)

same => n,Hangup()

Запись информации о вызове в календарь

С помощью функции CALENDAR_WRITE() открываются некоторые другие возможности в плане интеграции календаря. Из абонентской группы Asterisk мы можем вставить в календарь информацию, которую могут использовать другие устройства и приложения. Наш следующий пример – календарь, который отслеживает журналы вызовов. Для любого, кто изрядно разговаривает по телефону, кому нужно отслеживать время обзвона клиентов, записывать все звонки в календарь для наглядной справки может быть полезна при проверке дел в конце дня.

Мы собираемся снова использовать веб-календарь Google для этого примера, но теперь собираемся создать новый отдельный календарь только для отслеживания вызовов. Для записи в календарь нам нужно настроить файл calendar.conf немного по-другому, используя формат календаря CalDAV. Однако сначала нам нужно создать наш новый календарь.

С левой стороны интерфейса календаря Google будет ссылка с надписью Add (Добавить). Нажатие на нее откроет новое окно, где мы можем создать календарь. Мы назвали наш «Phone Calls» (Телефонные звонки).

Теперь нам нужно включить синхронизацию календаря CalDAV для нашего календаря. Информация о том, как это сделать, находится на странице поддержки Google. На этой странице отмечается, что только ваш основной календарь будет синхронизирован с устройством, но мы хотим чтобы наши звонки регистрировались в отдельном календаре, чтобы их можно было легко скрыть (и чтобы наш смартфон не синхронизировал звонки телефона, что может вызвать путаницу). В нижней части страницы есть две ссылки: одна для обычных пользователей календаря Google, а другая для пользователей Google Apps. Когда мы нажимаем на соответствующую ссылку, появляются наши календари. Затем мы видим страницу, которая содержит наши календари. Мы выбираем календарь Phone Calls (Телефонные звонки) и затем выбираем Save (Сохранить).

Далее настраивается наш calendar.conf для Asterisk. Одним из необходимых нам параметров является ссылка на календарь CalDAV. Существует Calendar ID – значение, которое нужно нам, оно будет определять наш календарь. Чтобы найти идентификатор календаря, нажмите стрелку вниз рядом с именем календаря в левой части страницы календаря и выберите Calendar Settings (Настройки календаря). В нижней части настроек календаря будут две строки, которые содержат значки для совместного использования календаря (XML, ICAL, HTML). Рядом с первым набором значков внутри поля Calendar Address (Адрес календаря) будет идентификатор календаря. Он будет выглядеть следующим образом:

(Calendar ID: 2hfb6p5974gds924j61cmg4gfd@group.calendar.google.com)

Если вы настраиваете его с помощью Google Apps перед идентификатором календаря будет стоять префикс вашего имени домена и подчеркивания (например shiftteight.org_). Запишите эту строку, так как мы собираемся использовать ее далее.

Откройте файл calendar.conf и добавьте новый раздел календаря. В нашем случае мы назвали его [phone_call_calendar]. Вы узнали форматирование календаря ранее, поэтому мы не будем проходить через все настройки снова. Ключевой настройкой для заметки является параметр url. Формат этого параметра

Нам нужно заменить <calendar_id> идентификатором календаря, который мы недавно нашли. Полная конфигурация в итоге выглядит следующим образом:

[phone_call_calendar]

type=caldav

; URL-адрес должен быть в одну строку

url=https://www.google.com/calendar/dav/

shifteight.org_2hfb6p5974gds924j61cmg4gfd@group.calendar.google.com/events/

user = leif@shifteight.org

secret = my_secret_password

refresh=15

timeframe=120

Теперь, когда у нас настроен календарь, нам нужно загрузить его в память, что можно сделать, перезагрузив модуль res_calendar.so:

*CLI> modulereload res_calendar.so

Убедитесь, что календарь был успешно загружен в память командой calendar show:

*CLI> calendar show calendars

Calendar Type Status

——– —- ——

phone_call_calendar caldav free

С помощью нашего календаря, успешно загруженного в память, мы можем написать некоторый диалплан для команды Dial(), чтобы сохранить информацию о вызове в календарь с помощью функции CALENDAR_WRITE():

[LocalSets]

exten => _NXXNXXXXXX,1,Verbose(2,Outbound calls)

same => n,Set(CalendarStart=${EPOCH}) ; Используется CALENDAR_WRITE()

same => n,Set(X=${EXTEN}) ; Используется CALENDAR_WRITE()

same => n,Dial(SIP/ITSP/${EXTEN},30)

same => n,NoOp(Handle standard voicemail stuff here)

same => n,Hangup()

exten => h,1,Verbose(2,Call cleanup)

; Всё, что следует далее должно быть в одной строке

same => n,Set(CALENDAR_WRITE(phone_call_calendar,summary,description,

start,end)=

OUTBOUND: ${X},Phone call to ${X} lasted for ${CDR(billsec)} seconds.,

${CalendarStart},${EPOCH})

В нашем диалплане мы создали простой сценарий, в котором осуществляем исходящий вызов через нашего провайдера интернет-телефонии (ITSP), но перед выполнением вызова сохраняем epoch3 в переменной канала (поэтому мы можем использовать ее позже, когда сделаем нашу запись в календаре в конце вызова). После вызова мы делаем запись в наш календарь phone_call_calendar с помощью функции CALENDAR_WRITE() во встроенном расширении h. Есть несколько параметров, которые мы можем передать в календарь, такие как сводка, описание, время начала и окончания. Вся эта информация затем сохраняется в календаре.

Мы также использовали функцию CDR() в нашем описании, чтобы показать количество секунд, в течение которых длился разговор, чтобы получить более точную оценку того, был ли дан ответ на вызов, и, если да, то как долго длился разговор. Мы также могли бы быть умнее и писать в календарь только в том случае, если ${CDR(billsec)} был больше 0, обрабатывая приложение Set() в приложении ExecIf(); например, same => n,ExecIf($[${CDR(billsec)} > 0]?Set(CALENDAR_WRITE …)).

Существует много возможностей для функции CALENDAR_WRITE(), но это только то, что мы реализовали и наслаждаемся.

Дополнительные функции

Доступны другие функции календаря, такие как CALENDAR_QUERY(), которая позволяет получить список событий за определенный период времени для определенного календаря, и CALENDAR_QUERY_RESULT(), которая позволяет получить доступ к особенностям событий этого календаря. Кроме того, вы можете создать функцию, которая записывает события в ваш календарь с помощью CALENDAR_WRITE(): например, вы можете разработать некоторый диалплан, который позволит вам выделять блоки времени в вашем календаре с телефона, когда вы находитесь в дороге без доступа к ноутбуку. Существует много возможностей, и все, что нужно, это немного творчества.

Интеграция голосовой почты с IMAP

“Единая система обмена сообщениями” была модным словом в телекоммуникационной отрасли на протяжении веков. Все дело в интеграции служб, чтобы пользователи могли получать доступ к одним и тем же типам данных в нескольких местах, используя разные методы. Одним из самых рекламируемых приложений является интеграция электронной и голосовой почты. Asterisk делал это в течение многих лет, но многие крупные компании все еще пытаются научиться этому. Asterisk имеет возможность отправлять пользователям голосовые сообщения по электронной почте, используя почтовый транспортный агент (Mail Transport Agent – MTA) в вашем дистрибутиве Linux (это всегда был sendmail, но и Postfix становится все более популярным как MTA). Голосовая почта на электронную является одной из старейших функций Asterisk, и обычно она работает без какой-либо конфигурации вообще.4

Интеграция Internet Message Access Protocol (IMAP) существует в Asterisk (и постоянно развивается) с версии 1.4. Интеграция голосовой почты IMAP означает, что пользователи могут получать доступ к голосовой почте через папку в своих учетных записях электронной почты, что дает им возможность прослушивать, пересылать и отмечать сообщения голосовой почты с той же гибкостью, что и приложение диалплана VoiceMail(). Asterisk будет знать о состоянии этих сообщений при следующем входе пользователей через телефонную систему.

По мере увеличения числа администраторов, интегрирующих Asterisk со своими IMAP-серверами, количество зарегистрированных и исправленных ошибок сначала увеличилось, а затем уменьшилось до такой степени, что интеграцию IMAP можно считать достаточно стабильной для использования в рабочей среде. В этом разделе мы обсудим, как скомпилировать поддержку голосовой почты IMAP и подключить систему голосовой почты к серверу IMAP.

Компиляция поддержки голосовой почты IMAP в Asterisk

Чтобы получить поддержку голосовой почты через IMAP в Asterisk, нам нужно скомпилировать библиотеку IMAP Университета Вашингтон. Набор инструментов UW IMAP даст нам функциональность для подключения к нашему серверу IMAP. Однако перед компиляцией программного обеспечения нам необходимо установить некоторые зависимости.

Зависимости для создания библиотеки IMAP включают инструменты, необходимые для сборки Asterisk, но способ, которым мы ее создаем, также требует библиотек разработки для OpenSSL и подключаемых модулей аутентификации (Pluggable Authentication Modules – PAM). Мы включили инструкции для RHEL и Ubuntu.

Зависимости RHEL

Установка библиотек разработки OpenSSL и PAM на RHEL может быть выполнена следующей командой:

$ sudo yum install openssl-devel pam-devel

Зависимости Ubuntu

Установка библиотек разработки OpenSSL и PAM на Ubuntu может быть выполнена следующей командой:

$ sudo apt-get install libssl-dev libpam0g-dev

Если вы попытаетесь установить libpam-dev на Ubuntu, он предупредит вас, что libpam-dev является виртуальным пакетом и вы должны явно установить один из пакетов в списке, который он представляет вам (который в нашем случае содержал только один пакет). Если libpam0g-dev не подходит для вашей версии Ubuntu, попробуйте установить виртуальный пакет. Это должно дать вам список допустимых пакетов для библиотеки разработки PAM.

Компиляция библиотеки IMAP

Теперь, когда наши зависимости удовлетворены, мы можем скомпилировать библиотеку IMAP, которую Asterisk будет использовать для подключения к серверу IMAP.

Первое, что нужно сделать, это перейти в каталог thirdparty, расположенный в каталоге asterisk-complete. Если вы еще не создали этот каталог, сделайте это сейчас:

$ cd ~/src/asterisk-complete

$ mkdir thirdparty

$ cd thirdparty

Далее идет загрузка набора инструментов IMAP и его компиляция. В следующих шагах будет получена последняя версия инструментария IMAP с сервера Университета Вашингтона (более подробная информация о наборе инструментов доступна по адресу http://www.washington.edu/imap/):

$ wget ftp://ftp.cac.washington.edu/mail/imap.tar.Z

$ tar zxvf imap.tar.Z

$ cd imap-2007e

Имя каталога imap-2007e может изменяться по мере появления новых версий набора инструментов.

Есть несколько опций, которые мы должны передать команде make при создании библиотеки IMAP, и значений, которые вы должны передать, зависящие от того, на какой платформе вы собираете (32- или 64-разрядная), если вам нужна поддержка OpenSSL, и нужна ли вам поддержка IPv6 или просто IPv4. Таблица 18-1 показывает некоторые из различных вариантов, которые вы могли бы выбрать на разных платформах.

Таблица 18-1. Опции времени компиляции библиотеки IMAP

Опция Описание
EXTRACFLAGS=”-fPIC” Требуется при сборке на 64-разрядных платформах.
EXTRACFLAGS=”-I/usr/include/openssl” Используется для сборки с поддержкой OpenSSL.
IP6=4 Многие платформы, поддерживающие IPv6, предпочитают такой способ подключения, который может быть нежелателен для всех серверов. Если вы хотите принудительно использовать IPv4 в качестве предпочтительного способа подключения установите этот параметр.

Если вы посмотрите в Makefile, поставляемом с библиотекой IMAP, то найдете список платформ, для которых библиотека может быть скомпилирована. В нашем случае мы будем компилировать для RHEL или Ubuntu с поддержкой PAM. Если вы компилируете на других системах, посмотрите в Makefile трехбуквенный код, который сообщает библиотеке как компилироваться для вашей платформы.

Компиляция для 64-разрядной платформы с поддержкой OpenSSL и предпочтением подключения через IPv4:

$ make lnp EXTRACFLAGS=”-fPIC -I/usr/include/openssl” IP6=4

Компиляция для 32-разрядной платформы с поддержкой OpenSSL и предпочтением подключения через IPv4:

$ make lnp EXTRACFLAGS=”-I/usr/include/openssl” IP6=4

Если вы не хотите компилироваться с поддержкой OpenSSL, просто удалите -I/usr/include/openssl из дополнительного параметра EXTRACFLAGS. Если вы предпочитаете подключение по IPv6 по умолчанию, просто не указывайте параметр IP6=4.

При установке поддержки IMAP мы всегда компилировали библиотеку c-client из исходного кода. Однако она может быть доступна в виде пакета для вашего дистрибутива. Например, Ubuntu имеет доступный пакет libc-client-dev. Это может сработать и избавить вас от некоторых неприятностей, но мы не тестировали его.

Компиляция Asterisk

После компиляции библиотеки IMAP нам нужно перекомпилировать модуль app_voicemail.so с поддержкой IMAP. Первый шаг должен выполнить скрипт configure и передать ему параметр –with-imap, чтобы сообщить где находится библиотека IMAP:

$ cd ~/src/asterisk-complete/asterisk/11

$ ./configure –with-imap=~/src/asterisk-complete/thirdparty/imap-2007e/

После завершения выполнения скрипта configure необходимо включить поддержку голосовой почты IMAP в menuselect:

$ make menuselect

Из интерфейса menuselect зайдите в Voicemail Build Options. В этом меню вы должны иметь возможность выбрать IMAP_STORAGE.

Если у вас нет возможности выбрать эту опцию – убедитесь, что ваша библиотека IMAP была успешно собрана (т.е. что у вас установлены все необходимые зависимости и при сборке не произошло ошибки) и что вы правильно указали путь к библиотеке IMAP при запуске скрипта configure. Можно также проверить что библиотека IMAP была найдена правильно, посмотрев файл config.log (находится в каталоге сборки Asterisk) для IMAP.

После выбора IMAP_STORAGE, сохраните и выйдите из menuselect и запустите make install, который будет перекомпилировать модуль app_voicemail.so и установит его в соответствующее место. Следующий шаг – настройка файла voicemail.conf находящегося в /etc/asterisk.

Настройка Asterisk

Теперь, когда мы скомпилировали поддержку IMAP в Asterisk, нам нужно включить ее, подключившись к серверу с поддержкой IMAP. Есть много IMAP-серверов, которые мы могли бы использовать, в том числе те, которые поставляются с серверами Microsoft, Dovecot и Cyrus на Unix, или веб-сервер IMAP такой, как тот, который поставляется Gmail от Google.5 Наши инструкции покажут, как подключить Asterisk к учетной записи Gmail с включенным IMAP так как это требует наименьшего количества усилий чтобы поднять и запустить голосовую почту с IMAP, но эти инструкции могут быть легко адаптированы для использования с любым существующим сервером IMAP.

Включение IMAP в Gmail. Включение поддержки IMAP в вашей учетной записи Gmail является простым (см. Рисунок 18-1). После входа в учетную запись выберите Settings в правом верхнем углу. Затем выберите Forwardingand POP/IMAP в строке меню под заголовком Settings. В разделе IMAP Access выберите Enable IMAP. После включения IMAP нажмите кнопку Save Changes в нижней части экрана.

Рисунок 18-1. Включение IMAP в Gmail.

Настройка voicemail.conf для IMAP. Чтобы наша система голосовой почты могла подключаться к системе IMAP – нам необходимо убедиться, что поддержка IMAP встроена в модуль app_voicemail.so в соответствии с инструкцией в “Компиляция Asterisk”. С поддержкой IMAP, скомпилированной в Asterisk, нам просто нужно указать модулю голосовой почты, как подключаться к нашему серверу IMAP.

Мы продемонстрируем как подключиться к учетной записи Gmail с поддержкой IMAP и использовать ее для хранения и получения сообщений голосовой почты. Если вы еще этого не сделали, прочитайте раздел “Включение IMAP в Gmail”, прежде чем продолжить. Последний шаг – настройка voicemail.conf для подключения к серверу.

В voicemail.conf добавьте следующие строки в раздел [general]. Убедитесь, что вы указываете только один формат (мы рекомендуем wav49) для записей голосовой почты и удалите все ссылки на хранилище голосовой почты ODBC, если вы включали их ранее:

[general]

format=wav49 ; формат хранения файлов

imapserver=imap.gmail.com ; расположение IMAP-сервера

imapport=993 ; порт IMAP-сервера

imapflags=ssl ; флаги, необходимые для подключения

expungeonhangup=yes ; удалять сообщения когда кладут трубку

pollmailboxes=yes ; используется для индикации ожидающего сообщения

pollfreq=30 ; как часто проверять изменения сообщений

Прежде чем настроить нашего пользователя для подключения к серверу IMAP Gmail, давайте обсудим параметры, которые мы только что установили в разделе [general]. Это основные параметры, которые помогут нам начать; мы сделаем еще несколько настроек в ближайшее время, но давайте посмотрим, что мы сделали уже.

Во-первых, опция format=wav49 объявила, что мы собираемся сохранить наши файлы как GSM с заголовком WAV, который можно воспроизводить на большинстве настольных компьютеров (включая Microsoft Windows), сохраняя при этом небольшой размер файла.

Затем мы настроили Asterisk для подключения к imapserver, расположенному в imap.gmail.com на imapport 993. Мы также установили imapflags на ssl, так как Gmail требует безопасного соединения. Без флага ssl IMAP сервер отклонит наши попытки подключения (поэтому было важно, чтобы мы скомпилировали нашу библиотеку IMAP с поддержкой OpenSSL). Другой вариант, который может потребоваться на частных серверах IMAP, таких как Dovecot – указать novalidate-cert для imapflags, когда требуется SSL-соединение, но сертификат не создается Центром сертификации.

Далее, мы установили expungeonhangup=yes, в результате чего сообщения, помеченные на удаление, удаляются с сервера когда разрывают соединение с приложением VoiceMail(). Без этой опции сообщения просто помечаются как прочитанные и остаются на сервере, пока не будут удалены через почтовое приложение или веб-интерфейс.

Для корректного получения обновлений индикации ожидания сообщения (Message Waiting Indication – MWI) необходимо включить pollmailboxes=yes, в результате чего Asterisk будет проверять сервер на наличие изменений состояния сообщений. Например, когда кто-то оставляет нам голосовую почту, и мы слушаем ее, открывая сообщение через наше приложение электронной почты, сообщение будет помечено как прочитанное, но без опроса почтового ящика Asterisk не будет иметь возможности узнать об этом и включит индикатор MWI на связанном устройстве на неопределенный срок. Наконец, мы установили соответствующий параметр pollfreq равным 30 секундам. Этот параметр определяет как часто Asterisk будет запрашивать у сервера статус сообщений: установите его соответствующим образом, чтобы контролировать объем трафика, поступающего на сервер голосовой почты.

В Таблице 18-2 показаны некоторые другие доступные нам варианты.

Таблица 18-2. Дополнительные опции голосовой почты IMAP

Опция Описание
imapfolder Имя папки, в которой будут храниться сообщения голосовой почты IMAP-сервера. По умолчанию они хранятся в папке INBOX.a
imapgreetings Определяет, хранятся ли приветствия голосовой почты на сервере IMAP или на сервере локально. Допустимые значения: yes или no.
imapparentfolder Определяет родительскую папку на сервере IMAP. Обычно настроено как INBOX, но если она используется где-то еще, можно указать её здесь.
greetingfolder Указывает папку для сохранения приветствий голосовой почты, если параметр imapgreetings включен значением yes. По умолчанию приветствия сохраняются в папке INBOX.
authuser Задает главного пользователя для подключения к серверу IMAP если на сервере настроен один пользователь, имеющий доступ ко всем почтовым ящикам.
authpassword Дополнение к директиве authuser. Дополнительные сведения см. в разделе authuser.
opentimeout Указывает таймаут открытия TCP (в секундах).
closetimeout Указывает таймаут закрытия TCP (в секундах).
readtimeout Указывает таймаут чтения TCP (в секундах).
writetimeout Указывает таймаут записи TCP (в секундах).

a Важно хранить сообщения голосовой почты в папке, отличной от папки INBOX, если количество сообщений, содержащихся в папке INBOX может быть довольно большим. Asterisk попытается собрать информацию обо всех сообщениях электронной почты, содержащихся в папке INBOX, и может либо истечь время ожидания, прежде чем получить всю информацию, либо просто занять очень много времени для сохранения или извлечения сообщений голосовой почты, что нежелательно.

Настроив раздел [general], давайте определим почтовый ящик для подключения к серверу IMAP.

В Главе 8 мы определили некоторых пользователей в контексте голосовой почты [shifteight]. Вот исходная конфигурация, определенная в этой главе:

[shifteight]

100 => 0107,Leif Madsen,leif@shifteight.org

101 => 0523,Jim VanMeggelen,jim@shifteight.org,,attach=no|maxmsg=100

102 => 11042,Tilghman Lesher,,,attach=no|tz=central

Мы собираемся изменить почтовый ящик 100 таким образом, чтобы он подключался к серверу IMAP Gmail для хранения и извлечения сообщений голосовой почты:

[shifteight]

100 => 0107,Leif Madsen,,,|imapuser=leif@shifteight.org|imappassword=secret

Файл voicemail.conf использует как запятые, так и пайпы в качестве разделителей, в зависимости от используемого поля. Первые несколько полей имеют определенные настройки, а последнее поле может содержать дополнительную информацию о почтовом ящике, разделенную символом пайпа (|).

Мы удалили адрес электронной почты из третьего поля, потому что больше не будем использовать sendmail для отправки голосовых сообщений: теперь они будут храниться непосредственно на почтовом сервере. Мы настроили почтовый ящик для соединения с именем пользователя IMAP leif@shifteight.org (потому что мы включили Google Apps для домена, в котором размещается наша электронная почта) и подключаемся с помощью IMAP пароля secret.

После настройки Asterisk нам нужно перезагрузить модуль app_voicemail.so. Если вы включаете отладку консоли, то при подключении к серверу голосовой почты должны отображаться следующие выходные данные:

*CLI> core set debug 10

*CLI> module reload app_voicemail.so

DEBUG[3293]: app_voicemail.c:2734 mm_log: IMAP Info:

Trying IP address [74.125.53.109]

DEBUG[3293]: app_voicemail.c:2734 mm_log: IMAP Info: Gimap ready for requests

from 99.228.XXX.XXX 13if2973206wfc.0

DEBUG[3293]: app_voicemail.c:2757 mm_login: Entering callback mm_login

DEBUG[3293]: app_voicemail.c:2650 mm_exists:

Entering EXISTS callback for message 7

DEBUG[3293]: app_voicemail.c:3074 set_update:

User leif@shifteight.org mailbox set for update.

DEBUG[3293]: app_voicemail.c:2510 init_mailstream: Before mail_open, server:

{imap.gmail.com:993/imap/ssl/user=leif@shifteight.org}INBOX, box:0

DEBUG[3293]: app_voicemail.c:2734 mm_log: IMAP Info: Reusing connection to

gmail-imap.l.google.com/user=”leif@shifteight.org”

При появлении ERROR ошибок проверьте конфигурацию и убедитесь, что библиотека IMAP скомпилирована с поддержкой SSL. Когда app_voicemail.so подключен, попробуйте оставить себе голосовую почту; затем проверить её через веб-интерфейс Gmail и убедитесь, что ваше сообщение хранится правильно. У вас также должен быть индикатор MWI на вашем устройстве, если оно поддерживает его, и если вы настроили mailbox=100@shifteight для устройства в sip.conf. Если вы загружаете сообщение голосовой почты и отмечаете его как прочитанное, индикатор MWI должен выключиться в течение 30 секунд (или другого значения, которое вы устанавливаете для pollfreq в voicemail.conf).

Использование XMPP (Jabber) с Asterisk

Расширяемый протокол обмена сообщениями о присутствия (XMPP, ранее называемый Jabber) используется для обмена мгновенными сообщениями и передачи информации о присутствии по сетям в режиме реального времени. В Asterisk он также используется для настройки вызова (сигнализации). Мы можем делать различные интересные вещи при интеграции с XMPP, например получать сообщение, когда кто-то звонит нам. Мы даже можем отправлять сообщения обратно на Asterisk, перенаправляя наши звонки на голосовую почту или в другое место. Кроме того, с chan_motif мы можем принимать и совершать звонки через сеть Google Voice или принимать звонки от пользователей Google Talk через веб-клиент.

Компиляция поддержки XMPP в Asterisk

Модуль res_xmpp содержит различные приложения и функции диалплана, которые полезны из диалплана Asterisk. Он также является зависимостью модуля канала chan_motif. Начать с интеграции XMPP в Asterisk нужно скомпилировав res_xmpp.

Зависимости RHEL

Для установки res_xmpp нам нужна библиотека разработки iksemel. Если установлена библиотека разработки OpenSSL, res_xmpp также будет использовать ее для безопасных соединений (рекомендуется). Мы можем установить их обе на RHEL с помощью следующей команды:

$ sudo yum install iksemel-devel openssl-devel

Библиотека iksemel будет установлена через EPEL.

Зависимости Ubuntu

Для установки res_xmpp нам нужна библиотека разработки iksemel. Если установлена библиотека разработки OpenSSL, res_xmpp также будет использовать ее для безопасных соединений (рекомендуется). Мы можем установить их обе в Ubuntu с помощью следующей команды:

$ sudo apt-get install libiksemel-dev libssl-dev

Установка res_xmpp

После установки зависимостей необходимо выполнить ./configure в исходниках Asterisk и make menuselect. Затем перейдите в меню Resource Modules и убедитесь, что res_xmpp включен. После этого запустите make install, чтобы получить новые модули.

Команды диалплана Jabber

Для связи по XMPP через Asterisk можно использовать несколько приложений и функций диалплана. Мы рассмотрим, как подключить Asterisk к серверу XMPP, как отправлять сообщения клиенту из диалплана и как маршрутизировать вызовы на основе ответов на первоначально отправленные сообщения. Отправляя сообщение через XMPP мы, по сути, создаем простое приложение для всплывающих окон, чтобы пользователи знали, когда вызовы поступают в систему.

Подключение к XMPP серверу

Прежде чем мы сможем начать отправлять сообщения нашим участникам XMPP, нам нужно подключиться к серверу с поддержкой XMPP. Мы собираемся использовать сервер XMPP в Google, так как он открыт и доступен для всех. Для этого необходимо настроить xmpp.conf в каталоге конфигурации /etc/asterisk. Следующий пример подключит нас к серверу XMPP в Google.

У вас уже должна быть учетная запись Gmail, которую вы можете получить на http://www.gmail.com.

Наш xmpp.conf должен выглядеть так:

[general]

[asterisk]

type=client

serverhost=talk.google.com

username=asterisk@shifteight.org

secret=<super_secret_password>

priority=1

port=5222

usetls=yes

usesasl=yes

status=available

statusmessage=”Ohai from Asterisk”

timeout=5

Давайте взглянем на некоторые параметры, которые мы только что установили, для понимания что происходит. Параметры описаны в Таблице 18-3. Мы описали все доступные параметры в xmpp.conf, несмотря на то, что не установили все параметры в нашем примере файла.

Tаблица 18-3. Опции xmpp.conf

Опция Описание
debug Включает/отключает отладку сообщений XMPP (которая может быть довольно подробной). Доступные варианты yes или no.
autoprune Включает/отключает автоматическое удаление пользователей из списка участников каждый раз, когда res_xmpp.so подключается к вашему аккаунту. Не используйте это для учетных записей, которые вы можете использовать за пределами Asterisk (например, ваш персональный аккаунт). Доступные параметры: yes или no.
autoregister Указывает, следует ли автоматически регистрировать пользователей из списка ваших друзей в памяти. Доступные параметры: yes или no.
collection_nodes Включает поддержку расширения XEP-0248 XMPP. Оно может быть включено для использования с распределенными состояниями устройств. Доступные параметры: yes или no. По умолчанию no.
pubsub_autocreate Если сервер PubSub автоматически создает узлы, то Asterisk должен явно предварительно создать узел перед публикацией. Доступные параметры: yes или no. По умолчанию no.
auth_policy Определяет, следует ли автоматически принимать запросы на подписку. Доступные параметры: accept или deny.
type Устанавливает тип клиента, с которым мы будем соединяться. Доступные параметры – client или component. (Вы почти всегда будете выбирать client.)
serverhost Указывает к какому хосту должно подключаться это соединение (например, talk.google.com).
pubsub_node Имя узла, используемого для публикации событий через PubSub. Значение является строкой.
username Предоставляет имя пользователя, которое будет использоваться для подключения к serverhost (например asterisk@gmail.com).
secret Задает пароль, который будет использоваться для подключения к serverhost.
port Указывает на какой порт мы попытаемся установить соединение с serverhost (например 5222).
usetls Указывает, следует ли использовать TLS при подключении к serverhost. Доступные параметры: yes или no.
usesasl Указывает, следует ли использовать SASL при подключении к serverhost. Доступные параметры: yes или no.
status Определяет состояние соединения по умолчанию при входе в учетную запись. Доступные варианты: chat, available, away, xaway, и dnd.
statusmessage Задает пользовательское сообщение о состоянии, используемое при подключении к Asterisk, например “Connected Via Asterisk”; используйте двойные кавычки вокруг сообщения.
buddy Вручную добавляет приятелей в список при подключении к серверу. Вы можете указать несколько друзей на нескольких линиях buddy (например, buddy=jim@shifteight.org).
timeout Указывает время ожидания (в секундах), в течение которого сообщения хранятся в стеке сообщений. По умолчанию 5 секунд. Эта опция применяется только ко входящим сообщениям, которые предназначены для обработки функцией диалплана JABBER_RECEIVE().
priority Определяет приоритет этого ресурса по отношению к другим ресурсам. Чем меньше число, тем выше приоритет.
sendtodialplan Если эта опция включена, входящие сообщения будут отправляться в диалплан. Доступные параметры: yes или no. По умолчанию no. (См. раздел “Внешние сообщения (инфраструктура обмена сообщениями)
context Если параметр sendtodialplan включен, то указывает контекст для отправки сообщений. Контекст по умолчанию – default.

После конфигурирования файла xmpp.conf мы можем загрузить (или перезагрузить) модуль res_xmpp.so.

Сделать это можно из консоли с помощью module reload res_xmpp.so:

*CLI> module reload res_xmpp.so

Reloaded res_xmpp.so

и проверим подключение с помощью команды xmpp show connections:

*CLI> xmpp show connections

Jabber Users and their status:

User: asterisk@shifteight.org – Connected

—-

Number of users: 1

Если у вас возникли проблемы с подключением вы можете попробовать выгрузить модуль, а затем загрузить его обратно в память. Если проблемы не устранены, то можно выполнить команду xmpp purge nodes чтобы удалить все существующие или поврежденные соединения из памяти. Кроме того, проверьте конфигурацию и убедитесь что у вас нет проблем с конфигурацией или опечаток. После того, как вы подключились, можете перейти к следующим разделам, где начинается самое интересное.

Отправка сообщений через JabberSend()

Приложение диалплана JabberSend() используется для отправки сообщений приятелям из диалплана Asterisk. Вы можете использовать это приложение в любом месте, где обычно используете диалплан, что делает его довольно гибким. Мы собираемся использовать его в качестве экранного приложения для отправки сообщения клиенту перед тем, как позвонить на телефон пользователя. В зависимости от используемого клиента сообщение может появиться на экране пользователя на панели задач.

Вот простой пример для начала:

[LocalSets]

exten => 104,1,Answer()

; *** Эта строка не должна содержать разрывов

same => n,JabberSend(asterisk,jim@shifteight.org,Incoming call from

${CALLERID(all)})

same => n,Dial(SIP/0000FFFF0002,30)

same => n,Hangup()

Этот пример демонстрирует как использовать приложение JabberSend() для отправки сообщения кому-то до набора его номера. Давайте разберем значения, которые мы использовали. Первый аргумент – asterisk – это заголовок раздела, который мы определили в файле jabber.conf как [asterisk]. В нашем примере xmpp.conf мы задали пользователю с именем asterisk@shifteight.org отправлять сообщения через сервер Google XMPP, а asterisk – это название раздела, которое мы определили. Второй аргумент jim@shifteight.org – это приятель, кому мы посылаем сообщение. Мы можем определить любого приятеля здесь, либо как голый JID (как мы делали выше), либо как полный JID с ресурсом (например, jim@shifteight.org/laptop). Третий аргумент JabberSend() – это сообщение, которое мы хотим отправить приятелю. В этом случае мы отправляем Incoming call from ${CALLERID(all)}, а для ввода информации об CallerID абонента в сообщении используется функция диалплана CALLERID().

Очевидно, что нам придется дополнительно построить наш диалплан, чтобы сделать это полезным: в частности, нам нужно будет связать имя приятеля (например, jim@shifteight.org) с устройством, которое мы вызываем (SIP/0000FFFF0002) для отправки сообщений правильному приятелю. Вы можете сохранить эти ассоциации в любых местах, например, в AstDB, в реляционной базе данных, извлекая с помощью func_odbc или даже в глобальной переменной.

Получение сообщений через JABBER_RECEIVE()

Функция диалплана JABBER_RECEIVE() позволяет нам получать ответы через сообщения XMPP, захватывать эти ответы и, предположительно, реагировать на них. Обычно мы используем функцию JABBER_RECEIVE() в сочетании с приложением JabberSend(), так как нам, скорее всего, потребуется отправить кому-то сообщение и предложить ему приемлемые значения, которые он может вернуть. Мы могли бы использовать функцию JABBER_RECEIVE(), либо для прямых вызовов на определенное устройство, такое как сотовый или стационарный телефон, или как текстовую версию автосекретаря, используемую для людей, которые плохо слышат подсказки (Например, для глухих пользователей или работающих в шумной рабочей среде). В последнем случае система должна быть предварительно настроена, чтобы знать, куда отправлять сообщения, возможно, на основе CallerID.

Вот простой пример, который отправляет сообщение кому-то, ждет ответа, а затем направляет вызов на основе ответа:

exten => 106,1,Answer()

; Весь текст должен размещаться в одну строку.

same => n,JabberSend(asterisk,leif.madsen@gmail.com,Incoming call from

${CALLERID(all)}. Press 1 to route to desk. Press 2 to send to voicemail.)6

same => n,Set(JabberResponse=${JABBER_RECEIVE(asterisk,leif@shifteight.org)})

same => n,GotoIf($[“${JabberResponse}” = “1”]?dial,1)

same => n,GotoIf($[“${JabberResponse}” = “2”]?voicemail,1)

same => n,Goto(dial,1)

exten => dial,1,Verbose(2,Calling our desk)

same => n,Dial(SIP/0000FFFF0002,6)

same => n,Goto(voicemail,1)

exten => voicemail,1,Verbose(2,VoiceMail)

; *** Эта строка не должна содержать разрывов

same => n,Set(VoiceMailStatus=${IF($[${ISNULL(${DIALSTATUS})}

| “${DIALSTATUS}” = “BUSY”]?b:u)})

same => n,Playback(silence/1)

same => n,VoiceMail(100@lmentinc,${VoiceMailStatus})

same => n,Hangup()

К сожалению, приложение JabberSend() требует чтобы весь текст сообщения был в одной строке. Если вы хотите разбить текст на несколько строк, вам нужно будет отправить его как несколько сообщений на отдельных строках с помощью JabberSend().

Наш простой диалплан сначала отправляет сообщение учетной записи Jabber (leif@shifteight.org) через учетную запись Jabber нашей системы (asterisk), настроенную в xmpp.conf. Затем мы используем функцию JABBER_RECEIVE() для ожидания ответа от leif@shifteight.org. Время ожидания по умолчанию составляет 5 секунд (как определено в xmpp.conf), но вы можете указать другой таймаут в третьем аргументе JABBER_RECEIVE(). Например, чтобы подождать ответа 10 секунд, мы должны были использовать такую строку:

Set(JabberResponse=${JABBER_RECEIVE(asterisk,leif@shifteight.org,10)})

Как только мы или получили ответ или таймаут истек, то переходим к следующей строке абонентской группы, которая начинает проверять ответ, сохраненный к переменной канала ${JabberResponse}. Если значение равно 1, мы продолжим наш диалплан на dial,1 текущего контекста. Если ответ 2, мы продолжаем наш диалплан в voicemail,1. Если ответ не получен (или неизвестен), то продолжаем в dial,1.

В диалплане dial,1 и voicemail,1 должны быть довольно очевидными. Это – не производственный пример; должна быть реализована некоторая дополнительная абонентская группа, чтобы сделать значения динамическими.

Однако, есть недостаток в том, как мы реализовали функцию JABBER_RECEIVE(). Наша функция блокирует или ожидает ответа от конечной точки. Если мы установим значение ответа низким, чтобы минимизировать задержку, мы не дадим получателю достаточно времени для ответа. Однако, если мы устанавливаем время для ответа достаточно большим, чтобы получатель мог комфортно ответить, мы указываем ненужную задержку в вызове устройства или отправке на голосовую почту.

Мы можем обойти эту проблему, используя локальный канал. Это позволяет нам выполнять два раздела диалплана одновременно, посылая вызов устройству и, в то же время, ожидая ответа от JABBER_RECEIVE(). Если мы получаем ответ от JABBER_RECEIVE() и нам нужно что-то сделать, мы можем выполнить Answer() на линию и заставить этот раздел диалплана продолжиться. Если устройство ответит на звонок, наш диалплан с JABBER_RECEIVE() будет просто отключен. Рассмотрим модифицированную абонентскую группу, реализующую локальный канал:

exten => 106,1,Verbose(2,Example using the Local channel)

same => n,Dial(Local/xmpp@${CONTEXT}/n&Local/dial@${CONTEXT}/n)

exten => xmpp,1,Verbose(2,Send an XMPP message and expect a response)

; *** Эта строка не должна содержать разрывов

same => n,JabberSend(asterisk,leif.madsen@gmail.com,Incoming call from

${CALLERID(all)}. Press 2 to send to voicemail.)

same => n,Set(JabberResponse=${

JABBER_RECEIVE(asterisk,leif@shifteight.org,6)})

same => n,GotoIf($[“${JabberResponse}” = “2”]?voicemail,1)

same => n,Hangup()

exten => dial,1,Verbose(2,Calling our desk)

same => n,Dial(SIP/0000FFFF0002,15)

same => n,Goto(voicemail,1)

exten => voicemail,1,Verbose(2,VoiceMail)

same => n,Answer()

; *** Эта строка не должна содержать разрывов

same => n,Set(VoiceMailStatus=${IF($[${ISNULL(${DIALSTATUS})}

| “${DIALSTATUS}” = “BUSY”]?b:u)})

same => n,Playback(silence/1)

same => n,VoiceMail(100@shifteight,${VoiceMailStatus})

same => n,Hangup()

Добавляя оператор Dial() в начало и перемещая нашу функцию отправки и получения Jabber в новое расширение под названием xmpp мы гарантируем, что можем одновременно вызвать расширение dial и расширение xmpp.

Обратите внимание, что мы удалили приложение Answer() из первой строки примера. Причина этого в том, что мы хотим выполнять Answer() на строку только после ответа устройства (что приводит к завершению расширения xmpp); в противном случае мы хотим, чтобы расширение voicemail выполнило Answer() на линию. Если voicemail ответило на линию это означает, что либо расширение xmpp получит ответ и укажет сделать Goto() к расширению voicemail, либо Dial() для нашего телефона истекло, вызывающее расширение голосовой почты должно быть выполнено, сделав тем самым линию Answer().

Приведенные здесь примеры служат трамплином для разработки многофункциональных приложений, которые отправляют и получают сообщения через серверы XMPP. Некоторые другие приложения и функции дилплана могут помочь в разработке приложений, такие как JABBER_STATUS() (или приложение диалплана JabberStatus()), которые используются для проверки статуса приятеля; применяя JabberJoin() и JabberLeave(), которые используются для присоединения и отключения XMPP конференц-залов; и приложение JabberSendGroup(), которое позволяет отправлять сообщения по протоколу XMPP комнатам чата.

chan_motif

Модуль chan_motif можно использовать для подключения к сетям с поддержкой Jingle. Он поддерживает три различных транспортных и производных протокола (в порядке предпочтения):

  • Jingle как определено в спецификации XEP-0166
  • Google Jingle, который следует спецификации Jingle для сигнализации, но использует пользовательский транспорт Google для медиапотока
  • Google-V1, оригинальная реализация Google предварительной спецификации Jingle

Модуль канала может автоматически определить какой транспорт использовать для входящих сессий. Для исходящих сеансов он может определить транспорт автоматически, если вызываемая конечная точка находится в списке. Если оконечная точка не находится в списке, то chan_motif попытается соединиться в предпочтительном порядке, как перечислено в пунктах маркированного списка выше, пока все возможности или не будут успешны или не потерпят неудачу.

В наших примерах мы будем использовать Google Talk (GTalk) для совершения и приема вызовов, так как он позволяет людям, использующим веб-приложения и другие инструменты Google, легко совершать звонки. GTalk – это веб-голосовая система, обычно используемая в веб-интерфейсе Gmail. Существуют разные клиенты и дополнения для внешних приложений, таких как Pidgin, но мы будем тестировать с веб-клиентом от Google.

Амортизация chan_gtalk и chan_jingle

При создании chan_motif использование chan_gtalk и chan_jingle следует считать устаревшим. В версиях, предшествующих Asterisk 11, для подключения к службам Gtalk и Jingle использовались драйверы res_jabber и gtalk и канал jingle. Однако эти драйверы каналов имеют довольно старые реализации и обслуживание этих модулей стало затруднительным. При этом chan_motif был создан для поддержки подключения к сервисам Jingle и Google Talk. Более подробная информация о причинах создания chan_motif доступна в блоге Digium.

Прежде чем мы сможем подключиться к chan_motif мы должны убедиться, что мы связаны через res_xmpp, так что если вы ещё так не сделали, пересмотрите “Подключение к XMPP-серверу” для получения информации о том, как подключиться к XMPP-серверу Google.

motif.conf

После того, как мы подключились через res_xmpp, теперь можем настроить файл motif.conf, который определяет наше соединение для приема и совершения вызовов. Простой файл конфигурации для разрешения подключений по сети Google (например, вызовы через веб-интерфейс, встроенный в Gmail) выглядит следующим образом:

[google]

context=google_incoming

disallow=all

allow=ulaw

connection=asterisk

Кажется довольно простым, но давайте рассмотрим нашу конфигурацию более подробно.

Во-первых, мы определяем имя нашего соединения, которое мы назвали google (имя между квадратными скобками). Вы можете назвать его как угодно, но это имя мы будем использовать для ссылки на эту учетную запись в нашем диалплане при совершении исходящего вызова. Следующая строка – имя контекста в нашем диалплане, на который будут направляться входящие вызовы. Затем мы отключаем все ранее включенные кодеки, а после включаем ulaw для этого соединения. В последней строке мы ссылаемся на наш xmpp.conf с помощью XMPP-соединения, настроенного в предыдущем разделе.

После того, как мы определили наш раздел, нам нужно загрузить chan_motif.so (если он ранее не был загружен) или перезагрузить его, чтобы драйвер канала мог прочитать новую конфигурацию:

*CLI> module reload chan_motif.so

*CLI> — Reloading module ‘chan_motif.so’ (Motif Jingle Channel Driver)

На данный момент наш модуль имеет свою конфигурацию и мы можем перейти к настройке диалплана, чтобы разрешить входящие и исходящие вызовы.

Прием звонков из Google Talk

Чтобы принимать звонки из Google Talk нам нужно добавить некоторые функции в наш диалплан. Сначала определим имя контекста в extensions.conf, который мы настроили в motif.conf:

[google_incoming]

После определения нашего контекста мы можем добавить внутренний номер для маршрутизации вызовов. Входящие звонки из сети Google будут попадать на расширение s7 так же, как аналоговый канал, поступающий через интерфейс DAHDI. Как только входящий вызов совпадает с внутр.номером, мы можем выполнить любую маршрутизацию, которую захотим, так же как с любым другим входящим вызовом. Чтобы сделать проще, мы направим вызов на одну из конечных точек SIP, которые мы настроили ранее:

[google_incoming]

same => n,Dial(SIP/0000FFFF0001,24)

same => n,Voicemail(100@default,u)

same => n,Hangup()

Конечно, мы можем проявить здесь немного больше фантазии и могли бы выполнить проверку вызовов, перенаправление на автосекретаря, переадресацию на мобильный телефон, или любые другие методы, которые захотели бы использовать.

После настройки нашего диалплана необходимо запустить dialplanreload, чтобы сделать его активным. После этого попробуйте позвонить из другого веб-интерфейса Gmail (не из той учетной записи, которую вы настроили для системы Asterisk), и ваш звонок должен быть перенаправлен на конечную точку SIP. Вы даже можете увидеть, что входящий абонент добавлен в список друзей вашей системы Asterisk:

*CLI> xmpp show buddies

XMPP buddy lists

Client: asterisk

Buddy: shifteight@gmail.com

Resource: gmail.64F29731

node: http://mail.google.com/xmpp/client/caps

version: 1.1

Google Talk capable: yes

Jingle capable: no

Прием звонков из Google Voice

Конфигурация для приема звонков из Google Voice аналогична (если не идентична) конфигурации для Google Talk, которую мы создали в предыдущем разделе. Небольшой совет, однако, заключается в том, что иногда вы не сможете отключить функцию скрининга вызовов (по какой-то причине мы все еще получаем ее, даже когда мы отключили в панели управления Google Voice). Если вы столкнулись с этой проблемой, но не хотите, чтобы скрининг ваших вызовов был включен, вы можете автоматически отправить DTMF перед вызовом устройства, добавив три выделенные линии, показанные здесь перед выполнением Dial():

[google_incoming]

exten => s,1,Verbose(2,Incoming call via Google from ${CALLERID(all)})

same => n,Answer()

same => n,Wait(2)

same => n,SendDTMF(1)

same => n,Dial(SIP/0000FFFF0001,24)

same => n,Voicemail(100@default,u)

same => n,Hangup()

Здесь мы используем приложения Wait() и SendDTMF(), чтобы сначала подождать 2 секунды после ответа на вызов (то есть, когда начнется скрининг вызова), а затем принять вызов автоматически (отправив DTMF-сигнал цифру 1). После этого мы отправляем вызов на наше устройство.

Исходящие вызовы через Google Talk

Чтобы позвонить пользователю Google Talk, настройте свой диалплан следующим образом:

[LocalSets]

exten => 123,1,Verbose(2,Extension 123 calling shifteight@gmail.com)

same => n,Dial(Motif/google/shifteight@gmail.com,30)

same => n,Hangup()

В Motif/google/shifteight@gmail.com часть строки Dial() может быть разбита на три части. Первая часть, Motif – это протокол, который мы используем для исходящего вызова. Вторая часть, google является именем учетной записи, как определено в motif.conf. Последняя часть, shifteight@gmail.com – это место, куда мы пытаемся звонить.

Человек, которому вы звоните через Google Talk, должен уже существовать в вашем списке приятелей. Если вы используете существующее соединение (например, соединение с клиентами мгновенного обена сообщениями), возможно, у вас уже есть приятели в списке. Если нет, то вам нужно попросить своих приятелей сперва позвонить вам, чтобы Asterisk мог автоматически принять и добавить их в список друзей. Это требование сети Google, а не Asterisk. Контроль авторегистрации приятелей осуществляется через autoregister для вашего подключения в файле xmpp.conf.

Исходящие вызовы через Google Voice

Чтобы совершать звонки с помощью Google Voice на номера ТфОП, создайте следующий диалплан:

[LocalSets]

exten => _1NXXNXXXXXX,1,Verbose(2,Placing call to ${EXTEN} via Google Voice)

same => n,Dial(Motif/google/${EXTEN}@voice.google.com)

same => n,Hangup()

Давайте кратко обсудим строку Dial(), чтобы вы поняли что происходит. Начнем с Motif – технологии, с которой мы будем звонить. После этого мы определили пользователя google как соединение, которое мы будем использовать при совершении нашего исходящего вызова (это настроено в motif.conf). Далее идет номер, на который мы пытаемся позвонить, как определено переменной канала ${EXTEN}. Мы добавили @voice.google.com чтобы серверы Google знали, что это вызов, который должен быть совершен через Google Voice8 в отличие от другого пользователя Google Talk.

Внешние сообщения (инфраструктура обмена сообщениями)

Начиная с Asterisk 10 была добавлена возможность принимать сообщения вне диапазона (например, получать сообщение без существующего канала), чтобы разрешить запуск диалплана на основе полученного сообщения. Возможность принять сообщение означает что вы потенциально можете сделать вызов, просто отправив сообщение в диалплан с клиента XMPP. Как вы можете себе представить, существует множество возможностей для этого, в том числе возможность предоставлять опции меню до звонка, поиск людей в каталоге или получение информации о компании, никогда не делая звонок в систему. И как только кто-то будет готов принять звонок, он может попросить систему позвонить ему и соединить с агентом.

Инфраструктура обмена сообщениями позволяет как получать, так и отправлять сообщения через SIP или XMPP, используя комбинацию функции диалплана MESSAGE(), приложения MessageSend() и конфигурации любого (или обоих) sip.conf и xmpp.conf для направления входящих вызовов в соответствующее расположение в диалплане.

Конфигурация xmpp.conf

Предположим, что вы уже настроили xmpp.conf по разделу “Использование XMPP (Jabber) с Asterisk”, поэтому мы пропустим начальную конфигурацию. Единственное, что вам нужно сделать, чтобы принимать сообщения через XMPP, это добавить два параметра конфигурации, описанные в таблице 18-4, в созданную вами учетную запись [asterisk].

Table 18-4. Параметры, связанные с внешним обменом сообщениями с через XMPP

Опция Описание
sendtodialplan Отправлять ли входящие сообщения через XMPP в диалплан. Доступные параметры: yes или no. По умолчанию no.
context Контекст, в котором должны обрабатываться входящие сообщения. Если не задано, то будет использован контекст default.

Установка sendtodialplan в no (по умолчанию) или в yes будет контролировать, будут ли отправляться входящие сообщения этому пользователю XMPP в диалплан. Какой контекст диалплана будет анализировать сообщения, управляется с помощью параметра context. Наша конфигурация в xmpp.conf будет выглядеть так:

[asterisk]

type=client

serverhost=talk.google.com

username=asterisk@shifteight.org

secret=<super_secret_password>

priority=1

port=5222

usetls=yes

usesasl=yes

status=available

statusmessage=”Ohai from Asterisk”

timeout=5

sendtodialplan=yes

contexts=IncomingMessages

После обновления нашей конфигурации в xmpp.conf, вы можете перезагрузить модуль res_xmpp.so в Asterisk:

$ asterisk -rx “module reload res_xmpp.so”

Конфигурация sip.conf

Asterisk имеет начальную реализацию SIP-обмена сообщениями. Функциональность очень проста в том, что она поддерживает только метод SIP-сообщений MESSAGE. Сеансовый обмен сообщениями с использованием сеанса протокола MSRP не поддерживается. К сожалению, SIP-клиенты обычно поддерживают только сеансовые сообщения. Поскольку это не является частью Asterisk, обмен сообщениями через SIP наиболее полезен между самими боксами Asterisk.

Включение поддержки обмена сообщениями довольно просто. Существует три опции (описанные в Табл. 18-5), связанные с сообщениями, две из которых уже включены по умолчанию.

Table 18-5. Параметры, связанные с внешними сообщениями в SIP

Опция Описание
accept_outofcall_message Управляет включением обмена внешними сообщениями. Когда сообщения принимаются – они передаются в диалплан. Доступные настройки – yes и no. По умолчанию yes
auth_message_requests Определяет, должны ли запросы MESSAGE проходить аутентификацию. Доступные варианты: yes или no. По умолчанию yes.
outofcall_message_context Определяет, какой контекст должен обрабатывать внешние сообщения. Если параметр не задан, используется контекст, связанный с пиром во время сопоставления. Опция может быть установлена как на уровне [general], так и на уровне пира.

Вместо того, чтобы полагаться на настройки по умолчанию в Asterisk, мы определим все три опции в разделе [general] нашего sip.conf. Таким образом, мы можем увидеть явно, что мы включили:

; Внешние сообщения

accept_outofcall_message=yes

outofcall_message_context=IncomingMessages

auth_message_requests=yes

Если вы хотите переопределить настройки по умолчанию, которые мы создали здесь, для определенных пиров, просто добавьте outofcall_message_context=Какой-тоКонтекст в определение пиров SIP.

После настройки перезагрузите драйвер SIP-канала:

$ asterisk -rx “sip reload”

Конфигурирование диалплана

В этом разделе мы покажем, как настроить дилплан для приема и отправки сообщений по протоколу XMPP.

В то время как отправка и получение сообщений через SIP возможны – это, как правило, не используется. Рассмотрим примеры в этом разделе, чтобы быть трамплином для вашей разработки, если вам нужна эта функциональность.

После того, как мы настроили нашу систему, как описано в “Конфигурация xmpp.conf”, нам нужно настроить наш дилплан для обработки входящих сообщений. Во-первых, давайте настроим диалплан так, чтобы мы могли принять сообщение и отобразить его в консоли Asterisk:

[IncomingMessages]

exten => s,1,NoOp()

same => n,Verbose(2,Totally getting a message yo)

same => n,Verbose(2,Got message from ${MESSAGE(from)} destined for

${MESSAGE(to)} with body ${MESSAGE(body)}))

Как видите, мы определили наш контекст как IncomingMessages. Когда сообщение поступает в Asterisk, оно будет сопоставлено в контексте расширением s. В первую очередь мы просто выполняем NoOp(). Следующая строка выводит стандартный текст с помощью приложения Verbose(). В последней строке мы снова используем приложение Verbose() для отображения содержимого body сообщения, а также from – от кого пришло сообщение и to – кому оно было предназначено. Содержимое body сообщения и заголовков from и to отображаются с помощью функции MESSAGE(), которая используется как для отображения полученных данных (как мы показали), так и для отправки данных из нашей системы Asterisk.

Чтобы проверить этот пример диалплана, введите следующую команду:

$ asterisk -r

*CLI> dialplan reload

*CLI> core set verbose 5

Теперь мы отправляем XMPP-сообщение на сервер Asterisk после добавления УАТС в список приятелей. После отправки любого сообщения мы должны увидеть Verbose() в консоли. В противном случае проверяем соединение с xmpp show connections и удостоверяемся, что сообщения пользователя УАТС перечислены в xmpp show buddies.

Чтобы отправить ответ мы используем функцию MESSAGE() для определения тела сообщения и приложение MessageSend() для запуска ответа, отправляемого на другой конец. Мы просто добавим следующие две строки после тех, что уже были определены в extensions.conf:

same => n,Set(MESSAGE(body)=Thank you for messaging the Shift-Eight PBX)

same => n,MessageSend(${MESSAGE(from)},XMPP:asterisk)

Давайте посмотрим, что мы делаем. Первая строка определяет текст сообщения, которым мы будем отвечать на входящее сообщение. Здесь нельзя задать несколько строк или создать новые строки в теле сообщения. Вторая строка – это то, что передает тело сообщения обратно конечным точкам, от которых мы получили сообщение. Аргументы в MessageSend() указывают кто ответил и какой аккаунт использовать для ответа.

Посмотрим на нашу вторую строку, наш первый аргумент использует функцию MESSAGE() с аргументом from, что приведет к отправке сообщения в ту же конечную точку, откуда мы получили сообщение. Второй аргумент представляет собой комбинацию протокола для ответа (в данном случае XMPP, другим параметром является SIP) и имени учетной записи, как определено в xmpp.conf (asterisk).

После внесения изменений перезагрузите диалплан с помощью dialplan reload и отправьте сообщение УАТС. Теперь вы должны получить ответ с благодарностью за обмен сообщениями Shift-Eight PBX.

Интеграция LDAP

Asterisk поддерживает возможность подключения к существующему серверу LDAP для загрузки информации на сервер Asterisk с помощью Архитектуры Realtime Asterisk (ARA). Преимущество интеграции Asterisk и LDAP сразу станет очевидным, когда вы начнете централизовывать свои механизмы аутентификации на сервере LDAP и использовать его для нескольких приложений: вы значительно сократите административные издержки управления пользователями, разместив всю их информацию в центральном расположении.

Существуют как коммерческие, так и открытые серверы LDAP. Наиболее популярным коммерческим решением, вероятно, является решение, реализованное серверами Microsoft Windows. Популярным сервером LDAP с открытым исходным кодом является OpenLDAP. Мы не будем углубляться в конфигурацию сервера LDAP здесь, но покажем схему, необходимую для подключения Asterisk к серверу и использование его для обеспечения SIP-соединений и службы голосовой почты для существующей пользовательской базы.

Конфигурирование OpenLDAP

Хотя обсуждение установки и конфигурации сервера LDAP выходит за рамки этой главы, оно, безусловно, применимо, чтобы показать вам, как мы расширили нашу первоначальную схему LDAP, чтобы добавить информацию, необходимую для интеграции Asterisk. Наша первоначальная установка следовала инструкциям со страницы документации Ubuntu. Нам нужно было только следовать инструкциям до и включить импорт backend.example.com.ldif; следующим шагом после импорта конфигурации серверной части является установка схем, связанных с Asterisk.

Если вы следуете вместе с импортированным бекэндом, перейдите в каталог исходников Asterisk. Затем скопируйте файл asterisk.ldap-schema в каталог /etc/ldap/schema:

$ cd ~/src/asterisk-complete/asterisk/11/contrib/scripts/

$ sudo cp asterisk.ldap-schema /etc/ldap/schema/asterisk.schema

После копирования файла схемы перезапустите сервер OpenLDAP:

$ sudo /etc/init.d/slapd restart

Теперь мы готовы импортировать содержимое asterisk.ldif на наш сервер OpenLDAP. Файл asterisk.ldif находится в папке /contrib/scripts каталога исходников Asterisk:

$ sudo ldapadd -Y EXTERNAL -H ldapi:/// -f asterisk.ldif

Теперь мы можем продолжить с онлайн-инструкцией и импортировать файл frontend.example.com.ldif. В этом файле находится начальный пользователь, которого мы можем пропустить на данный момент, поскольку собираемся изменить часть импорта пользователя, чтобы включить objectClass для Asterisk (т.е. в файле примера можно удалить раздел текста, начинающийся с uid=john).

Мы создадим пользователя и добавим значения конфигурации, что позволит пользователю зарегистрировать свой телефон (который, вероятно, софтфон, поскольку hardphone на рабочем столе пользователя, в большинстве случаев, настраивается централизовано) через SIP с использованием его логина и пароля, так же, как он обычно входит чтобы проверить почту и все остальное.

Файл конфигурации, который мы создадим далее, будет импортирован с помощью команды ldapadd и добавлен в объект people в пределах shifteight.org. Обязательно измените значения в соответствии с пользователем, которого вы хотите настроить в LDAP, и замените dc=shifteight,dc=org своим местоположением.

Однако, прежде чем мы создадим наш файл, нужно преобразовать пароль в MD5-хэш. Asterisk не будет аутентифицировать телефоны с помощью текстовых паролей при подключении через LDAP. Мы можем преобразовать пароль с помощью команды md5sum:

$ echo “my_secret_password” | md5sum

a7be810a28ca1fc0668effb4ea982e58 –

Мы вставим возвращаемое значение (без дефиса) в следующий файл в поле userPassword с префиксом {md5}:

$ cat > astuser.ldif

dn: uid=rbryant,ou=people,dc=shifteight,dc=org

objectClass: inetOrgPerson

objectClass: posixAccount

objectClass: shadowAccount

objectClass: AsteriskSIPUser

uid: rbryant

sn: Bryant

givenName: Russell

cn: RussellBryant

displayName: Russell Bryant

uidNumber: 1001

gidNumber: 10001

userPassword: {md5}a7be810a28ca1fc0668effb4ea982e58

gecos: Russell Bryant

loginShell: /bin/bash

homeDirectory: /home/russell

shadowExpire: -1

shadowFlag: 0

shadowWarning: 7

shadowMin: 8

shadowMax: 999999

shadowLastChange: 10877

mail: russell.bryant@shifteight.org

postalCode: 31000

l: Huntsville

o: shifteight

title: Asterisk User

postalAddress:

initials: RB

AstAccountCallerID: Russell Bryant

AstAccountContext: LocalSets

AstAccountDTMFMode: rfc2833

AstAccountMailbox: 101@shifteight

AstAccountNAT: yes

AstAccountQualify: yes

AstAccountType: friend

AstAccountDisallowedCodec: all

AstAccountAllowedCodec: ulaw

AstAccountMusicOnHold: default

Ctrl+D

Единственное поле, которое мы должны здесь упомянуть – это поле UserPassword. Мы требуем, чтобы значение в этом поле было в формате MD5-хэш. В версиях Asterisk до 1.8.0, префикс {MD5} перед хэш требуется. Хотя в более новых он больше не требуется, но все еще рекомендуется.

С созданного файла мы можем добавить пользователя на наш сервер LDAP:

$ sudo ldapadd -x -D cn=admin,dc=shifteight,dc=org -f astusers.ldif -W

Enter LDAP Password:

adding new entry “uid=rbryant,ou=people,dc=shifteight,dc=org”

Теперь наш пользователь импортирован в LDAP. Следующий шаг – необходимо настроить Asterisk для подключения к серверу LDAP и позволить пользователям аутентифицировать и регистрировать свои телефоны.

Компиляция поддержки LDAP в Asterisk

После настройки сервера OpenLDAP и импорта схемы необходимо установить зависимости для Asterisk и скомпилировать модуль res_config_ldap. Этот модуль является ключом, который позволит нам настроить Asterisk realtime для доступа к нашим пирам через LDAP.

После установки зависимости, необходимо перезапустить скрипт ./configure в каталоге исходников Asterisk, затем убедитесь, что выбран модуль res_config_ldap. Затем можете запустить make install для компиляции и установки нового модуля.

Зависимости Ubuntu

В Ubuntu нам нужно установить пакет openldap-dev, чтобы обеспечить зависимость для модуля res_config_ldap:

$ sudo apt-get install openldap-dev

Зависимости RHEL

В RHEL нам нужно установить пакет openldap-devel, чтобы обеспечить зависимость для модуля res_config_ldap:

$ sudo yum install openldap-devel

Конфигурирование Asterisk для поддержки LDAP

Теперь, когда мы настроили наш сервер LDAP и установили модуль res_config_ldap, нам нужно настроить Asterisk для поддержки загрузки пиров из LDAP. Для этого необходимо настроить файл res_ldap.conf для подключения к серверу LDAP и extconfig.conf для указания Asterisk, какую информацию следует получить от сервера LDAP и каким образом. Как только это будет сделано, мы можем настроить любые оставшиеся файлы конфигурации модуля, такие как sip.conf, iax.conf, voicemail.conf и так далее, где уместно. В нашем примере мы будем настраивать Asterisk для загрузки наших SIP-пиров из realtime, используя сервер LDAP в качестве нашей базы данных.

Конфигурирование res_ldap.conf

Файл res_ldap.conf.sample является хорошим местом для начала, потому что он содержит хороший набор шаблонов. Однако в верхней части файла, в разделе [_general], нам нужно настроить как Asterisk будет подключаться к нашему серверу LDAP. Наш первый вариант – url, который определит, как подключиться к серверу. Мы определили соединение как ldap://172.16.0.103:389, которое соединится с сервером LDAP по IP-адресу 172.16.0.103 на порт 389. Если у вас есть безопасное соединение с сервером LDAP, то можете заменить ldap:// на ldaps://. Кроме того, мы установили protocol=3, чтобы указать, что мы подключаемся к 3 версии протокола, что в большинстве (если не во всех) случаев будет правильным.

Последние три опции basedn, user и pass используются для аутентификации на нашем сервере LDAP. Нам нужно уточнить:

  • basedn (dc=shifteight,dc=org), которое является, по сути, доменным именем
  • Имя user, под которым мы собираемся аутентифицироваться на сервере LDAP как (admin)
  • Пароль пользователя для аутентификации (canada)

Если мы сложим все это вместе, мы получим что-то вроде следующего:

[_general]

url=ldap://172.16.0.103:389

protocol=3

basedn=dc=shifteight,dc=org

user=cn=admin,dc=shifteight,dc=org

pass=canada

Помимо этого, в остальной части примера файла конфигурации мы увидим множество шаблонов, которые можем использовать для сопоставления информации в Asterisk с нашей схемой LDAP. Давайте взглянем на первые строки шаблона [sip], который мы будем использовать для сопоставления информации о наших узлах SIP с базой данных LDAP:

[sip]

name = cn

amaflags = AstAccountAMAFlags

callgroup = AstAccountCallGroup

callerid = AstAccountCallerID

lastms = AstAccountLastQualifyMilliseconds

useragent = AstAccountUserAgent

additionalFilter=(objectClass=AsteriskSIPUser)

С левой стороны у нас есть поле в Asterisk с именем которое будем искать, а справа – сопоставление со схемой LDAP для запроса. Наш первый набор полей сопоставляет поле name с полем cn на сервере LDAP. Если вы посмотрите на данные, которые мы импортировали в разделе “Конфигурирование OpenLDAP” то увидите, что мы создали пользователя и присвоили значение RussellBryant полю cn. Таким образом, в нашем случае мы сопоставляем имя аутентификации (поле name) пользователя SIP со значением поля cn на сервере LDAP (RussellBryant).

Это относится и к остальным значениям далее некоторых полей (т.е. useragent, lastms, ipaddr), которые просто должны существовать, поэтому Asterisk может записывать информацию (например, регистрационную) на сервер LDAP.

Конфигурирование extconfig.conf

Наш следующий шаг – рассказать Asterisk, какую информацию загружать в realtime и какую технологию использовать. Используя файл extconfig.conf у нас есть возможность загрузки нескольких модулей динамически (но мы также можем загружать файлы статически). Дополнительные сведения об Asterisk realtime см. В разделе “Использование Realtime” в Главе 16.

В нашем примере мы настроим динамические объекты realtime sipusers и sippeers для загрузки наших SIP-пиров из LDAP. В следующем примере, у нас есть такой:

ldap,”ou=people,dc=shifteight,dc=org”,sip

Мы указали три аргумента. Во-первых, ldap – это технология, которую мы будем использовать для подключения к нашему объекту в realtime. Существуют и другие технологии, такие как odbc, pgsql, curl и так далее. Наш второй аргумент, заключенный в двойные кавычки, указывает, к какой базе данных мы подключаемся. В случае LDAP мы подключаемся к объекту-модулю people в домене shifteight.org. Наконец, наш третий аргумент – sip определяет, какой шаблон мы используем (как определено в res_ldap.conf) для сопоставления данных realtime с базой данных LDAP.

Кроме того, можно указать четвертый аргумент, который является приоритетом. При определении нескольких объектов realtime, например при определении queues или sippeers можно использовать аргумент приоритета для управления отказоустойчивостью, если конкретный механизм хранения становится недоступным. Приоритеты должны начинаться с 1 и увеличиваться последовательно.

Чтобы определить использование sipusers и sippeers с сервера LDAP, мы включили бы эти строки в extconfig.conf:

sipusers => ldap,”ou=people,dc=shifteight,dc=org”,sip

sippeers => ldap,”ou=people,dc=shifteight,dc=org”,sip

Конфигурирование sip.conf для realtime

Эти шаги являются необязательными для настройки SIP в realtime, хотя вы, вероятно, ожидаете, что все будет работать так, как мы собираемся описать. В файле sip.conf мы включим несколько опций для realtime, которые будут кэшировать информацию в память по мере загрузки из базы данных. Таким образом, мы позволим Asterisk звонить на устройства, просто просматривая информацию, хранящуюся в памяти. Кэширование не только делает realtime потенциально более эффективным, но и такие вещи как обновление состояний устройства, просто не могут работать, если устройства не кэшируются в памяти.

Пир загружается в память только после регистрации устройства или его вызова. При выполнении команды sip reload из консоли пиры будут очищены из памяти, поэтому может потребоваться изменить время регистрации, если это будет вызывать проблемы в системе.

Чтобы включить кэширование пиров в Asterisk, используйте параметр rtcachefriends в sip.conf:

rtcachefriends=yes

Есть дополнительные опции в realtime, такие как rtsavesysname, rtupdate, rtautoclean и ignoreregexpire. Они все объяснены в файле sip.conf.sample, расположенном в исходниках Asterisk.

Утилиты Text-to-Speech

Утилиты преобразования текста-в-речь используются для преобразования строк слов в аудио, которое можно воспроизводить вызывающим абонентам. Преобразование текста-в-речь существует уже много лет и постоянно совершенствуется. Хотя мы не можем рекомендовать утилиты преобразования текста-в-речь вместо профессионально записанных приглашений, они могут быть полезны в приложениях, где динамические данные должны передаваться вызывающему абоненту.

Festival

Festival является одним из старейших приложений для преобразования текста-в-речь в Linux. Хотя качество Festival не является достаточным для того, чтобы рекомендовать его для использования в продакшене, это, безусловно, полезный способ тестирования приложения на основе текста-в-речь. Если для вашего применения необходим более отполированный звук, то мы рекомендуем вам посмотреть Cepstral (рассмотренный далее).

Установка Festival в RHEL

Установка Festival и его зависимостей для RHEL проста. Просто используйте yum для установки пакета festival:

$ sudo yum install festival

Установка Festival в Ubuntu

Установка Festival и его зависимостей для RHEL проста. Просто используйте apt-get для установки пакета festival:

$ sudo apt-get install festival

Использование Festival с Asterisk

С установленным фестивалем нам нужно изменить файл festival.scm для подключения Asterisk к серверу Festival. На RHEL и Ubuntu файл находится в /usr/share/festival. Откройте файл и поместите следующий текст чуть выше последней строки (provide ‘festival’):

(define (tts_textasterisk string mode)

“(tts_textasterisk STRING MODE)

Apply tts to STRING. This function is specifically designed for

use in server mode so a single function call may synthesize the string.

This function name may be added to the server safe functions.”9

(let ((wholeutt (utt.synth (eval (list ‘Utterance ‘Text string)))))

(utt.wave.resample wholeutt 8000)

(utt.wave.rescale wholeutt 5)

(utt.send.wave.client wholeutt)))

После добавления этого необходимо запустить сервер фестиваля:

$ sudo festival_server 2>&1 > /dev/null &

С помощью menuselect из каталога исходников Asterisk убедитесь, что приложение app_festival выбрано в разделе Applications. Если оно еще не было выбрано не забудьте запустить make install после его выбора, чтобы установить приложение диалплана Festival().

Прежде чем использовать приложение Festival(), необходимо сообщить Asterisk, как подключиться к серверу Festival. Файл festival.conf используется для управления подключением и взаимодействием Asterisk с сервером Festival. Файл festival.conf.sample, расположенный в каталоге с исходным кодом Asterisk, является хорошим местом для начала, поэтому скопируйте festival.conf.sample из подкаталога /configs исходников Asterisk в каталог конфигурации /etc/asterisk:

$ cp ~/asterisk-complete/asterisk/11/configs/festival.conf.sample \

/etc/asterisk/festival.conf

Конфигурации по умолчанию обычно достаточно чтобы подключиться к серверу Festival на локальной машине, но при необходимости вы можете настроить параметры, такие как host, где распологается сервер Festival (удаленный), port для подключения, нужно ли включать кэширование файлов (по умолчанию no), расположение директории кэша (по умолчанию /tmp) и команда Asterisk передачи серверу Festival.

Чтобы убедиться, что приложение Festival() доступно, запустите core show application festival из консоли Asterisk:

*CLI> core show application festival

Если выходные данные не выводятся, может потребоваться загрузить модуль app_festival.so:

*CLI> module load app_festival.so

Убедитесь, что модуль app_festival.so существует в /usr/lib/asterisk/modules, если у вас все еще есть проблемы с загрузкой модуля.

После загрузки приложения Festival() в Asterisk необходимо создать тестовое расширение диалплана, чтобы убедиться, что Festival() работает:

[LocalSets]

exten => 203,1,Verbose(2,This is a Festival test)

same => n,Answer()

same => n,Playback(silence/1)

same => n,Festival(Hello World)

same => n,Hangup()

Перезагрузите диалплан с помощью команды dialplan reload из консоли Asterisk и протестируйте соединение с Festival, набрав добавочный номер 203.

Кроме того, если у вас возникли проблемы с сервером Festival, можно использовать следующий метод для создания файлов с помощью приложения text2wave, поставляемого с пакетом festival:

exten => 202,1,Verbose(2,Trying out Festival)

same => n,Answer()

; *** Эта строка не должна содержать разрывов строк

same => n,System(echo “This is a test of Festival”

| /usr/bin/text2wave -scale 1.5 -F 8000 -o /tmp/festival.wav)

same => n,Playback(/tmp/festival)

same => n,System(rm -f /tmp/festival.wav)

same => n,Hangup()

Теперь вы имеете достаточно, чтобы начать работу с генерацией аудио текста-в-речь для вашей системы Asterisk. Качество звука не блестящее, и генерируемая речь недостаточно ясна, чтобы ее можно было легко понять по телефону, но для целей разработки и тестирования Festival может заполнить пробел, пока вы не будете готовы к более профессиональному звучанию генератора текста-в-речь, такому как Cepstral.

Cepstral

Cepstral – это механизм преобразования текста-в-речь, который работает аналогично приложению Festival() в диалплане, но он производит гораздо более качественный звук. Не только качество значительно лучше, Cepstral разработала движок текст-в-речь, который эмулирует голос Элисон, так что ваш текст-в-речь может выдавать те же английские звуковые файлы, которые поставляются с Астериск по умолчанию, чтобы дать совместимые фразы для вызывающего абонента.

Cepstral является коммерческим модулем, но примерно за 30 долларов США вы можете иметь механизм преобразования текста-в-речь, который более ясен, более согласован с другими звуковыми подсказками в вашей системе и обеспечивает более приятный опыт для ваших абонентов. Инструкции программного обеспечения и установки Cepstral можно загрузить с интернет-магазина Digium.com.

Вывод

В этой главе мы сосредоточились на интеграции Asterisk с внешними службами, которые могут не иметь прямого отношения к созданию или обработке вызовов, но обеспечивают более тесную связь с существующими службами в сети, предоставляя сведения о маршрутизации вызовов или сведения о пользователях из существующей инфраструктуры.

1И потому авторы этой книги не имеют доступа к серверам Exchange для тестирования. 🙂

2На момент написания статьи в процессе загрузки модулей календаря после запуска Asterisk возникла ошибка. Она была подана как ошибка 18067 на https://issues.asterisk.org и, надеюсь, будет решена к тому времени, когда вы будете читать это. В противном случае следует помнить, что для правильной загрузки модулей в память может потребоваться перезапуск Asterisk.

3В Unix, epoch – это количество секунд, прошедших с 1 января 1970 года, не считая високосных секунд.

4Когда мы говорим “это работает”, то имеем в виду, что Asterisk составит электронное письмо и отправит его в MTA, и электронное письмо будет успешно передано из системы. То, что происходит с ним после того, как оно покидает систему, немного сложнее и часто включает в себя спам-фильтры, рассматривающие почту как подозрительную и фактически не доставляющие ее. На самом деле это не вина Asterisk, но это то, с чем вам придется иметь дело.

5Недавно мы также проверили open source проект roundcube для веб-почты и были очень впечатлены.

6Входящий вызов для ${CALLERID(all)}. Нажмите 1 для соединения. Нажмите 2 для отправки голосовой почты.

7Дополнительную информацию смотрите в разделе “Расширение s” в Главе 7.

8Для совершения звонков в определенные пункты назначения может потребоваться приобрести кредиты Google Voice в панели управления.

9Применить tts к STRING. Эта функция специально разработана для использования в режиме сервера, поэтому один вызов функции может синтезировать строку. Это имя функции может быть добавлено к функциям безопасности сервера.

Остались вопросы?

Я - Компаниец Никита, менеджер компании Voxlink. Хотите уточнить детали или готовы оставить заявку? Укажите номер телефона, я перезвоню в течение 3-х секунд.

VoIP оборудование

ближайшие курсы

ближайшие Вебинары

ONLINE

Why Choose HUGE?

Unlimited pre-designed elements

Each and every design element is designed for retina ready display on all kind of devices

User friendly interface and design

Each and every design element is designed for retina ready display on all kind of devices

100% editable layered PSD files

Each and every design element is designed for retina ready display on all kind of devices

Created using shape layers

Each and every design element is designed for retina ready display on all kind of devices