Skip to content

WebRTC media transport

Цель этого направления - дать браузерному клиенту нативный media path для аудио и видео: RTCPeerConnection в браузере, WebRTC Gateway на сервере и единая серверная модель устройств/SSRC для всех клиентов.

CORE-10 добавляет центральный WebRTC media node. Браузеры подключаются к VideoGrace Server по ICE/DTLS/SRTP на отдельные WebRTC UDP-порты, а сервер связывает этот транспорт с существующим Translator и conference lifecycle. Нативные клиенты, WSMServer, recorder и другие сервисы продолжают использовать существующий media core.

Текущий совместимый набор кодеков:

  • audio: Opus через WebRTC;
  • video: VP8 для текущего browser path;
  • целевой следующий шаг: H.264-first для iOS/Android/native compatibility, VP8 оставить как fallback/legacy path.

Почему нельзя подключить браузер прямо к Translator

Существующий серверный media core уже работает по UDP/RTP:

  • TranslatorPool выделяет один из UDP Translator-портов для устройства.
  • Translator разводит RTP по author_ssrc и receiver_ssrc.
  • Native-клиенты и WSMServer отправляют в Translator обычные RTP/RTCP пакеты.
  • WSMServer сейчас является мостом WebSocket binary frame -> UDP RTP.

Браузерный RTCPeerConnection не умеет отправлять такой plain RTP напрямую в UDP-порт Translator. WebRTC поверх UDP всегда включает:

  • ICE для выбора сетевого пути и consent checks;
  • DTLS handshake;
  • SRTP/SRTCP вместо plain RTP/RTCP;
  • SDP offer/answer и ICE candidates;
  • RTP/RTCP mux и обычно BUNDLE.

Значит, нужен WebRTC terminator/gateway: он принимает WebRTC от браузера, снимает ICE/DTLS/SRTP и связывает WebRTC-треки с существующей моделью device_id, author_ssrc, receiver_ssrc и Translator-портов.

Целевая схема

flowchart LR
    Browser["Browser\nRTCPeerConnection"] -->|ICE + DTLS + SRTP| Gateway["WebRTC Gateway"]
    Gateway -->|plain RTP/RTCP for native core| Translator["TranslatorPool / Translator"]
    Translator -->|plain RTP/RTCP for native/WSM/subscribers| Gateway
    Gateway -->|WebRTC media tracks| Browser

    Control["ControlWS"] -->|conference/device/signaling| Browser
    Control -->|device state| Gateway

ControlWS остается каналом управления. WebRTC Gateway становится media-шлюзом рядом с WSMServer, а не заменой conference logic.

Media flows

Publish microphone

  1. Клиент входит в конференцию обычным connect_to_conference_request.
  2. Клиент запрашивает device_params для микрофона.
  3. Сервер выдает device_id и author_ssrc.
  4. Клиент создает RTCPeerConnection и добавляет getUserMedia({ audio: true }) track.
  5. Клиент отправляет SDP offer через сигналинг.
  6. Gateway отвечает SDP answer и завершает ICE/DTLS.
  7. Gateway получает Opus RTP из WebRTC, преобразует SRTP в plain RTP и отправляет его на Translator port с author_ssrc.
  8. Серверная логика устройства остается прежней: участники получают device_connect.

Subscribe remote microphone

  1. Клиент получает device_connect с receiver_ssrc, author_ssrc, port.
  2. Клиент сообщает Gateway, что нужен remote audio renderer для этого устройства.
  3. Gateway регистрирует receiver на Translator:
  4. отправляет adjusting RTP/RTCP от имени receiver_ssrc, чтобы Translator запомнил UDP-адрес receiver;
  5. получает RTP автора с Translator;
  6. отправляет этот поток в браузер как WebRTC audio track.
  7. Браузер воспроизводит входящий звук через нативный WebRTC/audio path, без JS Opus decoder и без AudioContext как основного output.

Publish camera

  1. Клиент получает device_id, author_ssrc и Translator port через обычный lifecycle устройства.
  2. Клиент создает WebRTC offer со своим video track.
  3. Gateway принимает RTP от браузера, нормализует SSRC в author_ssrc и отправляет plain RTP в Translator. Это сохраняет совместимость с native-клиентами, recorder и WSMServer.
  4. Для браузерных WebRTC-подписчиков Gateway может пересылать RTP напрямую между WebRTC publisher/subscriber tracks, если publisher тоже WebRTC. Это не отменяет Translator: Translator остается ядром для native/WSM/recording path.

