Доброго времени суток всем!
Я уже писал о своем опыте работы с 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 очень выносят
После того, как мы добились от него работы в условиях, приближенных к продакшну, протестировали его, и поняв, что багов нет, стали тестировать дальше на продакшне, сохранив возможность перейти обратно на связку 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, кол-центром, записью звонков и делали его отказоустойчивым.
Автор: Gen1us2k