Pull to refresh

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

Reading time 5 min
Views 52K
Доброго времени суток всем!

Я уже писал о своем опыте работы с 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 патчили и компиляли по этому мануалу
После того, как мы этого добились, мы начали тестировать.

В процессе тестирования мы обнаружили:

  1. «Белый шум» при звонке
  2. Тишина до 10 секунд при входящем звонке.
  3. Входящий звонок скидывал исходящий.


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

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

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


Но появились следующие проблемы:

  1. Астериск падает при входящем звонке на определении RTP
  2. Тишина до 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-switch

Freeswitch


Плюсы:
  • Работает
  • Активно разрабатывается
  • Ничего не ломается в новых релизах

Минусы:
  • Нет возможности сделать подобный колцентр, как в asterisk с бабой-роботом по таймауту


Итог


SIP стал работать стабильно. Операторы счастливы. Текущая связка Freeswitch+JSSIP обрабатывает ~10k звонков в сутки и до 15k в часы-пик.

PS


Кому интересно могу написать о том, как мы настраивали Freeswitch с интеграцией с MySQL, кол-центром, записью звонков и делали его отказоустойчивым.
Tags:
Hubs:
+31
Comments 20
Comments Comments 20

Articles