Subscribe remote camera

  1. Клиент получает device_connect удаленной камеры и открывает video-subscribe WebRTC flow.
  2. Если источник - native/WSM/recorder path, Gateway получает RTP из Translator и отправляет его как WebRTC video track.
  3. Если источник - WebRTC publisher, Gateway может использовать прямой WebRTC forwarding между tracks и параллельно продолжать кормить Translator для остальных типов клиентов.
  4. Keyframe requests идут через Gateway к publisher и должны быть throttled, чтобы PLI/FIR-loop не превращался в flood.

Signaling API

Минимальный набор команд поверх ControlWS:

{
  "webrtc_offer": {
    "conference_tag": "test",
    "scope": "audio",
    "sdp": "v=0...",
    "device_id": 1059,
    "author_ssrc": 1214,
    "port": 5063
  }
}

device_id, author_ssrc и port являются media binding для publish path. Клиент берет их из обычного device lifecycle: device_params выдает device_id/author_ssrc, а device_connect CreatedDevice возвращает Translator port. Если binding не передан, сервер может завершить SDP/ICE handshake, но не будет отправлять RTP в Translator.

{
  "webrtc_answer": {
    "conference_tag": "test",
    "scope": "audio",
    "sdp": "v=0..."
  }
}
{
  "webrtc_ice_candidate": {
    "conference_tag": "test",
    "scope": "audio",
    "candidate": {
      "candidate": "candidate:...",
      "sdpMid": "0",
      "sdpMLineIndex": 0
    }
  }
}

scope определяет назначение binding:

  • audio - publish microphone;
  • video - publish camera/screen;
  • audio-subscribe - receive remote microphone;
  • video-subscribe - receive remote camera/screen.

Корреляция с текущей моделью устройств идет через device_id, author_ssrc, receiver_ssrc и port, которые уже приходят в device_connect.

Инварианты

  • Conference membership, permissions, visibility/hearability и lifecycle устройств остаются в Processor.
  • Translator остается media router; WebRTC Gateway не принимает решений о правах доступа.
  • WebRTC path не должен создавать WSMedia сессии для media payload.
  • WSMedia остается обязательным fallback для сетей и браузеров, где UDP/WebRTC/SRTP заблокирован или нестабилен.
  • Для браузера WebRTC path должен обходить JS Opus decode/encode и ScriptProcessor как основной audio pipeline.
  • WebRTC SRTP-порты не смешиваются с Translator-портами 5060-5063: это разные transport layers.
  • Translator остается ядром трансляции для native-клиентов, WSMedia, recorder и совместимости с существующей media-моделью.
  • Browser-to-browser video forwarding может оптимизироваться внутри Gateway, но не должен ломать Translator path.

Failover на WSMedia

WebRTC должен быть предпочтительным media path для браузера, но не единственным. В реальной сети UDP и SRTP могут быть заблокированы или деградировать, поэтому клиент и сервер должны сохранять рабочий WSMedia path как автоматический fallback.

Режим клиента:

  • auto: сначала пробовать WebRTC, при ошибке переходить на WSMedia.
  • webrtc: использовать только WebRTC для диагностики нового транспорта.
  • wsm: использовать только текущий WSMedia mux для диагностики и совместимости.

Условия перехода auto -> wsm:

  • ICE не вышел в connected/completed за ограниченный таймаут.
  • DTLS/SRTP handshake завершился ошибкой.
  • PeerConnection перешел в failed/disconnected и не восстановился быстро.
  • Есть signaling/device state, но media frames не приходят или не уходят в течение контрольного окна.
  • Браузер или платформа не поддерживает нужный WebRTC/audio path.

Инвариант реализации: Processor, conference membership, device lifecycle, device_id, author_ssrc, receiver_ssrc и TranslatorPool не должны зависеть от выбранного транспорта. WebRTC Gateway и WSMedia являются транспортными адаптерами вокруг одной серверной модели устройств. При failover клиент переподнимает те же опубликованные/подписанные устройства через WSMedia, а UI показывает восстановление связи, а не "мертвый" звонок.

Во время активной конференции автоматический возврат wsm -> webrtc не обязателен. Его можно добавлять позже только если переключение будет безопасным и без заметного разрыва media.

Server-owned ICE

