Интеграция Skype и Asterisk

Skip to end of metadata
Go to start of metadata

Интеграция Skype и Asterisk

Скришоты



Описание проблемы

Asterisk PBX обладает возможностью принимать звонки из сети Skype, а также осуществлять звонки в эту сеть. Данную возможность обеспечивает модуль chan_skype для Asterisk от Digium. После установки этого модуля, в Asterisk появляется новый тип канала — Skype, который доступен всем подключенным абонентам.
Однако, при использовании этого канала Skype возникает вопрос удобного его использования. В данный момент исходящие вызовы в Skype возможны если:

  • абонент звонит с программного телефона, в котором вместо номера можно набрать skypeid;
  • системный администратор прописал в конфигурационном файле статические настройки на skypeid, например: exten => 100,1,Dial(Skype/vasea_pupkin). Чтобы связаться со Skype пользователем vasea_pupkin, абоненты Астериск набирают номер 100.

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

Решение

Решением описанной проблемы является создание пользовательского интерфейса, при помощи которого абоненты АТС сами смогут назначать номера для Skype собеседников. Более того, при входящих звонках из сети Skype новый номер должен создаваться автоматически. Рассмотрим более детально.

Архитектура

Структуры данных

Для хранения данных используется ПО SQLite3.
Для хранения списка [SkypeID] и номеров используется следующая таблица:

Поле Тип Описание
id INTEGER AUTOINCREMENT PK Без комментариев
exten INTEGER UNIQUE NOT NULL Внутренний номер в АТС пользователя Skype
skypeid VARCHAR(256) UNIQUE NOT NULL [SkypeID] пользователя сети Skype
modified DATETIME Дата изменения записи
created DATETIME Дата создания записи

Обработка входящих звонков

При входящем звонке из сети Skype АТС Asterisk проверяет, существует ли в базе данных звонящий Skype пользователь. Если пользователь не найдет, выполняются следующие действия:
создается новая запись, где skypeid — идентификатор Skype пользователя, а exten — следующий свободный номер, генерируемый автоматически.
Астериск вызывает функцию установки [CallerID], и устанавливает CALLERID(num)=exten, а CALLERID(name)=skypeid. Таким образом, внутренний абонент АТС видит, какой номер у звонящего Skype пользователя, и может ему перезвонить по этому номеру (об этом далее).
Если звонящий пользователь Skype уже существует в базе, тогда вызывается только функция установки CALLERID номера и имени по найденному skypeid.

Обработка исходящих звонков

В контекст обработки исходящих звонков помещается проверка на наличие набранного номера в списке Skype пользователей. Если номер найден, делается звонок в сеть Skype по найденному skypeid.

WEB интерфейс пользователя

Для более точного управления списком номеров и skypeid используется WEB интерфейс. Это может потребоваться в случаях:

  • изменения skypeid для номера (привыкли набирать по короткому, а skypeid сменился);
  • добавление skypeid с заведомо назначенными номерами;
  • другое.
    Для написания WEB интерфейса мы использовали http://en.wikipedia.org/wiki/Lua_(programming_language), так как этот язык очень "легок" по сравнению с PERL/PHP/Python и другими.

    Описание Интерфейса

  • WEB интерфейс представляет собой единую страницу, доступную всем (можно и без авторизации).
  • При загрузке страница выводит список существующих записей с возможностями паджинации и сортировки по: exten, skypeid, дате добавления, дате изменения.
  • На странице доступен поиск по exten и по skypeid.
  • Возможно изменение поля exten, skypeid.
  • Поле modified меняется автоматически и доступно в режиме только чтение (как и created), служит в информационных целях.

Установка

Зависимости

  • Библиотеки и заголовочные файлы (инклуды): readline (readline-devel), libtool.(libtool)
  • SQLite3 и SQLite3 инклуды (sqlite3-devel)
  • unixODBC и SQLite3 ODBC драйвер
  • Asterisk
  • WEB, умеюший выполнять CGI скрипты: Nginx / Apache / Lighttp
    Заголовочные файлы требуются только в случае самостоятельной сборки пакета из исходных кодов (см. далее).

    Скачивание Skype for Asterisk GUI

