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выделяет один из UDPTranslator-портов для устройства.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
- Клиент входит в конференцию обычным
connect_to_conference_request. - Клиент запрашивает
device_paramsдля микрофона. - Сервер выдает
device_idиauthor_ssrc. - Клиент создает
RTCPeerConnectionи добавляетgetUserMedia({ audio: true })track. - Клиент отправляет SDP offer через сигналинг.
- Gateway отвечает SDP answer и завершает ICE/DTLS.
- Gateway получает Opus RTP из WebRTC, преобразует SRTP в plain RTP и отправляет его на Translator port с
author_ssrc. - Серверная логика устройства остается прежней: участники получают
device_connect.
Subscribe remote microphone
- Клиент получает
device_connectсreceiver_ssrc,author_ssrc,port. - Клиент сообщает Gateway, что нужен remote audio renderer для этого устройства.
- Gateway регистрирует receiver на Translator:
- отправляет adjusting RTP/RTCP от имени
receiver_ssrc, чтобы Translator запомнил UDP-адрес receiver; - получает RTP автора с Translator;
- отправляет этот поток в браузер как WebRTC audio track.
- Браузер воспроизводит входящий звук через нативный WebRTC/audio path, без JS Opus decoder и без
AudioContextкак основного output.
Publish camera
- Клиент получает
device_id,author_ssrcи Translatorportчерез обычный lifecycle устройства. - Клиент создает WebRTC offer со своим video track.
- Gateway принимает RTP от браузера, нормализует SSRC в
author_ssrcи отправляет plain RTP в Translator. Это сохраняет совместимость с native-клиентами, recorder иWSMServer. - Для браузерных WebRTC-подписчиков Gateway может пересылать RTP напрямую между WebRTC publisher/subscriber tracks, если publisher тоже WebRTC. Это не отменяет Translator: Translator остается ядром для native/WSM/recording path.
Subscribe remote camera
- Клиент получает
device_connectудаленной камеры и открываетvideo-subscribeWebRTC flow. - Если источник - native/WSM/recorder path, Gateway получает RTP из Translator и отправляет его как WebRTC video track.
- Если источник - WebRTC publisher, Gateway может использовать прямой WebRTC forwarding между tracks и параллельно продолжать кормить Translator для остальных типов клиентов.
- 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ожидает targetsrtp2; - собирает 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:
- SDP/codec negotiation: предпочитать H.264 для WebRTC, VP8 оставить fallback.
- RTP inspection: добавить H.264 keyframe detection по IDR/STAP-A/FU-A.
- Native clients: добавить OpenH264 software fallback.
- Mobile clients: использовать WebRTC как первый transport contract, без встраивания C++ core.
- Hardware acceleration: оформлять отдельными backend implementations, не смешивая с базовой H.264-интеграцией.