Table of Contents

Создание Skype ↔ SIP гейта

Задача

Одним из наиболее популярных приложений для голосового общения в сети является Skype. Для этого есть и объективные предпосылки - достаточно развитые возможности клиента и протокола, неплохая работа в условиях NAT (и даже возможность работы через прокси), интеграция (коммерческая) с телефонными сетями, мультиплатформенный клиент. Основной недостаток - закрытость протокола и клиента, сложность интеграции с другими chat/voice сервисами, замкнутость технологии на одной компании. Тем не менее - реалии таковы что на сегодняшний день это наиболее популярное средство для общения и, на мой взгляд, альтернатив, особенно открытых, немного. В этой заметке я решил описать создание гейта skype ↔ SIP с использованием IP АТС Asterisk. Данное решение позволит преобразовать skype трафик в стандартный и открытый SIP, с которым потом уже средствами Asterisk (и не только) можно делать все что угодно.

Выбор ПО

Редкий тролль не любит рассказов об ужасах, скрывающихся в BLOB`ах закрытых продуктов (особенно забавна история когда обнаружили чтение skype`ом /etc/passwd и стали трубить о том что скайп “ворует пароли”), которые чаще всего не подкреплены какими либо доказательствами. Тем не менее - в данной задаче, на мой взгляд, и в самом деле удобнее создать изолированное окружения, как по соображениям безопасности так и с точки зрения удобства поддержки. В качестве виртуальной машины я выбрал linux-kvm (также успешно протестирована работа в VirtualBox), в качестве гостевой среды - debian 5 (который как раз только что вышел). Выбор основан исключительно на личных предпочтениях, думаю что должно работать на любом другом дистрибутиве, и скорее всего, даже на BSD (в линуксяторе). В дальнейшем я планирую перенести гейт на XEN, так что в данном случае нормальная поддержка в debian работы в domU тоже плюс. Единственным найденным мной открытым решением для *nix стал Skypiax, так что тут и выбирать не пришлось.

Принцип работы

Как уже упоминалось - скайп закрытое приложение, и его протокол достаточно неплохо защищен от сторонних разработчиков. Так что единственным доступным клиентом протокола в настоящий момент является сам skype. Но для интеграции своего ПО со сторонними разработчиками (как железа, так и ПО) skype клиент позволяет работать с ним используя документированное API. В linux версии для транспорта используется DBUS и X11. API достаточно обширно, но тем не менее о полноценном embed клиенте говорить не приходится, так что нам все равно потребуется X11 и запущенный клиент. Skypiax позволяет Asterisk общаться с запущенными skype клиентами и совершать или принимать skype звонки.

Установка ПО

Для начала установим ОС. Для нашей задачи будет вполне достаточно диска на 2Gb (думаю, что хватило бы и сильно меньшего но это потребовало бы пересборки пакетов без ненужных зависимостей). Ставить дистрибутив x86_64 лишено смысла, так как клиент все равно i386, да и памяти меньше израсходуем.

~: qemu-img create ~/images/skype 2G
~: kvm -hda ~/images/skype -cdrom ~/dists/debian-500-i386-CD-1.iso

Выбираем вариант установки без десктоп окружения и прочего непотребства, все что нужно мы позже установим из пакетов. После того как установка завершена - перезагружаем гостя и устанавливаем нужные пакеты:

Asterisk, заголовки и куча преимущественно ненужных нам зависимостей

skype:~# apt-get install asterisk-dev  

Skype client

skype:~# wget http://skype.com/go/getskype-linux-deb
skype:~# dpkg -i skype-debian_2.0.0.71-1_i386.deb
skype:~# apt-get -f install
skype:~# dpkg -i skype-debian_2.0.0.71-1_i386.deb

Subversion (потребуется для скачивания исходников skypiax)

skype:~# apt-get install subversion

OpenSSH server (для управления в будущем и первоначальной настройки Skype)

skype:~# apt-get install openssh-server

Заголовки Xlib потребуются нам позже

skype:~# apt-get install libx11-dev

Теперь загрузим и скомпилируем skypiax:

skype:~# svn co http://www.celliax.org:8081/svn/celliax/trunk celliax 
skype:~# cd celliax/skypiax_stuff/build/
skype:~/celliax/skypiax_stuff/build# vi Makefile

Заменяем путь AST_INCLUDE_DIR=/home/user/devel/asterisk-1.4.23.1/include на AST_INCLUDE_DIR=/usr/include, компилируем и копируем результат в нужную нам папку.

skype:~/celliax/skypiax_stuff/build# make 
skype:~/celliax/skypiax_stuff/build# cp chan_skypiax.so /usr/lib/asterisk/modules/ && cp skypiax.conf /etc/asterisk/

На этом установка завершена, можно переходить к более увлекательному этапу настройки.

Настраиваем skype клиента

Для запуска skype я использован возможность X11 forwarding openssh сервера и клиента, присоединившись с десктоп машины на skype сервер с параметром -X:

ssh -X root@skypeserver.local 

Для своей работы скайп захочет звуковую карту, для подобных целей в alsa предусмотрен драйвер snd-dummy, загрузим его:

modprobe snd-dummy

После этого запускаем в терминале скайп, и если все работает правильно - он должен показать лицензионное соглашение и свой интерфейс на рабочем столе. Скайп позволяет использовать одно и тоже подключение из нескольких мест (чем, кстати, выгодно отличается от SIP), но тем не менее я рекомендую завести отдельную запись, как минимум для удобства тестирования. Запустив скайп соглашаемся с лицензией и вводим данные учетной записи. Если все настроено правильно - skype должен зарегистрироваться в сети. Перейдя в настройки отключаем уведомления (Notifications → Enable Event). Теперь самое важное - в пункте Sound Devices указываем устройство Dummy (hw:Dummy,0). В меню Advanced стоит отключить проверку обновлений, а в меню Video Devices - поддержку видео. После этого skype клиент должен без проблем совершать или принимать звонки, правда слышно ничего не будет, так как карта виртуальная. Не закрываем клиент (он нам скоро потребуется) и переходим к настройке Asterisk.