Установка скомпилированных пакетов

  • Для 32-х битной платформы (обычный PC) надо скачать файл asterisk-chan_skype-gui-0.1-x32-bin.tar.gz с сайта Asterisk Forge.
  • Для 64-битных платформ надо брать файл asterisk-chan_skype-gui-0.1-x64-bin.tar.gz с Asterisk Forge.
    Скачайте и распакуйте архив в /var/www/skype/. Если Вы хотите установить в другую директорию, потребуется отредактировать config.lua, расположенный в cgi-bin, и изменить пути. Файл по умолчанию предполагает, что URL продукта /skype/, и физическое расположение /var/www/skype/.
    config.lua
    prefixUrl="/skype"
    tmpDir = "/var/www/skype/cgi-bin/tmp"
    sessionsDir = "/var/www/skype/cgi-bin/sessions"
    dsn = "sqlite3://asterisk:df37hslkv@localhost/db/data.db"
    
    for _, path in ipairs{"/var/www/skype/lib/";"/var/www/skype/share/"} do
        package.cpath = (package.cpath or "?.so")..";"..path.."?.so"
        package.path = (package.path or "?.lua")..";"..path.."?.lua;"..path.."?/init.lua"
    end
    

Установка из исходных кодов

Если Вам не подходит установка бинарных файлов, Вы можете собрать весь пакет самостоятельно.
Скачайте asterisk-chan_skype-gui-0.1-src-tar.gz с сайта Asterisk Forge.
Сохраните во временной папке и распакуйте. Отредактируйте скрипт install.sh и замените при необходимости переменные AST_USER/AST_GROUP на системные учетные записи UNIX, под которыми работают процессы Asterisk и HTTP сервер. По-умолчанию, используются asterisk и apache. После этого запустить скрипт, передав ему в качестве параметра папку назначения, как показано в примере (используется путь /var/www/skype)

snowflake tmp #
snowflake tmp # tar zxf asterisk-chan_skype-gui-0.1-src.tar.gz
snowflake tmp # cd asterisk-chan_skype-gui-0.1-src
snowflake asterisk-chan_skype-gui-0.1-src # ./install.sh /var/www/skype
Compiling Lua...
Compiling Lua Datafilter...
Compiling Lua Socket...
Compiling Lua Posix...
Compiling Lua SQL...
Unpacking Luv...
Unpacking Skype GUI...
snowflake asterisk-chan_skype-gui-0.1 #

Если все прошло хорошо, переходим к конфигурированию WEB сервера. Если у Вас какие-то ошибки, смотрите файл build.log, в котором содержится детальный лог работы скрипта. Вы можете выслать его нам для анализа по адресу tech(at)pbxware.ru с темой "Ошибка установки chan_skype".

Конфигурация WEB сервера

Использование Виртуального Сервера

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

_Внимание!_ У нас установлен urlPrefix="" в cgi-bin/config.lua, так как продукт находится в корневой директории нашего WEB сервера.

<VirtualHost *:443>
    ServerName skype.domain.com
    DocumentRoot /var/www/skype/htdocs
    CustomLog     /var/log/apache2/skype.domain.com-access.log combined
    ErrorLog      /var/log/apache2/skype.domain.com-error.log
    LogLevel warn
    SSLEngine on
    SSLCertificateKeyFile /etc/apache2/ssl/server.key
    SSLCertificateFile /etc/apache2/ssl/server.crt

    ScriptAliasMatch ^/(?!(images/|js/|css/))  /var/www/skype/cgi-bin/index.lua/$1

    <Directory /var/www/skype/htdocs>
        Order deny,allow
        Allow from all
    </Directory>

    <Directory /var/www/skype/cgi-bin>
        Order deny,allow
        Allow from all
        AuthType basic
        AuthName "Skype configuration"
        AuthUserFile /var/www/skype/.htpasswd
        require valid-user
    </Directory>

</VirtualHost>

Теперь создадим файл с паролями:

