Запись, вещание и мост WebRTC → HLS

Автор: Николай СапуновОбновлено: август 202631 мин чтения
Содержание статьи +

TL;DR

Любой продукт с интерактивным видео поверх WebRTC рано или поздно сталкивается с одной и той же задачей: маркетинг называет её «записью», юристы – «архивом», а отдел роста – «прямой трансляцией на маркетинговом сайте». Это вторая, постоянная копия разговора для пассивных зрителей, живущая вне WebRTC-сессии. Доставить эту копию тысячам или миллионам зрителей быстрее всего по HLS, а работа по превращению содержимого комнаты SFU в публичный HLS-плейлист и называется в индустрии мостом WebRTC → HLS. В 2026 году в продакшене встречаются пять рабочих паттернов моста: пер-трековая запись, server-side композиция, композиция через headless-браузер, WebRTC → RTMP с выходом в отдельный live-энкодер, и управляемые SaaS-мосты вроде LiveKit Egress, Dolby OptiView и Amazon Chime Live Connector. Какой подойдёт вашему продукту, определяют три вопроса: сколько у вас разных макетов, работает ли мост в режиме горячего ожидания или поднимается по требованию, и какую общую задержку вы можете позволить. Эта статья проходит по всем пяти паттернам – с архитектурой, числами по задержкам, режимами отказа и реальной картиной продакшена в 2026 году.

Почему это важно

Если вы строите видеоконференцию, телемедицину, e-learning, live-shopping, аукционы, спорт-беттинг или платформу удалённой совместной работы поверх WebRTC, мост в HLS – это момент, когда переворачивается ваша экономика. Доставка по WebRTC стоит дорого в пересчёте на одного зрителя, потому что каждый зритель – это реальный peer сервера. Доставка по HLS дёшева в пересчёте на бит, потому что CDN кэширует сегмент один раз и отдаёт его миллиону клиентов. Архитектурные решения на уровне моста – что именно вы записываете, как составляете макет комнаты, где работает транскодер, насколько отстаёт от комнаты broadcast-хвост – задают потолок аудитории, который вы можете обслужить, и нижнюю границу счёта за CPU и за трафик. Эти решения обычно необратимы после того, как продукт запустился и на каждое шоу пришла тысяча зрителей. Статья даёт архитектуру, расчёт задержек и режимы отказа для каждого паттерна, чтобы вы выбрали мост правильно с первого раза, а не со второго после неудачного запуска.

Какую задачу решает мост

Комната WebRTC устроена как короткая, peer-маршрутизируемая, реалтаймовая сессия для двустороннего разговора. Каждый участник – peer сервера: сервер (Selective Forwarding Unit, или SFU; см. SFU, MCU и Mesh) согласует отдельный WebRTC-PeerConnection для каждого, запускает DTLS-SRTP-шифрование для каждого (см. DTLS, SRTP, TLS, mTLS для медиа), следит за состоянием ICE для каждого (см. ICE, STUN, TURN подробно) и форвардит RTP-пакеты в реальном времени внутри зашифрованного канала сессии. Экономика масштабируется как N участников × M kbps на участника. Шесть человек в комнате – небольшой SFU и недорогой TURN. Сто тысяч пассивных зрителей в комнате – уже нет: каждый зритель остаётся peer-ом, каждый стоит реальных байт на сервере, кривая стоимости линейна по числу зрителей.

HLS решает обратную задачу. Издатель пишет последовательность HTTP-сегментов в origin; HTTP-кэш (edge CDN) скачивает каждый сегмент один раз и отдаёт его всем, кто запросит этот URL. Кривая стоимости для оператора по сути плоская по числу зрителей, потому что fan-out делает CDN. Платит за это задержка: даже современный Low-Latency HLS (LL-HLS), нормативно описанный в HLS Authoring Specification от Apple и отслеживаемый в IETF как draft-pantos-hls-rfc8216bis (второе издание, наследующее RFC 8216), доставляет в диапазоне 2–5 секунд от издателя до зрителя – на порядки медленнее 200–500 мс, которые WebRTC даёт участникам комнаты (см. WebRTC delivery в масштабе).

