Подключиться к созвону сегодня так же просто, как отправить сообщение в корпоративном мессенджере. Один клик — и конференция готова. Но что творится под капотом платформы коммуникаций, когда вы нажимаете кнопку “Создать встречу”?

Когда в платформе коммуникаций Frisbee мы развивали собственную ВКС, нам казалось, что главная сложность заключается именно в передаче медиапотоков. Однако это лишь вершина айсберга. В корпоративном продукте звонок существует не сам по себе. Он работает внутри экосистемы мессенджера с пользователями, рабочими пространствами, ролями, правами доступа, мобильными и десктопными клиентами, push-уведомлениями, историей сообщений и интеграциями с другими сервисами. К этому добавляются корпоративные сети с VPN, NAT, firewall и нестабильным качеством соединения.
Поэтому при разработке ВКС нам пришлось решать не только задачу передачи медиа, но и строить полноценную платформу, способную масштабироваться, восстанавливаться после сбоев и развиваться вместе с продуктом. Платформа коммуникаций Frisbee давно вышла за рамки корпоративного мессенджера с видеозвонками. Сегодня это единая среда для корпоративных коммуникаций, которая объединяет ВКС, SIP-телефонию, вебинары, ИИ-ассистентов, запись и расшифровку встреч и многие другие опции.
В этой статье мы расскажем, какие архитектурные решения приняли при разработке ВКС, почему выбрали именно их и с какими техническими задачами столкнулись.
Архитектура ВКС
В качестве основы мы выбрали WebRTC — стандарт де-факто для real-time коммуникаций. Он решает ключевую задачу: позволяет передавать аудио и видео с минимальной задержкой, работать через NAT и адаптироваться к качеству сети.
Однако WebRTC отвечает только на один вопрос — как передать медиапоток. Все остальное остается на стороне приложения: создание комнаты, проверка прав доступа, приглашение участников, восстановление соединения, масштабирование конференций, сбор метрик и диагностика проблем.
Поэтому архитектуру мы сразу разделили на два независимых слоя.
Control plane отвечает за жизненный цикл звонка: создание конференции, подключение и отключение участников, управление ролями, синхронизацию состояния между клиентами, reconnect, missed call и другую бизнес-логику.
Media plane отвечает непосредственно за передачу медиа: установление WebRTC-соединений, маршрутизацию аудио- и видеопотоков, адаптацию качества связи и работу с сетевыми ограничениями.
Такое разделение позволило независимо развивать пользовательскую функциональность и real-time инфраструктуру, не связывая изменения в бизнес-логике с передачей медиа.
Почему мы выбрали SFU
Следующий архитектурный вопрос — каким образом передавать медиапотоки между участниками.
P2P хорошо подходит для звонков один на один, но плохо масштабируется. Каждый клиент вынужден поддерживать несколько соединений одновременно, отправляя медиапотоки каждому участнику отдельно. Это увеличивает нагрузку на процессор, сеть и аккумулятор устройства, особенно на мобильных клиентах.
MCU решает эту проблему за счет сервера, который декодирует, смешивает и повторно кодирует все медиапотоки. Такой подход дает больше контроля, но требует постоянной обработки видео и быстро становится слишком дорогим для массового использования.
Поэтому мы выбрали SFU (Selective Forwarding Unit).
В этой модели каждый участник публикует свои аудио- и видеопотоки в конференцию (publish), а остальные подписываются (subscribe) только на те потоки, которые им действительно нужны. Сервер не перекодирует видео, а выступает маршрутизатором медиапотоков.
Это дает сразу несколько преимуществ:
-
масштабируемость без постоянного перекодирования видео;
-
возможность независимо управлять каждым медиапотоком;
-
адаптивное качество для разных участников;
-
приоритизацию аудио перед видео;
-
отдельную обработку демонстрации экрана.
Такой подход оказался оптимальным компромиссом между производительностью, стоимостью инфраструктуры и гибкостью управления конференциями.
Реальные сети гораздо сложнее демо
Корпоративная ВКС редко работает в идеальных условиях. Пользователи подключаются через VPN, корпоративные прокси, мобильные сети, офисный Wi-Fi или домашний интернет, поэтому поддержку ICE, STUN и TURN мы изначально рассматривали как обязательную часть платформы.
Не менее важным оказался reconnect. Пользователь может сменить сеть, временно потерять соединение или свернуть приложение. Для него звонок должен продолжиться, а не завершиться с ошибкой, поэтому восстановление соединения стало штатным сценарием работы системы.
Еще один обязательный элемент архитектуры — observability. Для диагностики ВКС недостаточно знать, что пользователь “был в звонке”. Нужно понимать, сколько времени заняло подключение, какой маршрут выбрал ICE, были ли packet loss, jitter, RTT, происходил ли reconnect и на каком этапе возникла проблема. Поэтому сбор технических метрик и событий мы заложили в архитектуру с самого начала (подробнее об этом можно почитать в блоге платформы контейнеризации dBrain.cloud — нашей разработке, на которой разворачивается Frisbee).
В результате получилась модель, где control plane управляет жизненным циклом звонка, media plane отвечает за передачу медиа, а SFU маршрутизирует потоки между участниками. Именно на этой архитектуре затем были построены остальные возможности платформы — роли модераторов, режим вебинара, запись встреч, ИИ-ассистенты и агентский фреймворк, о которых расскажем дальше.
Агентский фреймворк
В какой-то момент возможностей обычной ВКС становится недостаточно. Появляются сценарии, где в звонок нужно добавить не еще одного человека, а отдельную исполняемую логику: расшифровку речи, синхронный перевод, модерацию, обработку событий комнаты, генерацию служебных сообщений или подключение внешнего ИИ-ассистента.
Чтобы такие сценарии не превращались в набор разрозненных интеграций, мы выделили отдельный агентский контур. В этой архитектуре внешний агент — это специальный тип участника комнаты, который может быть назначен на конкретную сессию и работать в рамках ее жизненного цикла. Он получает доступ к необходимым событиям и данным ВКС, а платформа управляет его запуском, состоянием и масштабированием независимо от пользовательских клиентов.
Для разработки агентов используется базовый агентский фреймворк, который берет на себя инфраструктурную часть: подключение к комнате, получение назначения, работу с состояниями, обмен служебными событиями и публикацию результатов обратно в сессию. Благодаря этому разработчику не нужно каждый раз реализовывать низкоуровневую интеграцию с ВКС — достаточно сосредоточиться на прикладной логике конкретного агента.
На уровне архитектуры поверх модели комнаты работает слой оркестрации. Он определяет, нужен ли в конкретной встрече агентский сценарий, создает задачу для исполнителя, после чего агент подключается к сессии и начинает работу.
Такой подход позволяет не зашивать агентскую логику в ядро ВКС, а развивать ее как отдельный управляемый слой. В результате внешние агенты становятся полноценным расширением платформы — от простых обработчиков событий до интерактивных ИИ-помощников.