snowflake ~ # htpasswd -c /var/www/skype/.htpasswd admin
New password:
Re-type new password:
Adding password for user admin
snowflake ~ #

Перегружаем apache и заходим на https://skype.domain.com. Появляется окно с вводом пароля.

Конфигурация в папке

Более простая конфигурация в существующем контейнере. В приведенном примере используется путь /skype/, поэтому установлена переменная urlPrefix="/skype" (без завершающего слеша) в файле cgi-bin/config.lua

# We make an assumption that skype gui package is unpacked into /var/www/skype and WEB site URL is http://domain.com/skype/

ScriptAliasMatch ^/skype/(?!(images/|js/|css/))  /var/www/skype/cgi-bin/index.lua/$1
<Directory /var/www/skype/cgi-bin>
        Order deny,allow
        Allow from all
        #AuthType basic
        #AuthName "Skype configuration"
        #AuthUserFile /var/www/skype/.htpasswd
        #require valid-user
</Directory>

Alias /skype/ "/var/www/skype/htdocs/"
<Directory /var/www/skype/htdocs>
        Order deny,allow
        Allow from all
</Directory>

Asterisk

ODBC

Используется SQLite3 в качестве базы данных через res_ODBC.

/etc/unixODBC/odbcinst.ini
[SQLite3]
Description=ODBC for SQLite3
Driver=/usr/lib/libsqlite3odbc.so
Setup=/usr/lib/libsqlite3odbc.so
Threading=2

Убедитесь, что путь к библиотеке libsqlite3odbc.so правильный!

/etc/unixODBC/odbc.ini
[SQLite3-skype]
Description=SQLite3 Skype database
Trace=Off
TraceFile=stderr
Driver=SQLite3
Database=/var/www/skype/cgi-bin/db/data.db

Если Вы меняете пути по-умолчанию, не забудьте сменить и тут.

/etc/asterisk/res_odbc.conf
[ENV]

[skype]
enabled => yes
dsn => SQLite3-skype
pre-connect => yes
/etc/asterisk/func_odbc.conf
[SKYPE_EXT]
dsn=skype
readsql=SELECT exten FROM skypecontact WHERE skypeid='${SQL_ESC(${ARG1})}'

[SKYPE_NAME]
dsn=skype
readsql=SELECT skypeid FROM skypecontact WHERE exten='${SQL_ESC(${ARG1})}'

[SKYPE_MAX_EXT]
dsn=skype
readsql=SELECT MAX(exten) FROM skypecontact

[SKYPE_ADD]
dsn=skype
writesql=INSERT INTO skypecontact (exten, skypeid, created, modified) VALUES ('${SQL_ESC(${VAL1})}', '${SQL_ESC(${VAL2})}', datetime('now','localtime'), datetime('now','localtime'))

Skype

Skype эккаунты сконфигурированы в chan_skype.conf

chan_skype.conf

[general]
engine_directory=/tmp/skype
default_user=pbxware.ru
bind_address=x.x.x.x
bind_port=0

[pbxware.ru]
secret=XXXXXXXXXXXXXXX
context=skype-in
exten=s
disallow=all
allow=ulaw
direction=both
auth_policy=accept

Наиболее важные настройки:

  • context - все звонки из Skype обрабатываются в этом контексте;
  • exten - какой номер набрать в указанном контексте.

Dialplan

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

; Context for our users
[from-internal]
exten => _XXX,1,Macro(std-exten,${EXTEN})
exten => _XXXX,1,Goto(skype-out,${EXTEN},1)

; Here we define what we do with incoming calls from skype
[from-skype]
exten => s,1,Goto(menu-main,s,1)
exten => _XXX,1,Goto(from-internal,${EXTEN},1)

; Context for outgoing skype calls
[skype-out]
exten => _XXXX,1,Set(DST=${EXTEN})
exten => _XXXX,2,Goto(s,1)
exten => s,1,Set(skype_name=${ODBC_SKYPE_NAME(${DST})})
exten => s,n,ExecIf($["${skype_name}" = ""]|Hangup)
exten => s,n,Dial(Skype/${skype_name})