Мост – это сервис между SFU и HLS-origin. Он подписывается на комнату WebRTC как специальный серверный участник, получает те же RTP-пакеты, что и любой зритель, декодирует медиа, при необходимости составляет несколько видео в один кадр, перекодирует результат, упаковывает в фрагментированный MP4 (CMAF) или MPEG-TS-сегменты и пишет их в HLS-origin, откуда CDN подхватывает. Зрители broadcast-хвоста получают поток с задержкой 2–10 секунд от разговора; участники комнаты продолжают видеть друг друга в реальном времени. Два разных стека, одно живое событие, мост между ними.

Рисунок 1. Архитектурная форма любого моста WebRTC → HLS. Левая половина интерактивна и дорога на каждого peer-а; правая – broadcast и дёшева на CDN; мост в центре делает работу по протоколам, упаковке и (обычно) композиции, которая соединяет две половины.

Почему SFU не делает это сам

Закономерный первый вопрос: «зачем нужен отдельный сервис – разве SFU не может писать HLS-сегменты?». Ответ – в том, как устроен SFU и под что он оптимизирован. Современный SFU – это высокопроизводительный форвардер RTP. Он принимает зашифрованные RTP-пакеты, читает заголовки и небольшое число полей payload-формата (для определения слоёв симулькаста и SVC; см. Simulcast и SVC), решает, какие пакеты кому форвардить, и отдаёт зашифрованные пакеты на выход. Он специально не декодирует медиа, потому что декодирование стоит дорого, а вся ценность SFU в том, что один процесс может обслуживать сотни и тысячи участников на обычном железе. HLS требует декодированных кадров, потому что композиция (отрисовка макета галереи), перекодирование (получение CMAF-совместимого H.264, H.265 или AV1 в нужной ABR-лестнице) и упаковка (запись fMP4- или MPEG-TS-сегментов по HLS-спецификации) работают с кадрами, а не с пакетами.

Команда LiveKit сделала компромисс явным в анонсе Universal Egress: «Главная цель egress-системы – не нагружать SFU. Ни при каких обстоятельствах мы не должны влиять на качество и производительность реал-тайм-аудио и видео». Все продакшен-SFU – mediasoup, Janus, LiveKit, Jitsi Videobridge, Pion (см. Выбор SFU) – пришли к тому же выводу. Мост – это отдельный воркер-процесс, часто на отдельной машине, часто с горизонтальным автоскейлингом, общающийся с SFU через один из двух интерфейсов: либо обычный RTP-форвард выбранных треков, либо серверная WebRTC-подписка, которая позволяет мосту появиться в комнате как скрытый участник.

Это и есть причина, по которой во всех описанных ниже паттернах участвует второй сервис. SFU остаётся форвардером; мост делает тяжёлую работу. Они операционно независимы.

Паттерн 1 – Пер-трековая запись: минимально жизнеспособный мост

Самый простой мост пишет один файл на трек на участника – никакой композиции, никакой живой раздачи, никакого HLS на первом этапе. У SFU запрашивают форвард выбранных RTP-потоков на recorder-процесс по обычному RTP, recorder пишет сырые RTP-пакеты в пер-трековый файл в формате типа .mjr (медиа-контейнер Meetecho для Janus), файл закрывается, когда участник выходит, и пост-процессинг превращает пер-трековые записи в воспроизводимый формат – .webm для видео, .opus или .m4a для аудио – уже после окончания комнаты. Если продукту нужен ещё и broadcast HLS, пост-обработанный файл скармливается в FFmpeg или GStreamer, которые делают HLS-плейлист и сегменты для загрузки в S3 или любой HTTP-origin для VOD-воспроизведения.

Janus поставляет этот паттерн со времён плагина RecordPlay; плагин пишет в .mjr, инструмент janus-pp-rec конвертирует в .webm / .opus, любой downstream-конвейер может сделать HLS дальше. У mediasoup паттерн похож: SFU вызывает transport.consume() на нужном треке, RTP форвардится в отдельный процесс по UDP, FFmpeg или GStreamer на другой стороне пишет файл. Пример записи в Kurento mediasoup-demos подробно документирует обмен SDP и команду FFmpeg.

Сильная сторона паттерна – операционная простота: путь записи – это форвардер RTP «выстрелил-и-забыл», recorder пишет файлы, пост-процессор работает после завершения комнаты. Никаких дедлайнов на live-транскодирование, никакого HLS-publish-цикла, который надо держать живым, никакой логики композиции, которую надо сопровождать. Цена – выход пер-трековый: один файл на камеру, один на микрофон, поэтому реконструкция единого «видео встречи» требует решения о макете и пост-композиции. Пост-процессинг часто медленный: на 60-минутную встречу уходит 5–20 минут композиции и перекодирования в зависимости от макета и целевого кодека. Для продуктов, где запись доставляется через минуты или часы как скачиваемый файл (архивы тренингов, телемед-копии для compliance, депозиции), это нормально. Для продуктов, где запись нужна как живой broadcast почти в темпе комнаты, – нет.

