- PVSM.RU - https://www.pvsm.ru -

sip2go: Альтернатива SIP клиентам для Android

Однажды заказчик, которому я разворачивал офисную телефонию, спросил меня: «А можно нашим сотрудникам поставить на телефоны SIP клиенты, чтобы их разговоры с клиентами проходили через офис, попадали в CRM и записывались?»

Мысль заказчика понятна: Почему бы просто не поставить софтофон на мобильник и не настроить его на свой сервер?

Но есть несколько причин, почему это работает откровенно плохо:

  • Софтофону придётся разрешить постоянную фоновую работу, иначе нет входящих звонков. Но это очень быстро «сушит» батарею. Конечно же, я знаю про схему linphone + Flexisip, но если честно, я тупо не смог нормально собрать Flexisip.;)

  • Проблемы с удержанием сессии. SIP протокол не любит клиентов со внезапно меняющимися IP адресами. А мобильный телефон делает это довольно часто.

  • SIP за NAT это отдельный вид мазохизма. Особенно весело, когда звук динамически пропадает на любой из сторон при каждом отдельном вызове.;)

  • Светить SIP сервер в мир без SBC — не хорошо. Жирный пароль не спасёт от постоянных сканов и брутфорса ботами, а fail2ban вместо защитника порой выполняет функцию вредителя.

В последний раз при необходимости экстренно обеспечить связь с офисом я второпях пустил SIP через OpenVPN. Но туннель регулярно отваливался, а в некоторых случаях вообще отказывался работать через мобильный интернет.

В какой‑то момент я подумал: Почему, чёрт возьми, мобильный софтофон не работает так же просто, как это делают мессенджеры?

Так родился открытый проект Sip2Go [1].

sip2go: Альтернатива SIP клиентам для Android - 1

Идея

Суть задумки была в том, чтобы избавиться сразу от всех проблем SIPа на смартфоне, заставив голосовую связь работать точно так же, как она работает у мессенджеров.

В Sip2Go телефон вообще не является SIP‑клиентом.

Схема выглядит иначе:

┌──────────────┐
│   Android    │
│  SIP2GO App  │
└──────┬───────┘
       │
       │ WSS / TLS
       │
       ▼
┌──────────────────┐
│ SIP2GO Gateway   │
│                  │
│  WebSocket       │
│       ↕          │
│  SIP / RTP       │
└────────┬─────────┘
         │
         │ SIP
         ▼
┌──────────────────┐
│  PBX / Asterisk  │
└──────────────────┘

Получилось довольно изящно:

SIP остаётся там, где он гарантированно работает, а мобильное устройство разговаривает с сервером обычным защищённым WebSocket‑соединением. Шлюз может подключаться к АТС как обычный SIP клиент, не требуя никаких специфических настроек на её стороне, что кардинально упрощает интеграцию этого софта в уже рабочую систему.

sip2go: Альтернатива SIP клиентам для Android - 2

Почему именно WebSocket

Мне нужен был транспорт, который:

  • нормально работает сквозь 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 до тех пор, пока клиент не примет звонок или не наступит таймаут. Тут практически как у мобильных операторов.:)


Что там с RTP?

На стороне 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.;)


А что происходит с SIP?

PBX продолжает заниматься своей работой. Для неё Sip2Go Gateway выглядит как ещё один SIP endpoint. Можно использовать существующую инфраструктуру телефонии, а мобильный доступ добавляется отдельным слоем. Это позволяет использовать Sip2Go вместе с существующей телефонией, не превращая PBX в экспериментальную лабораторию.

Правда, тут имеется маленький нюанс: я не стал реализовывать множественную регистрацию. То есть, если работать через регистрацию — получится прокинуть только один endpoint. А вот если нужно запихать сразу много, то нужно подключить шлюз в режиме транка (авторизация по IP) и маршрутизировать в его сторону вызовы на номера всех его подопечных. Наиболее удобный вариант в данном случае — выделить мобильным клиентам свой внутренний пул (например 7XXX)

sip2go: Альтернатива SIP клиентам для Android - 3

Лёгкое подключени

Понимая, кто будет пользоваться этим приложением я решил, что нужно максимально упростить его настройку.

В голову мысль: а почему бы не сделать настройку как у eSIM? Отсканил одноразовый QR, либо кликнул на одноразовую ссылку и ты в сети!

Реализация такого подхода моментально избавила меня от необходимости лишнего сопровождения пользователей.


Боевые испытания

Одним из первых пользователей Sip2Go в реальных условиях стал руководитель предприятия, которое я обслуживаю.

До этого мы с ним использовали схему с SIP‑клиентом поверх OpenVPN, и периодическая диагностика глюков этой связки меня однажды прилично достала.

Когда появилась первая рабочая версия Sip2Go, я предложил ему стать добровольным испытателем.

Тестирование получилось особенно значимым, поскольку в данном случае удалось испытать работу софта за пределами страны, где был расположен сервер.

Честно говоря, я даже не знаю, кто из нас был больше впечатлён результатом: Шеф, который внезапно получил простое решение наболевшей проблемы или я, который офигел от положительных отзывов весьма требовательного пользователя.:)


Open source

Sip2Go состоит из двух основных частей:

Исходный код открыт, Шлюз можно развернуть на собственной инфраструктуре и использовать собственные Firebase credentials для push‑уведомлений. Также, придётся собрать и приложение, добавив в него свои ключи от firebase. Инструкция по установке имеется тут [4] и на репозитории проекта.


sip2go: Альтернатива SIP клиентам для Android - 4

Заранее поясню, что это за настройка "Push relay URL" и "Push relay API key".

Данная настройка предназначена для коммерческих клиентов, которые пользуются официальной сборкой приложения с Google Play с привязкой к моему аккаунту Firebase. Она используется исключительно для того, чтобы не хранить приватный токен на серверах клиентов и не является обязательной, поскольку при добавлении своего токена в .env шлюз сможет отправлять FCM без всяких дополнительных релеев. Более подробная информация об этом находится тут [5].

Абсолютно весь функционал программы, без каких либо ограничений доступен бесплатно, при условии самостоятельной сборки приложения с привязкой к своему аккаунту Firebase.


А где клиент под iOS?

Увы, у меня нет аккаунта разработчика для 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