VideoGrace не должен зависеть от внешних STUN/TURN-сервисов для базового server-relay сценария. WebRTC Gateway работает как публичная UDP-точка самого VideoGrace Server: браузер получает ICE candidate сервера через ControlWS и отправляет WebRTC/UDP на этот адрес.

Если сервер имеет публичный IP прямо на интерфейсе, дополнительных ICE-сервисов не требуется. Если сервер находится за NAT или libdatachannel видит только приватный адрес вроде 192.168.x.x, нужно явно указать адрес, который браузеры должны использовать:

export VG_WEBRTC_ADVERTISE_ADDRESS=core.videograce.ru

Та же настройка может жить в серверном конфиге:

[WebRTC]
AdvertiseAddress=core.videograce.ru

Если WebRTC.AdvertiseAddress не задан, сервер использует Network.Address / VG_ADDR.

Для эксплуатации лучше ограничить UDP-диапазон и открыть его на firewall/NAT:

export VG_WEBRTC_PORT_RANGE_BEGIN=43000
export VG_WEBRTC_PORT_RANGE_END=43100
[WebRTC]
PortRangeBegin=43000
PortRangeEnd=43100

Если нужно привязать libdatachannel к конкретному локальному интерфейсу:

export VG_WEBRTC_BIND_ADDRESS=0.0.0.0
[WebRTC]
BindAddress=0.0.0.0

Инвариант: VG_WEBRTC_ADVERTISE_ADDRESS должен быть достижим с клиентской сети, а UDP-порты из диапазона должны приходить на VideoGrace Server. Эти порты отдельные от Translator-портов. Если UDP недоступен, web-клиент в режиме auto обязан перейти на WSMedia.

Codec direction

Audio path использует Opus. Это обязательный WebRTC codec и он хорошо подходит для браузеров и мобильных клиентов.

Video path должен двигаться в сторону H.264-first:

  • iOS WebRTC не должен рассматриваться как VP8-capable target;
  • mobile native clients должны публиковать и принимать H.264;
  • native desktop может использовать OpenH264 как software fallback;
  • аппаратное ускорение нужно выносить в отдельные backend implementations: VideoToolbox на Apple, Media Foundation/NVENC/QSV на Windows, VAAPI/NVENC на Linux;
  • VP8 можно оставить как fallback для web/desktop, но не как единственный codec.

Gateway не должен становиться video transcoder по умолчанию. Его задача - WebRTC termination, RTP routing, keyframe/RTCP control и совместимость транспортов. Кодирование/декодирование должно жить на клиенте или в специализированных media services.

Варианты реализации Gateway

In-process C++ gateway

Рекомендуемый долгосрочный вариант.

Подходящая библиотека: libdatachannel.

Плюсы:

  • C++17, ближе к текущему серверу.
  • ICE/DTLS/SRTP и media tracks без полной тяжести Google libwebrtc.
  • Можно встроить рядом с WSMServer и использовать существующие UDPSocket, TranslatorPool, логирование и конфиг.

Минусы:

  • Нужно добавить новую third-party зависимость и сборку под Linux/Windows.
  • Потребуется аккуратная интеграция с event loop сервера.

В сервере зависимость должна включаться только через backend gateway:

cmake -S . -B build -DVG_ENABLE_LIBDATACHANNEL=ON
cmake --build build --target VideoGraceServer

Без VG_ENABLE_LIBDATACHANNEL сервер собирается со stub gateway и принимает signaling-команды, но не поднимает WebRTC media.

Что дает libdatachannel

libdatachannel закрывает именно WebRTC-терминацию, а не заменяет наш media core:

  • ICE и candidate negotiation;
  • DTLS handshake;
  • SRTP/SRTCP;
  • SDP offer/answer;
  • WebRTC media tracks;
  • SCTP/datachannel support, который сейчас не является целью audio/video path.

Кодеки, микширование, конференционная модель, права доступа, TranslatorPool и устройство/SSRC lifecycle остаются в VideoGrace. Gateway должен получить из WebRTC обычные RTP/RTCP пакеты и передать их в существующий UDP media core.

Сборка libdatachannel binaries

Исходники libdatachannel лежат в thirdparty/libdatachannel, headers - в Lib/libdatachannel/include. Бинарные артефакты не собираются основным CMake автоматически и не должны становиться частью обычного исходного diff. Для каждой платформы они собираются отдельно, публикуются как пакет Lib/libdatachannel, а в рабочую копию подтягиваются через Lib/upd_*_libs.py по той же модели, что и остальные bundled-библиотеки.