Реальные числа для Паттерна 1

Трек 720p VP8 на 1500 kbps плюс аудиотрек Opus на 64 kbps дают примерно 175 МБ .mjr в час на участника. Пост-обработка восьмиучастниковой комнаты в 720p-галерею на 16-ядерном encode-воркере с libx264 FFmpeg в пресете veryfast занимает 18–25 минут на 60-минутную запись. Затратная линия – wall-clock пост-процессора умноженный на часовую ставку; линия хранения – пер-трековые файлы плюс собранный выход.

Паттерн 2 – Server-side композиция: один мост-воркер на комнату

Второй паттерн переносит композицию внутрь мост-воркера, но не привязывает воркер к браузеру. Мост подписывается на SFU как серверный WebRTC-участник (или получает RTP-форварды выбранных треков), запускает медиаконвейер, который декодирует каждый подписанный трек, выкладывает декодированные кадры в единый композитный кадр по выбранному оператором layout-функционалу, перекодирует композит как один поток H.264 или H.265, упаковывает закодированный поток как фрагментированный MP4 (CMAF) или MPEG-TS, пишет сегменты и плейлист в HLS-origin и обновляет плейлист по мере закрытия новых сегментов. Конвейер обычно собирается на GStreamer или графе libavfilter из FFmpeg; layout-функция – это несколько сот строк кода, размещающих N видеоисточников в сетку, в active-speaker, в presenter-плюс-thumbnails или любую другую раскладку, нужную продукту.

Этот паттерн чаще всего реально работает «под капотом» у продакшен-мостов. Деплои на mediasoup обычно поднимают отдельный Node- или Python-воркер, который вызывает consume() для треков комнаты, передаёт RTP в GStreamer-элементы webrtcbin / rtpbin и compositor, прогоняет результат через x264enc и hlssink2. Документация GStreamer на hlssink2 описывает элемент и его свойство low-latency; low-latency=true включает CMAF chunked transfer для совместимости с LL-HLS. Деплои на Janus делают аналогичное с плагинами Streaming и VideoRoom плюс внешний композер.

Задержка от спикера до broadcast-зрителя в хорошо настроенном мосту Паттерна 2 – это примерно сумма: RTP-форвард внутри ЦОД (sub-10 мс), декодирование (один кадр, ~33 мс при 30 fps), композит (один кадр, sub-10 мс), кодирование с zero-latency-тюнингом (один кадр, ~33 мс), сегментация и запись пакетёром (одна часть, ~200 мс для LL-HLS-части), распространение по CDN (обычно 200–500 мс для первого хита через origin shield; см. Origin shield и tiered caching), требуемый буфер плеера (1–3 части для LL-HLS, то есть 200–600 мс). Итог – 2–5 секунд для LL-HLS; около 8–15 секунд для классического HLS с 6-секундными сегментами и 3-сегментным буфером плеера. Участники комнаты продолжают видеть друг друга за 200–500 мс; broadcast-хвост отстаёт на 2–5 секунд для low-latency и 8–15 секунд для классики. (См. Задержка glass-to-glass.)

Сильная сторона – низкий пол по задержке: можно собрать настоящий low-latency broadcast-хвост без аренды стороннего SaaS. Цена – операционная: мост-воркер – это stateful реалтаймовый процесс, который должен жить всё время комнаты, layout-код живёт внутри него и требует сопровождения, энкодеру нужна аппаратная акселерация, чтобы экономично масштабироваться (иначе доминирует CPU), а сегментёр должен успевать за wall-clock, иначе плейлист отстаёт.

Типичная ошибка: считать, что GStreamer-овский WebRTC заменяет SFU

