ID Caller
ID Caller

В октябре прошлого года на Хабре вышла статья «Как я писал свою звонилку для видеозвонков» — автор под ником CEOCTO за несколько вечеров написал P2P-видеозвонилку на WebRTC, потому что его достали обрывающиеся созвоны в мессенджерах. Я прочитал, улыбнулся, полез смотреть исходники на GitHub — и на этом всё. Как обычно бывает с чужими pet-проектами: оценил, закрыл вкладку, забыл.

Я живу в Сербии четвёртый год, здесь у меня свой бизнес. Про ту статью вспомнил, когда понял, что не могу нормально дозвониться маме в Россию. Дело не в моём интернете и не в деньгах — часть привычных мессенджеров там просто заблокирована, а держать впн ради звонка сыну для человека, который не по этой части, задача не из простых: то отвалится в середине разговора, то придётся заново вспоминать, как его включить. Технически звонок возможен. Практически — каждый раз квест.


Jopa Call как учебный проект — и почему этого мало для звонка маме

CEOCTO в своей статье сразу оговаривается: JOPA Call — учебный проект, а не продакшен-сервис. Это видно по архитектуре: P2P на WebRTC, сигнальный сервер на Go, STUN/TURN для обхода NAT — ровно тот набор, которого хватает, чтобы за несколько вечеров с ChatGPT и Gemini получить рабочий видеозвонок между двумя Android-телефонами. Уже само по себе достижение для проекта такого масштаба.

Чтобы звонок так же просто работал у обычного, нетехнического человека на другом конце, этого мало по трём причинам. Android-only — а у мамы, как и у половины моих контактов, может быть iPhone. Сквозное шифрование — сам автор пишет, что оно в планах, а не в релизе. И главное — «за несколько вечеров» означает отсутствие тестов, обработки деградации сети и всего того скучного, что отличает pet-проект от сервиса, которому должен без объяснений поверить нетехнический человек за тысячи километров.

Что я знал такого, чего не было у автора Jopa Call

Опыт из телекома тоже не прошёл бесследно. Довольно долго я писал iOS-часть похожего сервиса изнутри коммерческой компании — видел, какие грабли обычно всплывают не в демо на два устройства, а в проде: обрыв сети посреди звонка, VoIP-push, который обязан синхронно поднять экран входящего звонка до истечения таймаута (иначе Apple банит приложение), деградация звука на слабом канале. Это и определило выбор технологии: Kotlin Multiplatform — весь продуктовый код общий для Android и iOS, платформенные модули — только тонкие адаптеры системных API (CallKit/PushKit на iOS, ConnectionService на Android). Не два отдельных приложения, а один продукт с двумя витринами.

Из этого же бэкграунда выросло решение, которое действительно нравится: групповые аудиозвонки на mesh-топологии — до 8 участников без выделенного медиасервера (SFU). Обычно групповые звонки такого масштаба тянут за собой инфраструктуру транскодирования и маршрутизации потоков; у нас каждый узел рассылает трафик сам, а нетривиальная часть — договориться, кто кому шлёт офер при подключении нового участника, и не перепутать это с таймаутами приглашений. Этой механике тоже достанется отдельная статья в цикле.

Mesh vs. SFU
Mesh vs. SFU

Коммерческие рельсы вместо вечера с ChatGPT

Тут стоит сказать честно: весь код в проекте написан ИИ. Но не в духе «вечер с ChatGPT», а по процессу, который я выстраивал как для коммерческой разработки. Каждая фича начинается с discovery-пакета: спецификация, критерии приёмки, разбивка на тикеты — и только потом код. TDD в буквальном смысле: сначала падающий тест отдельным коммитом, потом реализация, потом рефакторинг. Без критерия приёмки агент не имеет права придумывать поведение сам.

Ревью тоже не человеческое в привычном смысле — я использовал Claude Code и Codex как независимых ревьюеров друг для друга: то, что написал один harness, критикует и проверяет другой, с другой моделью под капотом. Процент автономности высокий — процентов 80 работы прошло через Ralph Loop, агентный цикл, который сам берёт следующую задачу из очереди, пишет тест, чинит, коммитит и переходит к следующей. Но не обошлось и без бебиситтинга: где-то агент упирался в архитектурную развилку, где-то зацикливался на неверной гипотезе, и приходилось вмешиваться руками. На всё это ушёл месяц и, если честно, я не берусь точно посчитать, сколько токенов — счёт шёл на миллионы.

TDD & Ralph Loop
TDD & Ralph Loop

Приватность как архитектурное ограничение, а не обещание

Приватность в проекте — это не строчка в политике, а следствие схемы данных. Сервер физически не может отдать то, чего не хранит: только identity (12-значный ID и Ed25519-ключ, сгенерированные на устройстве), связи между контактами по факту обмена QR-кодом и токены для пуш-уведомлений. Имена контактов, история звонков, содержимое медиа — только на устройстве, сам звонок P2P идёт по DTLS-SRTP напрямую. Удаления — физические, никаких soft-delete с меткой «удалено», которая формально скрыта, а по факту жива в бэкапе. Сигнальные данные, по которым в принципе можно восстановить детали звонка (token, sdp, candidate), не попадают ни в логи, ни в Sentry — это отдельно проверяется тестами на редакцию.

Для меня это не абстрактный принцип «мы за приватность», а прямое следствие изначальной задачи: сервис не должен становиться точкой, из которой можно узнать, кто кому и когда звонил. Так остаётся меньше того, что вообще можно спросить — ни у меня, ни у пользователя сервиса. Да и теоретически не должно быть вопросов по пользовательским данным у “товарищей”, их просто нет.