Настраиваем Asterisk

  1. Подключаемся к серверу с включенным X11 forwarding
    Desktop:~$ ssh -X root@skypeserver.local
  2. Для того, чтобы астериск смог взаимодействовать с запущенным skype клиентом нам потребуется значение переменной DISPLAY
    skype:~# echo $DISPLAY

    В моем случае это localhost:11.0

  3. Параметры skype транков (их может много) задаются в /etc/asterisk/skypiax.conf. По умолчанию там уже заданы 2 транка, закомментируем их. Параметры для моего транка выглядят так:
    [skypeclient]
    language=en ; default
    context=default ; incoming context
    extension=600 ; forward calls to default asterisk echo test
    skype=yes ; legacy setting
    X11_display=localhost:11.0 ; value from $DISPLAY
    tcp_cli_port=11234 ; 2 random pots
    tcp_srv_port=11235 ;
    skype_user=skypet123 ; skype nickname
    playback_boost=0 ; volume boost for playback
    capture_boost=0 ; ... and recording

    В данной конфигурации я указал X11_display из пункта 2, для того, чтобы asterisk смог соединиться с запущенным клиентом. Extension=600 обозночает что входящие звонки в будут перенаправлены в extension 600, который по умолчанию (см. extensions.conf) перенаправляется на эхо тест задержки. Это позволит нам убедиться что все работает правильно и заодно определить на слух задержу сигнала.

  4. Запускаем астериск в режиме консоли
    skype:~# /etc/init.d/asterisk stop; asterisk -c -vvv -ddd

    . Если все настроено верно - скайп должен показать уведомление о том, что другая программа пытается к нему подключиться. Обязательно отмечаем галку “Remember this selection” и разрешаем подключение.

После этого пробуем позвонить на эту скайп запись. Если все настроено верно - вы должны слышать эхо-тест астериска. Кстати, распознавание DTMF прекрасно работает, что позволяет создавать IVR на базе данного решения.

Запуск скайп в виртуальном X сервере

Для того, чтобы skype работал в виртуальном X11 окружении установим xvfb - Virtual Framebuffer 'fake' X server.

skype:~# apt-get install xvfb

Данный сервер позволяет работать X11 приложением локально, не требуя видео карты и потребляя сравнительно немного ресурсов. Для запуска скайпа создадим скрипт skypestart.sh:

#!/bin/sh 

# loading sound driver
/sbin/modprobe snd_dummy
# setting DISPLAY
export DISPLAY=:1
# starting virtual framebuffer X-Server
nohup /usr/bin/Xvfb ${DISPLAY} -screen scrn 300x600x8 >/dev/null &
echo <skypenick> <password>|/usr/bin/skype --pipelogin &
# restarting asterisk
sleep 5
/etc/init.d/asterisk restart

заменив <skypenick> <password> на данные skype записи. Этот скрипт загружает snd_dummy, запускает X-server и загружает скайп. Перезагрузка астериска требуется для того, чтобы он установил связь с клиентом.

Скрипт можно добавить в крон, например так:

@reboot /root/skypestart.sh

Или сделать на его основе полноценный init.d сценарий. Также возможна запуска более чем одной копии Skype. Для этого надо скопировать $HOME/.Skype/ в соответствующие поддиректории, и переопределив HOME и DISPLAY запустить для каждой из копий свой xvfb сервер и клиента, добавив соответствующие записи в конфигурацию asterisk.

Redirect звонков skype на SIP phone

Для тестирования работы skype c SIP телефоном я использовал ATA adapter Linksys (подойдет и любой sofpthone, например - Ekiga), подключив его к Asterisk. Для этого создадим запись в файле /etc/asterisk/sip.conf

; linksys ata adapter, skype testing
[sipphone]
context=default
type=friend ; ATA login
secret=f.ck ; ATA password
host=dynamic ; allow to register

Перезапустим Asterisk и настроем АТА адаптер используя Asterisk в качестве сервера. Для проверки наберем на SIP телефоне 600#, вы должны услышать эхо тест.

Если все работаем - настроим перенаправление. Для этого в /etc/asterisk/skypiax.conf заменим строчку extension=600 на, например extensions=555. В файле /etc/asterisk/extensions.conf (секция [default]) добавим

exten => 555,1,Dial(SIP/sipphone);

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

Вызов skype абонентов

Для того, чтобы с sipphone вызывать skype пользователей - добавим соответствующие записи в /etc/asterisk/extensions.conf (секция default), например

[default]
exten => 555,1,Dial(SIP/sipphone);
exten => 556,1,Dial(Skypiax/skypeclient/echo123);
exten => 557,1,Dial(Skypiax/skypeclient/drugdiler);
exten => 558,1,Dial(Skypiax/skypeclient/advokat);

и в консоли Asterisk наберем dialplan reload. Теперь набрав на sipphone 556 asterisk соединет нас с Skype call testing service. Что и требовалось )

Заключение

Для использования решения в production желательно сделать некоторые доработки, так я планирую сделать скрипты для пуска/остановки клиентов, создать rootless окружение для всего этого, интегрировать все это хозяйство с monit и перенести все в Xen domU. Тем не менее уже сейчас понятно что решение работоспособно и работает достаточно неплохо. Я буду рад дельным замечаниям и комментариям на эту тему.

Alex Samorukov