Повторяющееся заблуждение: элемент GStreamer webrtcbin можно «навести» на комнату LiveKit или mediasoup, и мост готов. Нельзя. webrtcbin – это peer-элемент; он согласует PeerConnection 1:1 с одним другим peer-ом, а не с протоколом сигналинга SFU. Мост должен говорить на room-протоколе SFU на control-plane – RoomService.JoinRoom у LiveKit, WebSocket-сигналинг у mediasoup, API VideoRoom-плагина у Janus – и направлять в GStreamer-конвейер только RTP, который пошёл после согласия SFU и установки ключей SRTP. Именно поэтому у каждого продакшен-моста есть тонкая SFU-специфичная прослойка перед конвейером GStreamer / FFmpeg, а никогда не «один конвейер».

Рисунок 2. Пять продакшен-паттернов моста в 2026 году. Сложность растёт слева направо; контроль над макетом тоже растёт – пока в Паттерне 5 макет не фиксируется контрактом с вендором.

Паттерн 3 – Headless-браузер: макет в HTML

Третий паттерн – это то, что LiveKit, Daily и несколько других коммерческих WebRTC-платформ предлагают по умолчанию как room-composite egress. Вместо того чтобы писать layout-код внутри мост-воркера, оператор пишет обычную веб-страницу на HTML, CSS и JavaScript, которая отрисовывает желаемый вид комнаты в браузере. Мост-воркер поднимает реальный headless Chrome, открывает эту страницу, страница подключается к комнате через обычный web-SDK как скрытый участник, браузер рендерит живой композит в canvas, воркер захватывает выход браузера покадрово, кодирует, пакует как HLS и пишет сегменты.

Документация LiveKit Egress называет это режимом «room composite». Исходники Egress делают ровно то, что описано выше: когда egress-сервис получает RoomCompositeEgressRequest, он открывает Chrome, загружает выбранный template как веб-страницу, подключает её к комнате LiveKit как скрытого участника через JavaScript, и контентная область окна браузера захватывается, кодируется и оборачивается в выходной контейнер – HLS, MP4 или RTMP в downstream. Кодирование делает GStreamer внутри LiveKit Egress; GStreamer был выбран над FFmpeg для room composition, потому что libavfilter FFmpeg оказалось сложнее программно собирать под нужды команды.

Сильная сторона – непревзойдённая гибкость макета: оператор может вывести любой вид, который умеет рендерить веб-страница. Active-speaker плюс четыре thumbnails, presenter-плюс-боковой-чат, кастомный брендовый оверлей с логотипом и нижней третью, анимированный переход при смене активного спикера – каждое из этого реализуется как изменение CSS или JavaScript в шаблоне, а не как кодовое изменение в мост-воркере. Цена – ресурсный след: headless Chrome на каждую активную комнату потребляет 1–2 ГБ памяти и одно-два ядра CPU ещё до кодирования, поэтому стоимость на комнату выше, чем у чистого GStreamer-конвейера в Паттерне 2. Для комнат с уникальными макетами при умеренном масштабе (типичный SaaS-продукт для конференций или вебинаров) компромисс обычно правильный. Для комнат с одним фиксированным макетом и очень большим масштабом (платформа спорт-беттинга с 10 000 live-событий) Паттерн 2 дешевле.

Реальные числа для Паттерна 3

Room-composite egress в стиле LiveKit под headless Chrome в 1280×720 / 30 fps с x264enc в zero-latency-тюнинге и LL-HLS-выходом – это примерно 1,6 ГБ RAM и 1,8 CPU-ядра на активную комнату на современном Intel Xeon. Общая задержка от активного спикера до LL-HLS-зрителя – 3–5 секунд для LL-HLS-конфигурации с 200-мс частями и 8–15 секунд для классического HLS с 4–6-секундными сегментами. Команда LiveKit явно отмечает, что RTMP-relay из LiveKit Egress несёт встроенный буфер 1–2 секунды поверх LL-HLS-задержки ради надёжности relay – то есть путь WebRTC → LiveKit Egress → RTMP → downstream-HLS добавляет этот буфер поверх собственной задержки моста, что часто выводит общий glass-to-glass за 6 секунд.

Паттерн 4 – WebRTC → RTMP с выходом в отдельный live-энкодер

Четвёртый паттерн вытесняет HLS-упаковку из мост-воркера и делегирует её существующему live-энкодеру: AWS Elemental MediaLive, Wowza Streaming Engine, NimbleStreamer, инсталляция Ant Media Server, Mux Video, Cloudflare Stream Live или Amazon IVS. Мост-воркер по-прежнему делает WebRTC-подписку и композицию; дальше он перекодирует композит, заворачивает закодированный поток в RTMP и пушит RTMP в downstream live-энкодер, который делает ABR-лестницу (см. Построение битрейт-лестницы), CMAF-упаковку, генерацию HLS- и DASH-плейлистов, вставку рекламных меток SCTE-35 и интеграцию с CDN. Работа мост-воркера заканчивается на «опубликовать один высокобитрейтный RTMP-поток на заданный endpoint».