Запись ВКС: отдельный модуль и агент перехвата реплик
Запись в ВКС мы изначально проектировали не как простое сохранение одного файла, а как отдельный модуль со своей логикой жизненного цикла. В разных сценариях пользователю может понадобиться только аудио, только видео или оба варианта одновременно, поэтому система поддерживает независимый запуск аудио- и видеозаписи в рамках одной встречи.
При этом запись не является частью основного медиаконтура. После старта модуль получает необходимый медиапоток, а готовые файлы сохраняются во внешнее объектное хранилище. Это позволяет не привязывать записи к конкретным узлам, упрощает дальнейшую обработку и делает систему более масштабируемой.
Отдельная задача появляется, когда нужно получить не просто запись разговора, а структурированную расшифровку с разделением по участникам. Модели распознавания речи умеют определять смену говорящих, но в реальных конференциях с пересечением реплик, шумом и нестабильным качеством звука этого бывает недостаточно.
Для этого вместе со стартом записи запускается отдельный служебный контур. Он отслеживает события комнаты и фиксирует временную разметку: когда участник начал говорить и когда завершил реплику. В результате система получает не только аудиофайл, но и дополнительный контекст о структуре разговора.
На этапе последующей обработки эти данные используются для более точной расшифровки: проще определить границы реплик, связать фрагменты речи с конкретными участниками и получить более качественный итоговый текст. Таким образом, запись отвечает за сохранение медиаданных, а параллельный контур событий — за сохранение структуры разговора.

ИИ-ассистент: автоматическая суммаризация встреч
ИИ-ассистент в платформе коммуникаций Frisbee превращает запись ВКС в структурированный отчет: выделяет основные темы, решения и договоренности, а также предоставляет полную расшифровку встречи, если нужно вернуться к деталям.
После завершения звонка запускается цепочка обработки из двух основных этапов. Первый сервис отвечает за транскрибацию — преобразует аудиозапись в текст. Второй анализирует полученный текст и формирует итоговый отчет с помощью языковой модели. Оба сервиса работают на GPU-оборудовании с моделями, развернутыми внутри нашей инфраструктуры.

