- PVSM.RU - https://www.pvsm.ru -
Однажды заказчик, которому я разворачивал офисную телефонию, спросил меня: «А можно нашим сотрудникам поставить на телефоны SIP клиенты, чтобы их разговоры с клиентами проходили через офис, попадали в CRM и записывались?»
Мысль заказчика понятна: Почему бы просто не поставить софтофон на мобильник и не настроить его на свой сервер?
Но есть несколько причин, почему это работает откровенно плохо:
Софтофону придётся разрешить постоянную фоновую работу, иначе нет входящих звонков. Но это очень быстро «сушит» батарею. Конечно же, я знаю про схему linphone + Flexisip, но если честно, я тупо не смог нормально собрать Flexisip.;)
Проблемы с удержанием сессии. SIP протокол не любит клиентов со внезапно меняющимися IP адресами. А мобильный телефон делает это довольно часто.
SIP за NAT это отдельный вид мазохизма. Особенно весело, когда звук динамически пропадает на любой из сторон при каждом отдельном вызове.;)
Светить SIP сервер в мир без SBC — не хорошо. Жирный пароль не спасёт от постоянных сканов и брутфорса ботами, а fail2ban вместо защитника порой выполняет функцию вредителя.
В последний раз при необходимости экстренно обеспечить связь с офисом я второпях пустил SIP через OpenVPN. Но туннель регулярно отваливался, а в некоторых случаях вообще отказывался работать через мобильный интернет.
В какой‑то момент я подумал: Почему, чёрт возьми, мобильный софтофон не работает так же просто, как это делают мессенджеры?
Так родился открытый проект Sip2Go [1].

Суть задумки была в том, чтобы избавиться сразу от всех проблем SIPа на смартфоне, заставив голосовую связь работать точно так же, как она работает у мессенджеров.
В Sip2Go телефон вообще не является SIP‑клиентом.
Схема выглядит иначе:
┌──────────────┐
│ Android │
│ SIP2GO App │
└──────┬───────┘
│
│ WSS / TLS
│
▼
┌──────────────────┐
│ SIP2GO Gateway │
│ │
│ WebSocket │
│ ↕ │
│ SIP / RTP │
└────────┬─────────┘
│
│ SIP
▼
┌──────────────────┐
│ PBX / Asterisk │
└──────────────────┘
Получилось довольно изящно:
SIP остаётся там, где он гарантированно работает, а мобильное устройство разговаривает с сервером обычным защищённым WebSocket‑соединением. Шлюз может подключаться к АТС как обычный SIP клиент, не требуя никаких специфических настроек на её стороне, что кардинально упрощает интеграцию этого софта в уже рабочую систему.

Мне нужен был транспорт, который:
нормально работает сквозь NAT;
обходит кривые хелперы, типа SIP ALG, которые частенько вредят.
выглядит как обычный https;
позволяет стабильно удерживать двустороннее соединение;
одинаково хорошо подходит для управляющих сообщений и передачи аудио.
Работает сквозь любой веб сервер в режиме реверс прокси (хоть через cloudflare).
WebSocket здесь оказался практически безальтернативным выбором.
Телефон устанавливает WSS‑соединение с Sip2Go Gateway, после чего через него идут управляющие сообщения и аудио. При этом серверная часть продолжает работать с обычной SIP‑инфраструктурой. А это залог того, что для шлюза нет принципиальной разницы, к какой именно АТС его подключат: будь то условный FreePBX, проприетарная коробочка с лампочками или вовсе SIP провайдер с неизвестно чем под капотом.
Допустим, пользователь хочет позвонить с мобильного приложения.
Android отправляет запрос через WebSocket на gateway.
Gateway уже сам взаимодействует с SIP‑сервером:
Android
│
│ "позвонить на 123"
▼
SIP2GO Gateway
│
│ SIP INVITE
▼
PBX
│
▼
SIP абонент
В обратную сторону всё работает почти так же, но с небольшим нюансом.
Когда на соответствующий номер приходит входящий звонок, PBX передаёт его gateway (как своему абоненту), а дальше немного магии: шлюз отправляет серверу прогресс звонка, а сам в это время отправляет мобильному клиенту FCM (push пробуждение) и ждёт, когда подключится к шлюзу.
При этом мобильный клиент не обязан постоянно висеть на сессии и ждать звонка. Шлюз будет «искать» его и держать статус RINGING до тех пор, пока клиент не примет звонок или не наступит таймаут. Тут практически как у мобильных операторов.:)
На стороне PBX мы остаёмся в привычном мире SIP, работая на кодеках PCMU/PCMA (ulaw/alaw).
На стороне мобильного устройства аудиопоток кодируется в Opus и бегает через WebSocket.
Gateway выступает посредником и транскодером между этими двумя мирами:
SIP / RTP
│
PCMU/PCMA
|
▼
┌─────────────────┐
│ Gateway │
│ │
│ audio bridge │
│ │
└────────┬────────┘
│
Opus
│
▼
Android
В результате мобильному приложению не нужно реализовывать весь зоопарк SIP/RTP/NAT traversal, который обычно сопровождает VoIP‑клиент. Ему достаточно поддерживать собственный небольшой протокол общения с gateway.
Разрыв соединения может случиться по самым разным причинам, начиная со смены IP адреса, при переключении между сетями и заканчивая полным закрытием приложения.
Например, если соединение было потеряно в момент, когда звонок уже поступил, приложение не должно считать, что ничего не происходило.
Даже в сценарии рестарта приложение, как только оно снова подключится к шлюзу, тот сообщит о наличии активной сессии и попытается её возобновить, не роняя вызов.
Для этого gateway и клиент умеют синхронизировать состояние активного вызова после повторного подключения. Время, отведённое на попытки восстановления соединения настраиваются на стороне шлюза.
Если же восстановить связь вовремя не удалось — шлюз отправляет АТС грустный Bye.;)
PBX продолжает заниматься своей работой. Для неё Sip2Go Gateway выглядит как ещё один SIP endpoint. Можно использовать существующую инфраструктуру телефонии, а мобильный доступ добавляется отдельным слоем. Это позволяет использовать Sip2Go вместе с существующей телефонией, не превращая PBX в экспериментальную лабораторию.
Правда, тут имеется маленький нюанс: я не стал реализовывать множественную регистрацию. То есть, если работать через регистрацию — получится прокинуть только один endpoint. А вот если нужно запихать сразу много, то нужно подключить шлюз в режиме транка (авторизация по IP) и маршрутизировать в его сторону вызовы на номера всех его подопечных. Наиболее удобный вариант в данном случае — выделить мобильным клиентам свой внутренний пул (например 7XXX)