Это доминирующий паттерн для любого продукта, у которого уже работает видеоинфраструктура под не-WebRTC-контент и который хочет добавить интерактивный WebRTC-источник. Amazon Chime SDK поставляет ровно этот паттерн как Live Connector, который захватывает Chime-встречу и пушит RTMPS в Amazon IVS или AWS Elemental MediaLive – HLS-работу делает downstream-сервис. Dolby OptiView (переименованный Millicast) поддерживает RTMP / RTMPS-ingest, который транс-мьюксится в WebRTC для low-latency egress и может быть теem-нут в HLS через отдельный downstream-сервис. Паттерн работает для любой связки SFU + live-энкодер, лишь бы мост-воркер можно было настроить на push RTMP в произвольный URL.

Сильная сторона – операционная нормальность: команда, у которой уже работает кластер live-энкодеров, не должна учить второй пакетёр. Цена – задержка: каждый RTMP-хоп добавляет буферизацию с обеих сторон (RTMP-отправитель издателя, RTMP-приёмник получателя), live-энкодер добавляет свою сегментирующую задержку, плеер HLS добавляет свой буфер. Реалистична цифра 6–12 секунд glass-to-glass; sub-5 секунд – тяжело.

Почему RTMP в 2026 году, когда протокол в целом умирает

RTMP – lingua franca ingest для live-энкодеров (см. RTMP в 2026: мёртвый протокол, бессмертный дефолт). Каждый live-энкодер последних 15 лет принимает RTMP, и сочетание TCP-доставки, предсказуемой обрамления и повсеместно доступных серверных парсеров делает его дорогой наименьшего сопротивления между кастомным мостом и любым коммерческим пакетёром. SRT (см. SRT подробно) – современная альтернатива для хопов через публичный интернет, и небольшое число мостов умеет пушить SRT вместо RTMP – но внутри ЦОД RTMP достаточно быстр и поддерживается везде. Мосту всё равно, что RTMP умирает в end-to-end-доставке; он использует его как локальный interconnect между двумя сервисами, и на этом сегменте возраст RTMP – не проблема.

Паттерн 5 – Управляемые мосты

Пятый паттерн – купить мост как SaaS. Вендоры, которые в 2026 поставляют настоящий end-to-end-мост WebRTC → HLS: LiveKit Cloud (Universal Egress с выходом в HLS / MP4 и RTMP-relay), Dolby OptiView (платформа Millicast с WHEP-доставкой и HLS-egress через партнёрские интеграции), Amazon Chime SDK Live Connector, Cloudflare Stream (с оговоркой ниже), 100ms, Vonage Video API, Daily, Twilio Programmable Video и небольшое число broadcast-grade специалистов вроде Norsk и Phenix. Оператор реализует WebRTC на стороне платформы и подписывает контракт, в который включён мост в HLS или DASH на стороне egress. Вендор скрывает всё то, что описано в Паттернах 2, 3 и 4.

Компромисс стандартный managed-service: оператор отгружает фичу за квартал вместо года, поминутная цена выше, чем у self-hosted-моста на собственном железе, гибкость макета – это то, что вендор позволяет в шаблонах (room composite у LiveKit – это HTML-template; у Daily – один из горстки фиксированных пресетов), а roadmap вендора управляет тем, когда появятся новые фичи. Большинство продуктов, выкатывающих мост в первом релизе конференций, стартуют отсюда; часть мигрирует в Паттерн 2 или 3, когда объёмы оправдывают инженерную работу по «вкорачиванию» моста.

Оговорка по Cloudflare Stream