Для macOS arm64:

thirdparty/libdatachannel/build_vg_macos.sh

Для Linux x86_64:

thirdparty/libdatachannel/build_vg_linux.sh

Для Windows x64 из Developer PowerShell for Visual Studio:

powershell -ExecutionPolicy Bypass -File thirdparty/libdatachannel/build_vg_windows.ps1 -Platform win_x64

Для Windows Win32:

powershell -ExecutionPolicy Bypass -File thirdparty/libdatachannel/build_vg_windows.ps1 -Platform win32

Скрипт:

  • подтягивает build-only зависимости в thirdparty/libdatachannel/deps;
  • фиксирует libsrtp на v2.7.0, потому что libdatachannel 0.24.2 ожидает target srtp2;
  • собирает static datachannel-static;
  • использует OpenSSL из Lib/OpenSSL/lib/x64 для win_x64 и Lib/OpenSSL/lib/win32 для win32;
  • копирует результат в платформенную папку Lib/libdatachannel/lib/*.

Ожидаемые артефакты:

Lib/libdatachannel/lib/mac_arm64/libdatachannel-static.a
Lib/libdatachannel/lib/mac_arm64/libjuice-static.a
Lib/libdatachannel/lib/mac_arm64/libsrtp2.a
Lib/libdatachannel/lib/mac_arm64/libusrsctp.a

Lib/libdatachannel/lib/lin_x64/libdatachannel-static.a
Lib/libdatachannel/lib/lin_x64/libjuice-static.a
Lib/libdatachannel/lib/lin_x64/libsrtp2.a
Lib/libdatachannel/lib/lin_x64/libusrsctp.a

Lib/libdatachannel/lib/win_x64/datachannel-static.lib
Lib/libdatachannel/lib/win_x64/juice-static.lib
Lib/libdatachannel/lib/win_x64/srtp2.lib
Lib/libdatachannel/lib/win_x64/usrsctp.lib

Lib/libdatachannel/lib/win32/datachannel-static.lib
Lib/libdatachannel/lib/win32/juice-static.lib
Lib/libdatachannel/lib/win32/srtp2.lib
Lib/libdatachannel/lib/win32/usrsctp.lib

После публикации пакета для платформы сервер проверяется так:

cmake -S . -B /tmp/videograce-cmake-webrtc-check -DVG_ENABLE_LIBDATACHANNEL=ON
cmake --build /tmp/videograce-cmake-webrtc-check --target VideoGraceServer

Sidecar gateway

Быстрый прототип.

Подходящая библиотека: Pion WebRTC.

Плюсы:

  • Самый быстрый способ проверить production-like WebRTC audio path.
  • Можно изолировать риск от основного сервера.
  • Gateway общается с основным сервером по ControlWS/API и с Translator по UDP.

Минусы:

  • Новый runtime и deployment unit.
  • Нужно решить авторизацию и discovery Translator ports.
  • После прототипа, возможно, придется переносить в C++.

Full libwebrtc

Не рекомендуется для первого этапа.

Плюсы: максимальная совместимость с браузерами.

Минусы: тяжелая сборка, большой бинарный и операционный вес, сложнее сопровождать.

CORE-10 readiness

Готовый WebRTC gateway должен закрывать:

  • signaling webrtc_offer/answer/ice_candidate через ControlWS;
  • publish microphone: browser mic track -> Gateway -> Translator;
  • subscribe microphone: Translator -> Gateway -> browser remote audio track;
  • publish camera: browser camera track -> Gateway -> Translator;
  • subscribe camera: Translator/Gateway -> browser remote video track;
  • WSMedia fallback без регресса для сетей, где UDP/WebRTC/SRTP недоступен;
  • native/WSM/recorder compatibility через Translator path;
  • throttled keyframe requests, чтобы browser RTCP feedback не создавал бесконечный PLI/FIR flood.

Следующий этап

После CORE-10 video compatibility нужно переводить на H.264-first:

  1. SDP/codec negotiation: предпочитать H.264 для WebRTC, VP8 оставить fallback.
  2. RTP inspection: добавить H.264 keyframe detection по IDR/STAP-A/FU-A.
  3. Native clients: добавить OpenH264 software fallback.
  4. Mobile clients: использовать WebRTC как первый transport contract, без встраивания C++ core.
  5. Hardware acceleration: оформлять отдельными backend implementations, не смешивая с базовой H.264-интеграцией.