; Context for incoming Skype calls
[skype-in]
; Save dialed exten
exten => _X.,1,Set(DST=${EXTEN})
exten => _X.,2,Goto(s,1)
; If from skype comes start exten
;exten => s,1,ExecIf($["${DST}" = ""]|Set|DST=s); 1.4 version
exten => s,1,ExecIf($["${DST}" = ""]?Set(DST=s)); 1.6 version
; Let see if we already have this account
exten => s,n,Set(skype_name=${CALLERID(num)})
exten => s,n,Set(skype_ext=${ODBC_SKYPE_EXT(${skype_name})})
exten => s,n,GotoIf($["${skype_ext}" = ""]?not-found:found)
; Existing account found
exten => s,n(found),NoOp(Found Skype ID ${skype_name} with exten ${skype_ext})
exten => s,n,Set(CALLERID(num)=${skype_ext})
exten => s,n,Set(CALLERID(name)=${skype_name})
exten => s,n,Goto(from-skype,${DST},1)
; New Skype account calling
exten => s,n(not-found),Set(skype_ext=${ODBC_SKYPE_MAX_EXT()}); Get maximum extension number
;if database is empty we initialize 1-st exten 1000
;exten => s,n,ExecIf($["${skype_ext}" = ""]|Set|skype_ext=1000); 1.4. version
exten => s,n,ExecIf($["${skype_ext}" = ""]?Set(skype_ext=1000)); 1.6 version
; Add new record with next available exten
;exten => s,n,Set(ODBC_SKYPE_ADD()=$[${skype_ext}+1]\,${skype_name}); 1.4 version
exten => s,n,Set(ODBC_SKYPE_ADD()=$[${skype_ext}+1],${skype_name}); 1.6 version
exten => s,n,Set(CALLERID(num)=${skype_ext}+1)
exten => s,n,Set(CALLERID(name)=${skype_name})
exten => s,n,Goto(from-skype,${DST},1)

'''Внимание! Этот конфигурационный файл для Asterisk 1.6. Для Asterisk 1.4 надо закомментировать одни строки и расскоментировать другие. Смотрите комментарии. В противном случае Asterisk будет "ругаться".

Перегрузите Asterisk

CLI> reload

Готово

Теперь позвоните со своего Skype софтфона на Ваш корпоративный Skype эккаунт и убедитесь, как это сработало!

Если Вам потребуется помощь, у Вас есть пожелания по доработки или адаптации под Ваше окружение, пишите на tech(at)pbxware.ru с пометкой "Разработка chan_skype".

Проблемы

Смотрите также англоязычную версию документации, раздел Troubleshooting.

Контакты и авторское право

Данный продукт разработан компанией "АТС Дизайн" - www.pbxware.ru.

Продукт распространяется под лицензией GNU GPL.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jun 19, 2011

    Pogonea Konstantin says:

    1. Ошибка в диалплане для 1.6, мои поправки: ; Add new record with next avail...

    1. Ошибка в диалплане для 1.6, мои поправки:

    ; Add new record with next available exten
    exten => s,n,Set(skype_ext=$[${skype_ext}+1]) ; -- добавил присвоение нового значения, чтобы в дальнейшем не суммировать каждый раз
    ;exten => s,n,Set(ODBC_SKYPE_ADD()=${skype_ext}\,${skype_name}); 1.4 version
    exten => s,n,Set(ODBC_SKYPE_ADD()=${skype_ext}\,${skype_name}); 1.6 version -- для 1.6 пришлось также добавить слэш м\у значениями, иначе ничего не передавал
    exten => s,n,Set(CALLERID(num)=${skype_ext}) ; -- не хватало $[ ], если делать +1 выше, то тогда уже и не нужно
    exten => s,n,Set(CALLERID(name)=${skype_name})
    exten => s,n,Goto(from-skype,${DST},1)

    2.Не работает удаление\изменение записей через web-интерфейс, только добавление. Мои хождения по скриптам lua ничего не дали...

    [AsteriskNOW], апач работает от юзера asterisk.