Cloudflare Stream поддерживает WebRTC ingest и egress через WHIP и WHEP (см. WHIP – WebRTC-ingest, RFC 9725 и WHEP – HTTP-egress для WebRTC). По состоянию на середину 2026 года WebRTC-документация Cloudflare явно говорит, что WHIP и WHEP должны использоваться вместе – нельзя публиковать через WHIP и проигрывать через HLS или DASH на одном и том же Cloudflare-Stream-entry. Чтобы получить HLS-broadcast из WebRTC-потока, размещённого в Cloudflare, мост-воркер оператора должен подписаться через WHEP, перекодировать и пушить RTMP (или использовать Live-RTMP-ingest у Cloudflare) в Cloudflare-Stream-Live-вход, который уже произведёт HLS. Путь рабочий, но это не одношаговый вызов «WHIP-in, HLS-out» в API Cloudflare. Другие вендоры (LiveKit, Mux, AWS) сворачивают обе половины в единый управляемый конвейер; одна из причин, почему LiveKit Cloud в 2025–26 захватила непропорционально большую долю рынка WebRTC-мостов в HLS.

Как выбрать паттерн – продакшен-дерево решений

Честное дерево решений начинается с трёх вопросов в таком порядке.

  1. Broadcast-зрители – это фича или побочный эффект? Если основной режим продукта – конференции или телемедицина, а запись – compliance-копия, которую живая аудитория никогда не смотрит, верный ответ – Паттерн 1 (пер-трековая запись с офлайн-пост-процессингом). Мост – это батчевая задача. Ничего сложного не должно работать в реальном времени.
  2. Если broadcast-зрители – фича, их сотни или многие тысячи? Для сотен зрителей у оператора обычно хватает трафикового бюджета на прямую WebRTC-доставку в хвост (вариант с WHEP из Паттерна 5 или self-hosted WebRTC-egress), и путь HLS опционален. Для многих тысяч HLS становится обязательным, потому что WebRTC-кривая стоимости крутая – и мост обязан быть реалтаймовым конвейером, что подталкивает к Паттернам 2, 3, 4 или 5.
  3. Продукту нужен уникальный макет или достаточно одного из трёх-четырёх стандартных? Уникальный макет (кастомный брендинг, кастомные оверлеи, кастомные переходы) обычно означает Паттерн 3 (headless-браузер, HTML/CSS-шаблоны) – layout-работа уезжает в HTML, а не в медиаконвейер, и это самое дешёвое место для её сопровождения. Стандартные макеты при очень больших объёмах склоняют к Паттерну 2 (GStreamer-конвейер с compositor-элементом), который сильно дешевле на комнату, но негибок. Стандартные макеты при умеренном масштабе, которые команда не хочет сопровождать, – очевидный случай для Паттерна 5 (управляемый мост).

Расчётный пример с арифметикой. Допустим, продукт – это B2C live-shopping-платформа. В комнате один ведущий по WebRTC; broadcast-хвост – 30 000 зрителей по HLS. Каждый зритель смотрит 720p на 2500 kbps 45 минут шоу. Прямая WebRTC-доставка 30 000 зрителям по 2,5 Mbps дала бы 75 Gbps egress за всё шоу. За CDN-трафик по $0,005/ГБ это 75 Gbps × 2700 с ÷ 8 = 25 312 ГБ × $0,005 = $126 за шоу – но только при условии, что WebRTC-серверная ферма в принципе вытянет 75 Gbps, что предполагает существенный WebRTC-distribution-слой (каскадные SFU и регионы; см. WebRTC в масштабе). HLS-доставка того же контента через multi-CDN (см. Архитектура multi-CDN) потребляет те же 25 312 ГБ, но цена за ГБ для кэшируемых HLS-сегментов на этих объёмах – $0,002–$0,003, то есть около $63 за шоу. Стоимость CPU и упаковки моста – фиксированная добавка (Паттерны 2 или 3 – $1–$3 за комнато-час), которая нивелируется экономией уже после пары тысяч зрителей. Штраф по задержке – broadcast-зрители на 3–5 секунд позади ведущего – нормален для шоппинга; не нормален для аукциона. Выбор для шоппинга – Паттерн 2 или Паттерн 3 с LL-HLS; выбор для аукциона – Паттерн 5 с WHEP и без HLS-хопа вообще.

Рисунок 3. Бюджет задержки glass-to-glass для каждого паттерна моста, разбитый на семь стадий с заметной задержкой. Паттерн 1 пропущен – он даёт файл, а не живой поток; четыре живых паттерна попадают в диапазон 2–15 секунд, причём выбор LL-HLS против классического HLS даёт больший вклад, чем выбор паттерна.

Что реально работает в продакшене, по SFU

Пять основных open-source SFU имеют свою идиоматическую историю моста в 2026.

