SIP через WebRTC на продакшне. Как мы к этому шли и какие проблемы решали

Доброго времени суток всем! Я уже писал о своем опыте работы с WebRTC тут, но учитывая то, что в последнее время всё больше статей на эту тему появляется на хабре и то, что я давно хотел написать о том, как мы добились стабильной работы SIP телефонии через WebRTC на продашне, я решил написать через что мы прошли.

А прошли мы через многое: боль, панику, истерики, кучу матов и пожелания добра мейнтейнерам.Сейчас же это всё в прошлом. Мы избавились от всех костылей, которые мы делали, и сделали так, чтобы операторы звонили и всё работало стабильно.В статье, я как можно подробнее описал все проблемы, с которыми мы сталкивались, используя как можно меньше кода и конфигов.

Кому интересно, прошу под кат.

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

На первоначальном этапе мы выбрали:

SIPml5 — как фронтенд либу Asterisk — как бекенд Google Chrome — как браузер. где всё это должно работать. За весь путь мы использовали:

Asterisk и SIPml Asterisk + Webrtc2sip и SIPml Freeswitch + SIPml Freeswitch + JSSIP Не много о софтах: Asterisk — всем известный soft-switch. Делается умельцами из Digium Freeswitch — Soft-switch. Oдин из конкурентов Asterisk SIPml5 — позицианируют себя как первый HTML5 SIP клиент. Javascript либа для работы с SIP. JSSIP — легковесная Javascript либа для работы с SIP. WebRTC2SIP — SIP и медиа гейтвей asterisk + sipml Начало пути. Нам надо было добится рабочей схемы и позвонить с браузера себе на мобильный.Asterisk патчили и компиляли по этому мануалуПосле того, как мы этого добились, мы начали тестировать.В процессе тестирования мы обнаружили:

«Белый шум» при звонке Тишина до 10 секунд при входящем звонке. Входящий звонок скидывал исходящий. 1. «Белый шум» был исправлен с помощью этого патча2. Проблему со скидыванием звонка удалось решить, с помощью настройки пользователя на Asterisk. Был выставлен лимит 1 звонок на пользователя.3. Проблему с 10 секундной тишиной решили исправить, обновив Asterisk до версии 1.6.

И вот мы уже на 1.6 астериске. После беглого тестирования стало понятно:

«Белого шума» нет Нативная поддержка вебсокетов Но появились следующие проблемы:

Астериск падает при входящем звонке на определении RTP Тишина до 10 секунд осталась. Проблему с тишиной удалось решить тем, что мы отказались от STUN в SIPml5. Ситуация стала лучше, но не исчезла полностью.Решили попробовать WebRTC2SIP, как советовали мейнтейнеры SIPml5.

asterisk + webrtc2sip + sipml На этом этапе у нас следующая ситуация:

Нет старых багов Asterisk не падает Тишина исчезла. НО! Появилась проблема в том, что WebRTC2SIP не готов для продакшна. Он постоянно падал с разной периодичностью.Судя по багрепорту в треккере о проблеме знали уже полгода, когда мы стали его использовать. Поняв, что от мейнтейнеров ничего не добится, стали проблему решать сами.

// А тем временем проект уже в продакшне.

Потратив неделю и так не решив проблему, сделали рестартер webrtc2sip и стали смотреть в сторону Freeswitch.

freeswitch + sipml В сторону Freeswitch я смотрел еще тогда, когда вышла Бета версия 1.4 с поддержкой WebRTC.

На этом этапе стало понятно, что ни от Asterisk, ни от Doubango Telecom помощи ждать не стоит и нужно как-то решать проблему самим.

На начальных этапах работы с Freeswitch очень выносят мозг xml конфиги, но когда привыкаешь к ним, то жить без них не можешь.После того, как мы добились от него работы в условиях, приближенных к продакшну, протестировали его, и поняв, что багов нет, стали тестировать дальше на продакшне, сохранив возможность перейти обратно на связку Asterisk + WebRTC2SIP

После миграции проблемы со стороны софтсвитча исчезли. Появились проблемы со стороны SIPml:

Если позвонить и скинуть трубку, то sipml будет думать, что ему также звонят и будет пробовать взять уже мертвый звонок. Звонок длился не больше 2х минут. Сделали несколько костылей для того, чтобы эти проблемы нам не мешали и решили перейти на JSSIP. О JSSIP знали уже около месяца. А еще тут было много ненависти к Doubango и их продуктам и огромное желание избавится от их продуктов.

