WebRTC або як я навчив нашу CRM дзвонити на телефони
Компанія, в якій мені довелося працювати, займається продажем інтернет-послуг. Щоранку чергова зміна розбирає загальний стек заявок, що накопичилися, і починається обдзвон клієнтів для уточнення замовлень. Протягом дня оператори ще приймають вхідні дзвінки. До початку моєї витівки вони використовували для дзвінків такий десктопний SIP-клієнт:

Але найголовнішим траблом була відсутність інтеграції з нашою web-системою та базою даних. Такі, здавалося б прості завдання, як відкриття картки клієнта на вхідний дзвінок, збереження статистики дзвінків для кожного із співробітників та моніторинг їхньої активності з адміністративного web інтерфейсу — все це дуже складно зробити з десктопним софтфоном, навіть у тому випадку він має відповідні можливості інтеграції з браузером, наприклад, за допомогою плагінів.
Виникла ідея об'єднати в одній системі та базі даних всю внутрішню роботу та дзвінки. Я довго допилював нашу CRM з функцією вбудованої дзвонилки із записом розмов. Для реалізації дзвінків розглянув ряд технологій і дійшов висновку, що їх не так вже й багато. Знайшлася пара опенсорсних і комерційних реалізацій, а також кілька SAAS сервісів, які не підходили через внутрішні політики безпеки — обробляти дзвінки через власний сервер.
Спочатку намагався використовувати sipml5:
Так виглядають SIP запити на стороні браузера у консолі налагодження:

В результаті почав тестувати Web Call Server. Це не SAAS і дозволяє обробляти дзвінки через свій сервер, що в даному випадку потрібно:

За функціями приблизно те саме, що і у sipml5, ті ж WebRTC дзвінки на SIP і назад. Є ще підтримка Flash, але в ній не було необхідності, тому що всі оператори використовують переважно Chrome і Firefoxбраузер, а тим, хто використовує IE, довелося пересісти на більш "правильні" браузери.
У навантаження дається софтфон на JS з відкритим кодом, який можна перемалювати і адаптувати для web-сторінки.
Основна відмінність від sipml5 – це взаємодія з сервером через API, а не через SIP over Websockets. Тобто. SIP стека на стороні браузера немає. Він розташований лише за сервера. Це полегшило завдання front-end розробнику, т.к. SIP стек на стороні браузера кидав його в сум'яття, а при роботі з Javascript API і CSS стало можливим зосередитися на інтерфейсній частині.
Отже, як я це все впроваджував.
1. Взяв такий сервер на Amazon EC2: Пам'яті і дискового простору багато не потрібно. Хіба що для ліг. А обчислювальні потужності CPU у таких завданнях можуть бути важливими, тому взяв не найслабший інстанс.

2. Підняв Apache для web-інтерфейсу, встановив та запустив WCS сервер.



Виявилося, що в API є для цього спеціальна функція loginByToken:
Для того щоб розібратися, як ця функція працює, довелося добре постаратися. За допомогою документації та прикладів вдалося з'ясувати, що все це працює приблизно так:

1) При створенні токена на стороні CRM використовується алгоритм шифрування AES, яким зашифровується рядок, що включає SIP логін та пароль користувача, а також іншу необхідну інформацію.
Ключ шифрування відомий тільки нашому серверу, де розгорнуто CRM, а також WCS серверу. Крім того, термін дії токена визначається спеціальним атрибутом expires для того, щоб не було можливості ним повторно скористатися. Криптування токена відбувається в AES CTR mode. Нижче приклад c openssl, в якомувідбувається генерація шифрованого токена з передачею SIP пароля:
В результаті отримав щось на кшталт:
У цьому випадку процедура автоматичної реєстрації по токену розпочнеться відразу після перезавантаження сторінки. 2 і 3) loginByToken і розшифровка.
На стороні сервера в конфізі прописані ключі шифрування для AES:
Таким чином, коли приходить токен з префіксом CRM: для його розшифровки використовується відповідний ключ.
В результаті розшифровки WCS сервер отримує зашифрований раніше рядок:
і з цього рядка XML бере всі дані необхідні для SIP реєстрації.
3) Як тільки сервер розшифрував дані, він посилає SIP REGISTER запит на SIP і на 401 відповідь віддає вже нормальну Digest аутентифікацію з використанням розшифрованих на попередньому етапі SIP логіну та паролю.
Деякі результати впровадження браузерних дзвінків:
1. Дзвінки робляться з сайту і приймаються на сайті, де всі дії фіксуються в системі.
2. Стало можливим прослуховування записаних розмов, що допомагає вирішувати конфліктні ситуації з клієнтами та розбіжності між співробітниками. Це важливо для нашого розподіленого офісу.
3. Кількість прийнятих дзвінків збільшилася приблизно 20%. Стало зрозуміло, що оператори не завжди піднімали слухавку під час дзвінка клієнта. На даний момент можна сказати, що все працює, як задумано. Проблемні ситуації вдалося вирішити без серйозного занурення у SIP матч.
З недоліків можна назвати неможливість встановлення під Windows. До речі, з установкою під Linux та інтеграцією теж довелося повозитися і, схоже, що подужає її лише просунутий користувач/розробник.
WebRTC аудіо дзвінки працюють стабільно і без будь-яких додаткових браузернихплагінів, типу Flash Player. Тож можна сказати, що мені вдалося реалізувати задуману інтеграцію і два тижні роботи було витрачено недаремно.
Хардкорна конфа за С++. Ми запрошуємо лише профі.