LiveKit поставляет Egress как отдельный воркер-бинарь, который реализует все четыре живых паттерна (Паттерны 2, 3, 4 и версию «Паттерна 5», когда запущен в LiveKit Cloud). Egress – самый opinionated из пятёрки: room composition – HTML-template, кодирование – GStreamer, HLS-выход – через hlssink с опциональными LL-HLS-частями, RTMP-выход – на downstream live-энкодеры или прямо в Twitch / YouTube. Сообщество стандартизировалось вокруг него.

mediasoup не поставляет мост в составе core-библиотеки. Паттерн – написать отдельный воркер на Node или Python, который вызывает transport.consume() на нужных треках, форвардит полученный RTP в GStreamer- или FFmpeg-процесс через обычный RTP и оставляет на нём композицию, кодирование и упаковку. Сообщество mediasoup поддерживает несколько референсных реализаций – в первую очередь mediasoup3-record-demo и пример записи Kurento mediasoup-demos. Продакшен-деплои обычно дополняют это внутренним layout-сервисом, который сопровождает сама компания.

Janus поставляет плагин RecordPlay для пер-трековой записи в .mjr и плагин Streaming для повторного broadcast. Несколько Janus-деплоев добавляют кастомный плагин или внешний процесс для HLS-работы; документация команды Meetecho подробно описывает механику записи, а janus-pp-rec – официальный пост-процессор.

Jitsi Videobridge использует Jibri (Jitsi Broadcasting Infrastructure) как мост. Jibri – по сути Паттерн 3: headless Chrome подключается к встрече как скрытый участник, захватывает экран, и либо пишет в MP4 для архива, либо пушит RTMP в downstream (обычно YouTube Live для community-деплоя Jitsi Meet). Jibri не делает HLS напрямую; HLS-шаг делает downstream.

Pion – это Go-библиотека, а не opinionated сервер, и мосты на Pion обычно кастомные: команда пишет подписку на комнату, композицию (часто через Go-биндинги к GStreamer через go-gst, как делает LiveKit) и путь кодирования и упаковки. Twitch и несколько других крупных WebRTC-деплоев используют Pion в продакшене с кастомными мост-стеками.

Ловушка: WebRTC bandwidth-estimator и тихое тротлирование моста

Тонкий режим отказа, в который рано или поздно попадает каждая команда – взаимодействие bandwidth-estimator у SFU (см. Оценка полосы в WebRTC) с мост-воркером. Мост подписывается на комнату как обычный участник, то есть SFU воспринимает его как реального subscriber-а и применяет к потоку для моста свою обычную логику congestion control – Google Congestion Control или transport-cc. Если связь моста к SFU кратковременно теряет пакеты (шумный intra-DC link, перегруженный TURN-relay), SFU понижает слой simulcast или SVC, форвардимый мосту, и HLS-выход моста молча проседает по разрешению. Участники в комнате на здоровых линках продолжают видеть высокое разрешение; broadcast-хвост видит 720p или 360p, которое ведущий никогда не отправлял в 360p.

Решение – явно подписать мост на самый высокий доступный слой и зафиксировать его, считая мост «VIP-subscriber», которого SFU никогда не понижает. LiveKit Egress, Jibri и большинство продакшен-мостов делают это по умолчанию; самописный мост Паттерна 2 требует явной настройки preferred-layer при подписке и отключения layer-downgrade для этого subscriber-а. У SFU все нужные ручки есть; режим отказа – забыть ими воспользоваться.

Где здесь Фора Софт

Фора Софт поставляет WebRTC-продукты с 2008 года и мосты WebRTC → HLS в продакшене во всех ключевых вертикалях: видеоконференции, телемедицина, e-learning и live-shopping. Телемедицинские деплои обычно требуют Паттерна 1 – compliance-копия каждого визита, в архив на S3, никогда не транслируется живьём – и инженерная работа в основном вокруг регуляторных метаданных (таймстемпы, идентификаторы участников, политика retention). Деплои в e-learning и live-shopping чаще требуют Паттерна 2 или Паттерна 3 – low-latency публичный HLS, который пускает в сессию гораздо большую пассивную аудиторию – и инженерная работа в основном про layout-шаблоны, тюнинг энкодера под целевую ABR-лестницу и операционную дисциплину держать stateful-парк мостов, который автоскейлится по активным комнатам. Урок из этих проектов: мост редко бывает той частью продукта, которую видит клиент, но стабильно бывает той частью, которая определяет, масштабируется ли запуск выше нескольких сотен одновременных зрителей.