Для подготовки качественного результата нужно объединить два источника данных: сам текст встречи и информацию о том, кто и когда говорил. Эти данные приходят из разных систем и могут иметь задержки, поэтому одной из ключевых технических задач стала их синхронизация. Отдельная сложность возникает при шуме или одновременной речи нескольких участников — в таких случаях сложнее определить, кому принадлежит конкретная реплика.
При работе с языковыми моделями также пришлось решать проблему качества результата. Одни модели лучше сохраняют структуру отчета, другие глубже анализируют смысл, но хуже соблюдают формат. Кроме того, модели могут генерировать недостоверные детали, поэтому потребовалось много экспериментов с настройками и выбором оптимального варианта.
Система также поддерживает сценарии деградации: если один из этапов обработки недоступен, мы не останавливаем весь процесс, а выдаем пользователю максимально полный результат из доступных данных.
Для масштабирования используется параллельная обработка задач. Специальный механизм распределяет запросы между GPU-узлами, отслеживает их загрузку и направляет новые задачи на менее занятые ресурсы, что позволяет сокращать время ожидания обработки встреч.
SIP как часть общей модели коммуникаций
Корпоративный мессенджер редко существует в изоляции. Во многих компаниях уже есть собственная телефония, внутренние номера, внешние линии и существующая SIP-инфраструктура. Поэтому вопрос стоял не в том, нужен ли SIP как протокол, а в том, как встроить телефонные звонки в общую модель коммуникаций, не создавая еще один отдельный контур связи.
Мы реализовали SIP как подключаемый модуль, интегрированный в жизненный цикл ВКС. Для пользователя ничего не меняется: он работает в привычном интерфейсе мессенджера, а платформа сама создает медиасессию, связывает ее с внутренним идентификатором звонка и подключает телефонного участника к общей конференции.
Такой подход оказался более гибким, чем отдельный телефонный сервис. Телефония нужна не каждому внедрению, поэтому SIP можно подключать только там, где он действительно востребован. При этом после подключения он работает по тем же правилам, что и остальные сценарии платформы: участвует в координации старта вызова, хранении состояния активной сессии и обработке событий при подключении, отключении участников или завершении разговора.
В результате SIP воспринимается не как внешняя интеграция, а как еще один сценарий коммуникации внутри платформы. Это упрощает сопровождение системы, делает поведение звонков единообразным и позволяет развивать телефонию вместе с остальными возможностями ВКС, не создавая для нее отдельную архитектуру.
Режим модератора
С точки зрения архитектуры режим модератора оказался не отдельной сущностью, а еще одним состоянием комнаты. Мы не строили для него отдельный сервис — вся логика встроилась в уже существующий механизм синхронизации состояния участников.
За основу мы используем Data Channel поверх WebRTC для доставки событий между всеми клиентами и общую metadata комнаты, которая хранит текущее состояние конференции. В metadata находится список модераторов, режимы работы комнаты и другие параметры, которые должны быть одинаковыми для Web, Desktop, Android и iOS.

Когда инициатор встречи назначает нового модератора, клиент отправляет соответствующее событие через Data Channel. Сервер обновляет metadata комнаты, после чего новое состояние автоматически синхронизируется со всеми участниками. Получив обновленную metadata, клиенты перестраивают интерфейс: у нового модератора появляются дополнительные действия — отключение микрофонов, удаление участников, управление режимами конференции и передача роли другим пользователям.
На первый взгляд задача выглядит простой — хранить список модераторов. На практике возникла проблема конкурентных изменений. Серверная часть работает на Java и развернута в нескольких экземплярах, поэтому два администратора могут одновременно изменить состав модераторов. Без синхронизации одно из изменений может быть потеряно.
Для защиты от гонок данных мы использовали распределенные блокировки на базе Redis. Перед изменением metadata сервер получает блокировку, обновляет состояние комнаты и только после этого публикует новую версию. Благодаря этому список модераторов остается консистентным независимо от того, какой экземпляр сервера обработал запрос.
Такой подход позволил оставить бизнес-логику максимально простой: права модератора — это часть общего состояния комнаты, а их распространение происходит через уже существующий механизм синхронизации, без отдельных каналов обмена сообщениями.
Именно на этой функциональности команда Frisbee уже провела открытый вебинар о переезде с Telegram на корпоративный мессенджер (как это происходит, можно посмотреть тут). Сейчас идет активное внедрение полноценного режима вебинара.
Режим вебинара
Режим вебинара построен поверх той же архитектуры и не требует отдельного сценария подключения участников. Для системы это обычная конференция, у которой меняется состояние комнаты.
При включении режима в metadata записываются соответствующие параметры: кто может публиковать аудио- и видеопотоки, какие ограничения действуют для остальных участников и кто обладает правами управления. Изменения распространяются через Data Channel, поэтому все клиенты практически одновременно получают новое состояние комнаты.
На клиентской стороне именно metadata определяет доступное поведение интерфейса. Если участнику запрещена публикация аудио или видео, соответствующие элементы управления блокируются, а попытки изменить состояние не приводят к публикации новых медиапотоков.
Такой подход позволяет реализовать режим вебинара без отдельной логики передачи медиа. SFU продолжает работать по модели publish/subscribe, а ограничения накладываются на уровне управления состоянием комнаты. В результате режим вебинара остается обычной ВКС-сессией, в которой меняются только правила публикации медиапотоков.
Запросы доступа
Запросы доступа решают другую задачу и не связаны с режимом вебинара. Если вебинар определяет, что участник может делать после входа в конференцию, то запрос доступа отвечает за вопрос можно ли вообще попасть в комнату.
При включенной настройке пользователь, переходящий по ссылке, сначала попадает в очередь ожидания. На этом этапе он еще не является участником конференции, поэтому у него нет WebRTC-соединения и, соответственно, недоступен Data Channel.
Для уведомления модераторов мы переиспользовали существующий механизм metadata комнаты. Новый запрос добавляется в общее состояние конференции, после чего все модераторы получают обновление автоматически через уже существующий канал синхронизации. Это позволило не создавать отдельную систему доставки событий.