Проверив все на tryit.jssip.net и поняв, что проблем нет, через три дня, после миграции на JSSIP, у нас SIP стал работать стабильно и без багов.

Резюме Вот такая история получилась. А теперь мое личное мнение по каждому софту.SIPml Плюсы:

Поддерживает трансфер Минусы:

Очень огромная. Минифицированный js файл весит > 1 Mb Нет полной документации. Много чего приходилось выискивать по интернетам. Больше заточена под WebRTC2sip Много кода Пример подключения к серверу // Взято из документации SIPml.init ( function (e){ var stack = new SIPml.Stack ({realm: 'example.org', impi: 'bob', impu: 'sip: bob@example.org', password: 'mysecret', events_listener: { events: 'started', listener: function (e){ var callSession = stack.newSession ('call-audiovideo', { video_local: document.getElementById ('video-local'), video_remote: document.getElementById ('video-remote'), audio_remote: document.getElementById ('audio-remote') }); callSession.call ('alice'); } } }); stack.start (); } ); Пример звонка // Взято из документации var callSession; var eventsListener = function (e){ console.info ('session event = ' + e.type); } var makeCall = function (){ callSession = sipStack.newSession ('call-audiovideo', { video_local: document.getElementById ('video-local'), video_remote: document.getElementById ('video-remote'), audio_remote: document.getElementById ('audio-remote'), events_listener: { events: '*', listener: eventsListener } // optional: '*' means all events }); callSession.call ('johndoe'); } JSSIP Плюсы:

Легковесная (~130kb) Отличная документация на сайте разработчика Отлично работает с Freeswitch (по идее и с Asterisk и другими, но тут я уже не проверял) Отличное API Минусы:

Не умеет делать трансфер звонка Пример подключения к серверу: // Из документации var configuration = { 'ws_servers': 'ws://sip-ws.example.com', 'uri': 'sip: alice@example.com', 'password': 'superpassword' }; var coolPhone = new JsSIP.UA (configuration);

Пример звонка // из документации var selfView = document.getElementById ('my-video'); var remoteView = document.getElementById ('peer-video');

// Register callbacks to desired call events var eventHandlers = { 'progress': function (e){ /* Your code here */ }, 'failed': function (e){ /* Your code here */ }, 'started': function (e){ var rtcSession = e.sender;

// Attach local stream to selfView if (rtcSession.getLocalStreams ().length > 0) { selfView.src = window.URL.createObjectURL (rtcSession.getLocalStreams ()[0]); }

// Attach remote stream to remoteView if (rtcSession.getRemoteStreams ().length > 0) { remoteView.src = window.URL.createObjectURL (rtcSession.getRemoteStreams ()[0]); } }, 'ended': function (e){ /* Your code here */ } };

var options = { 'eventHandlers': eventHandlers, 'extraHeaders': [ 'X-Foo: foo', 'X-Bar: bar' ], 'mediaConstraints': {'audio': true, 'video': true} };

coolPhone.call ('sip: bob@example.com', options); Webrtc2sip Плюсы:

Помог решить проблему с Asterisk Минусы: Не стабильный Стабильность наладили спустя год. Asterisk Как я понял, умельцы в одном релизе чинят, в другом ломают.На версии 1.7 SIP через WebRTC работать у меня перестал.

Хабраюзер Ovoshlook отлично и подробно описал проблему:

Умельцы уже пропатчили. сейчас всеобщая и всепоглащающая проблема в другом- когда астериск делает бриджинг он посылает инвайт с транспортом AVP, и если вызываемый абонент сидит на вебфоне — он соответственно ожидает транспорт AVPF и шифрование. Как следствие при звонке вызываемый будет отвечать 603 ошибкой c комментарием failed to get local sdp.В общем и целом — при исходящх астериск не следит за тем с какого устройства на нем сидит клиент. Как вариант можно проксировать и преобразовывать через openSIPS или Kamailio, но это уже совсем другая тема.

В итоге всё это надоело и мы выбрали Freeswitch как soft-switchFreeswitch Плюсы:

Работает Активно разрабатывается Ничего не ломается в новых релизах Минусы: Нет возможности сделать подобный колцентр, как в asterisk с бабой-роботом по таймауту Итог SIP стал работать стабильно. Операторы счастливы. Текущая связка Freeswitch+JSSIP обрабатывает ~10k звонков в сутки и до 15k в часы-пик.PS Кому интересно могу написать о том, как мы настраивали Freeswitch с интеграцией с MySQL, кол-центром, записью звонков и делали его отказоустойчивым.

© Habrahabr.ru