Расчётный пример: бюджет задержки для LL-HLS-моста

Допустим, live-shopping-продукт работает на Паттерне 2 с LL-HLS-выходом. Ведущий публикует 1080p H.264 на 4 Mbps; мост в том же ЦОД, что и SFU; LL-HLS-конфигурация – 200-мс части и 6-секундный target segment; целевой буфер плеера – две части.

По стадиям:

  • Захват микрофона у спикера до энкодера: 30 мс.
  • Pacing H.264-энкодера у спикера (libwebrtc default): 30 мс.
  • Транзит RTP от спикера до SFU по публичному интернету: 40 мс.
  • Форвард SFU пакета мост-subscriber-у (intra-DC, sub-мс сеть плюс pacing SFU): 5 мс.
  • Декодер моста (один кадр при 30 fps): 33 мс.
  • Compositor (один кадр): 8 мс.
  • Энкодер моста в zero-latency (один кадр): 33 мс.
  • Pacкетёр закрывает 200-мс часть и пишет её в origin: 200 мс.
  • HTTP-распространение origin → CDN edge: 80 мс.
  • Загрузка по preload-hint у плеера и буфер из двух частей: 400 мс.

Сумма: 30 + 30 + 40 + 5 + 33 + 8 + 33 + 200 + 80 + 400 = 859 мс от захвата до первого декодируемого байта у зрителя, плюс собственный pacing декодера у зрителя и одно отображение: ещё ~100 мс. Итог glass-to-glass – 950 мс – 1,1 с при тугой конфигурации и хорошем плеере (hls.js с поддержкой LL-HLS; см. hls.js подробно). Удвоение буфера плеера до четырёх частей (типично для стабильности) выводит итог на 1,4–1,6 с. Классическая конфигурация HLS с 4-секундными сегментами и 3-сегментным буфером плеера даёт 14–16 с – нормально для продукта, где основной интерактив – чат, а ведущий естественно делает паузы под broadcast-хвост.

Смысл расписать бюджет: у каждой стадии есть число. Мост – не магия; это сумма известных стадийных задержек, и каждую можно тюнить в пределах спецификации.

Сводная таблица – пять паттернов рядом

ПаттернМесто композицииLive или batchТипичный glass-to-glassКастомные макетыСтоимость на комнату (относительная)Сложность для оператора
1. Пер-трековая записьНет (пер-трековые файлы)Batch (пост-процесс)Не live – файл позжеНет (только в пост-композиции)НизкаяНизкая
2. Server-side компонентМост-воркер (GStreamer)Live2–5 с LL-HLS, 8–15 с classicОграничены (изменения в коде)НизкаяВысокая
3. Headless-браузерМост-воркер (HTML/CSS)Live3–5 с LL-HLS, 8–15 с classicБезграничныСредняяСредняя
4. RTMP в live-энкодерМост + downstream-энкодерLive6–12 с типичноОграничены со стороны мостаНизкая на мосту; энкодер биллится отдельноСредняя (два сервиса)
5. Управляемый мост (SaaS)ВендорLive3–8 с типичноВендорские шаблоныСамая высокая поминутноСамая низкая

Ключевые выводы

  • Любой WebRTC-продукт рано или поздно нуждается в egress в HLS или DASH для пассивного хвоста; мост – стандартный ответ.
  • В продакшене работают пять паттернов; выбор по размеру аудитории, гибкости макета и допустимой задержке.
  • SFU специально не делает HLS сам – композиция и кодирование живут в отдельном воркере, подписанном на комнату.
  • LL-HLS через хорошо настроенный мост Паттерна 2 или 3 даёт 2–5 секунд glass-to-glass; классический HLS – 8–15 секунд.
  • Пиньте мост на максимальный слой – иначе broadcast-хвост тихо просядет по разрешению под congestion control у SFU.

Что прочитать дальше

CTA

  • Поговорить с инженером по стримингу – забронируйте 30-минутный scoping-call с архитектором Фора Софт.
  • Смотреть наши кейсы – WebRTC, телемедицина, live-shopping, e-learning.
  • Скачать decision sheet WebRTC → HLS – пять паттернов, бюджеты задержки и дерево решений на одном PDF: Скачать.

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.