Понимая, кто будет пользоваться этим приложением я решил, что нужно максимально упростить его настройку.
В голову мысль: а почему бы не сделать настройку как у eSIM? Отсканил одноразовый QR, либо кликнул на одноразовую ссылку и ты в сети!
Реализация такого подхода моментально избавила меня от необходимости лишнего сопровождения пользователей.
Одним из первых пользователей Sip2Go в реальных условиях стал руководитель предприятия, которое я обслуживаю.
До этого мы с ним использовали схему с SIP‑клиентом поверх OpenVPN, и периодическая диагностика глюков этой связки меня однажды прилично достала.
Когда появилась первая рабочая версия Sip2Go, я предложил ему стать добровольным испытателем.
Тестирование получилось особенно значимым, поскольку в данном случае удалось испытать работу софта за пределами страны, где был расположен сервер.
Честно говоря, я даже не знаю, кто из нас был больше впечатлён результатом: Шеф, который внезапно получил простое решение наболевшей проблемы или я, который офигел от положительных отзывов весьма требовательного пользователя.:)
Sip2Go состоит из двух основных частей:
Sip2Go Gateway [2]
Исходный код открыт, Шлюз можно развернуть на собственной инфраструктуре и использовать собственные Firebase credentials для push‑уведомлений. Также, придётся собрать и приложение, добавив в него свои ключи от firebase. Инструкция по установке имеется тут [4] и на репозитории проекта.

Заранее поясню, что это за настройка "Push relay URL" и "Push relay API key".
Данная настройка предназначена для коммерческих клиентов, которые пользуются официальной сборкой приложения с Google Play с привязкой к моему аккаунту Firebase. Она используется исключительно для того, чтобы не хранить приватный токен на серверах клиентов и не является обязательной, поскольку при добавлении своего токена в .env шлюз сможет отправлять FCM без всяких дополнительных релеев. Более подробная информация об этом находится тут [5].
Абсолютно весь функционал программы, без каких либо ограничений доступен бесплатно, при условии самостоятельной сборки приложения с привязкой к своему аккаунту Firebase.
Увы, у меня нет аккаунта разработчика для apple. Собственно, как и нет устройств, на которых можно тестировать софт.
Впрочем, я был бы искренне рад, если бы за это взялся кто‑то другой.:)
Автор: MegaCrash
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/softfon/458372
Ссылки в тексте:
[1] Sip2Go: https://s2g.uz
[2] Sip2Go Gateway: https://github.com/ibuben/sip2go-gateway
[3] Sip2Go Android Client : https://github.com/ibuben/sip2go-Android-App
[4] тут: https://s2g.uz/docs?lang=ru
[5] тут: https://s2g.uz/saas?lang=ru
[6] Источник: https://habr.com/ru/articles/1084386/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1084386
Нажмите здесь для печати.