Data
Data

Что дальше

Сейчас в проекте не хватает одной вещи — устойчивого TURN-релея для российских сетей, где прямое P2P-соединение не проходит: провайдерский NAT, корпоративные файрволы, ограничения операторов. В ближайших планах — TURN-серверы в белых списках специально для звонков в Россию и вообще на ее территории, чтобы соединение устанавливалось даже в сетях, где всё остальное — квест. Пока это roadmap, не готовая фича. TURN конечно есть в проекте, но пока он не привязан к гео и находится в Германии (нормально доступен из РФ).

Сам сервис можно посмотреть на id-caller.online/ru — не буду превращать статью в рекламный лендинг, ссылка просто для тех, кому интересно попробовать или взглянуть на техническую сторону вблизи.

О чём будет этот цикл

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

Расследования и баги — самый читаемый жанр малой формы: почему видео на iOS зависало на протяжении месяца (спойлер: use-after-scope в чужой библиотеке), как сторож медиастатистики сам гасил камеру на 8-й секунде звонка, и как юнит-тесты остаются зелёными, пока фича не работает вовсе — потому что транспортный слой физически не был подключён к потребителю.

Тестирование — livelock из-за бесконечных delay-циклов в корутинах, зачем писать тесты для того, что не исполняется (CI-конфиги, docker-compose, метаданные сторов), и как автоматизировать полевой стенд из четырёх Android и iPhone без единого касания экрана.

Архитектура — уже упомянутый mesh для групповых звонков без SFU, протокол как source of truth между Kotlin- и Go-частями, звонки без номеров телефона и аккаунтов.

Платформенная специфика — правила iOS, за нарушение которых бывает больно (VoIP-push обязан синхронно поднять экран звонка до истечения таймаута), и почему Android-вендоры воюют с фоновыми звонками.

Инфраструктура и релиз — как получить TLS-сертификат для coturn без отдельного certbot, и как не сойти с ума, отправляя звонилку в Google Play.

Процесс — что должно лежать в репозитории, чтобы AI-агент разрабатывал фичи по спецификации, а не просто генерировал код.

Начну с истории про зависание видео на iOS — самого упорного бага за весь проект, из-за которого пришлось форкать чужую библиотеку.

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

Комментарии (7)


  1. dimbo
    19.08.2026 16:03

    Идея интересная, но боюсь, что как сервис в России высоко не взлетит. Как только приобретет заметную популярность - сразу придет РКН, ибо есть ФЗ №149, который вводит термин “организатор распространения информации в сети Интернет” и перечисляет обязанности этих самых организаторов. Прикрыться тем, что вы чего-то там не храните - не получится, ибо хранить всякие сведения - будет вашей обязанностью по закону.


    1. DevlabStudio Автор
      19.08.2026 16:03

      Справедливое замечание, и я не буду делать вид, что архитектура — это железная защита от 149-ФЗ. Мой расчёт тут скорее инженерный, чем юридический: сервер не ретранслирует и не хранит содержимое звонка — он только сводит два устройства для P2P-соединения, дальше SRTP-трафик идёт напрямую между ними, серверу физически нечего перехватывать и складывать в базу.

      Подпадает ли такая роль под определение «организатора распространения информации» — вопрос открытый, устоявшейся практики именно под P2P-архитектуру такого рода я не видел. Так что это не «прикрытие от РКН» в духе «мы просто скажем, что не храним», а сокращение поверхности заранее: даже если завтра прилетит требование что-то предоставить, содержимого звонков и истории у меня физически нет — отдавать нечего. Метаданные о том, кто с кем связан по коду, при этом на сервере есть, это я не скрываю.

      Дальше это действительно вопрос к юристам, а не к схеме БД — согласен, что риск реальный и его точно не стоит недооценивать.


  1. n0isy
    19.08.2026 16:03

    Приватность в проекте — это не строчка в политике, а следствие схемы данных.

    Маркер того, что статья написана через агента.

    ИИИИии коментарий выше - тоже.


    1. DevlabStudio Автор
      19.08.2026 16:03

      Так я и не скрываюсь :) Весь код приложения написан ИИ, об этом прямо в статье сказано, и про сам процесс будет отдельная часть цикла. Тексты тоже честно прогоняю через скил-редактора: черновик и фактура мои, а формулировки он местами причёсывает. Судя по всему, ту фразу как раз он и причесал. Допускаю еще места!

      Забавно, что вычислили меня по предложению, которое мне в статье нравится больше всего. Учту, что оно теперь считается маркером.

      Если по существу схемы данных есть что возразить или спросить - отвечу сам, без редактора. Могу даже с парой опечаток, для достоверности :)


      1. dimbo
        19.08.2026 16:03

        Не, нуачо… Мне тоже нужно будет запилить агента, чтобы Хабр комментил. И пусть агенты между собой болтают. Анекдот в тему.


        1. DevlabStudio Автор
          19.08.2026 16:03

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

          А комменты пока сам, тут живого общения жалко. Ну как сам... вы поняли.

          Я в прошлом своем комменте забыл у вас спросить, а как относится тот закон к правовому полю другой страны? Разве не нужно вести деятельность из под российском компании, чтобы они сделали соблюдение моей обязвнностью?


  1. Tomasina
    19.08.2026 16:03

    JOPA Call - эпичное название.