Со стороны ожидающего пользователя ситуация отличается. Поскольку он еще не подключен к комнате, получать обновления через WebRTC он не может. Для этого используется long polling: после создания запроса сервер выдает идентификатор ожидания, а клиент с заданным интервалом опрашивает его статус — разрешен вход, отклонен или запрос еще находится в обработке.
Во время разработки неожиданно возникла еще одна проблема. Пользователь мог просто закрыть вкладку браузера или перезагрузить страницу, не отправив серверу никакого события. В результате запрос продолжал числиться в очереди, хотя самого пользователя уже не существовало.
Для очистки таких “висящих” запросов мы использовали механизм keepalive fetch, который позволяет отправить завершающий HTTP-запрос даже в момент закрытия страницы. Благодаря этому очередь ожидания остается актуальной и не требует дополнительной очистки.
Еще одной задачей стала обратная совместимость. Старые версии клиентов не поддерживали сценарий ожидания разрешения на вход и воспринимали закрытую комнату как обычную ошибку подключения. Поэтому API пришлось версионировать: новый endpoint поддерживает сценарий ожидания с long polling, а старый продолжает возвращать привычную ошибку и предлагает пользователю обновить клиент. Такой подход позволил постепенно внедрить новую функциональность без нарушения совместимости с уже развернутыми версиями приложения.
Траблшутинг: диагностика проблем без влияния на конференцию
Отдельная практическая задача для любой ВКС — разбор пользовательских проблем. Даже при стабильной работе системы в реальных условиях возникают ситуации, когда у одного участника ухудшается качество видео, пропадает звук или соединение начинает деградировать в конкретной сети.
Для таких случаев мы предусмотрели отдельный траблшутинг-сценарий. Проблемных участников можно динамически вывести в изолированный диагностический контур на отдельной машине и анализировать их поведение отдельно от основной конференции.

Такой подход позволяет исследовать конкретный кейс: смотреть телеметрию, служебные события, состояние медиапотоков и сетевые параметры именно тех пользователей, у которых возникает проблема. При этом изменения маршрутизации, транспортных настроек или низкоуровневых параметров не затрагивают остальных участников звонка.
Большая часть сложных проблем в ВКС связана не с бизнес-логикой, а с сетевой средой: NAT, firewall, корпоративными прокси, потерями пакетов, джиттером, качеством канала и выбором транспортного пути. Такие проблемы редко решаются одним универсальным исправлением — чаще требуется локальная диагностика и проверка разных гипотез.
Поэтому отдельный диагностический контур позволяет превратить траблшутинг из вмешательства в работу всей конференции в управляемый инструмент: проблему можно изолировать, изучить и подобрать решение, не влияя на остальных пользователей.
Если посмотреть на архитектуру целиком, то становится заметно, что сама передача аудио и видео занимает лишь небольшую часть системы. Основная сложность современной корпоративной ВКС — это управление состоянием распределенной системы, интеграция различных сценариев коммуникации и обеспечение устойчивой работы в реальных сетях. Именно вокруг этих задач сегодня и развивается платформа коммуникаций Frisbee.
Какие архитектурные подходы, инструменты или технологии используете вы при построении систем реального времени? Делитесь опытом, задавайте вопросы и обсуждайте тему в комментариях — будет интересно сравнить подходы и обменяться практическими кейсами.
ссылка на оригинал статьи https://habr.com/ru/articles/1066538/