
Привет, Хабр! Я Данил и я разработчик проекта Termidesk Assistant. На нашем проекте мы успешно используем технологию WebRTC, а еще ее используют такие технологические гиганты, как Google Meet, Microsoft Teams, Discord и многие другие.
Хотел бы поговорить о наболевшем, а именно о тех проблемах, с которыми я успел столкнуться, но почему мы все равно остановились на этой технологии. Возможно даже страница будет расширяться теми шишками, которые на меня упали по ходу движения через этот темный лес. Если вы планируете начать проект, который передает аудио и/или видео и ищите открытую технологию для него, ну, и для тех, кто просто интересуется и изучает этот стандарт, то это статья для вас.
Что же такое WebRTC?
WebRTC (Web Real-Time Communication) - открытый стандарт и набор технологий, обеспечивающий прямую (peer-to-peer) передачу аудио, видео и данных в реальном времени между браузерами и приложениями без необходимости установки плагинов или дополнительного ПО.
Минимальный клиент
Для примера давайте напишем базовый клиент на JavaScript и рассмотрим основные функции. Для этого переходите в наш репозиторий на GitFlic. Читайте код, клонируйте проект, запускайте, если есть желание, делайте форк и отправляйте запросы на слияние.
Кратко опишу имеющиеся ключевые функции и их роли:
-
navigator.mediaDevices.getUserMedia()
Захватывает поток с камеры и микрофона. Результат — MediaStream, который мы сразу выводим в <video id="localVideo"> и добавляем в RTCPeerConnection.
-
new RTCPeerConnection(rtcConfig)
Создаёт объект соединения, готовый обмениваться медиапотоками и данными. В конфигурации указываем STUN/TURN-серверы для поиска и пробивки NAT.
-
pc.addTrack(track, stream)
Добавляет каждую дорожку (video/audio) из локального потока в соединение, чтобы её можно было передать удалённой стороне.
-
pc.onicecandidate
Срабатывает при нахождении нового ICE-кандидата (IP-адреса/порта для пиров). Их нужно передать другому участнику через канал сигнализации.
-
pc.createOffer() / pc.createAnswer()
Создают SDP-оффер и SDP-ответ — описания возможностей кодеков, протоколов и сетевых каналов. Оффер идёт от инициатора, ответ — от принимающей стороны.
-
pc.setLocalDescription() / pc.setRemoteDescription()
Устанавливают локальное SDP и SDP от партнёра. Это фаза согласования (SDP-handshake).
-
pc.ontrack
Приходит событие, когда удалённая сторона добавляет дорожки. Полученный MediaStream выводим в <video id="remoteVideo">.
-
Сигнализация (sendSignal / onSignal)
WebRTC не включает механизм передачи офферов/ответов и кандидатов — это надо сделать самостоятельно (через WebSocket, HTTP-polling, любой сервер).
Этот шаблон — база для любых WebRTC-сценариев (пиринга, чатов, удалённого рабочего стола и т.д.). Дальше можно добавлять data-каналы, TURN-серверы, управление качеством и шифрование. Файл с кодом можете найти тут.
Если хотите собрать свой клиент-клиент, например, на ВМ, то придется создать сервер, который через websocket-каналы будет перегонять между клиентами данные для инициализации сессии. Код сервера можно найти тут. Это простой пример сервера, основанный на асинхронных aiohttp и asyncio.
По итогу мы получаем вот такую картину:

Не обращайте внимание, что картинка только под Remote Video, я тестировал на ВМ, камера занята хостом и транслируем как раз второму клиенту, что мы и видим - УСПЕХ!
Буду рад видеть ваши pull requests на репозитории. Давайте сделаем из него полноценный открытый видеочат.
С какими сложностями я столкнулся, работая с этой технологией
Ice-кандидаты
Ice-кандидат - это точка входа клиента, которая отправляется другому клиенту для подключения. Главная проблема в том, что если в браузере мы не инициируем устройства, то вместо ip-адреса ice-кандидат будет содержать в себе обфусцированное mDNS-имя типа 123febefbfh.local. Но мы живем в клиентоориентированном капитализме, а значит, клиент прав, а клиент хочет подключение без подтверждения девайсов, поэтому лечим так:
const c = event.candidate;
const o = c.toJSON();
o.candidate = o.candidate.replace(
/ ([0-9a-f-]+\.local) /,
` ${server_ip} `
);
Dummy-stream
Нельзя просто получать стрим в одну сторону.

Это двусторонняя технология, поэтому требуется двусторонняя SDP-сигнализация, то есть SDP-оффер должен содержать хотя бы одну медиасекцию. Многие браузеры завершают подключение, если нет исходящего потока. Решение - dummy-stream, вот как он выглядит в коде:
if (!constraints.audio && !constraints.video) {
console.log("No devices selected, returning dummy stream");
const dummy = new AudioContext().createMediaStreamDestination().stream;
dummy.getAudioTracks().forEach(t => t.enabled = false);
return dummy;
}
И это всё!
Альтернативные технологии
Разберем технологии, которые могли бы использоваться для архитектуры клиент-сервер-клиент
Таблица 1. Двусторонние технологии для архитектуры клиент-сервер-клиент
Технология |
Плюсы |
Минусы |
SIP + RTP/RTCP |
- Стабильный стандарт телефонии с десятилетиями опыта - Поддерживается большинством VoIP-оборудования (Asterisk, FreeSWITCH) - NAT traversal через SIP Extensions - Масштабируемость, поддержка аудио и видео |
- Безопасность (шифрование) чаще опциональна (для этого есть есть SRTP) - Сложная интеграция с браузерами: кодеки не всегда совпадают, нужен софт-клиент или WebRTC-шлюз |
XMPP + Jingle |
- Легко расширяется под разные задачи (чаты, файлы, звонки) - Экосистема для чатов, групп, ботов - Отдельный сервер сигнализации для масштабирования и фильтрации - Поддержка p2p звонков с медиапотоком (RTP) - p2p-звонки |
- Медиа-секция не строго стандартизована, возможны несовпадения кодеков - Нет нативной браузерной поддержки - ICE/TURN работает нестабильно - Шифрование не обязательно - Мало готовых решений из-за маленького комьюнити |
RTMP |
- Простой клиент-серверный протокол |
- Проприетарный - Поддержка прекращена Adobe - Нет p2p - Задержка высокая (500+ мс) - Односторонний поток - Работает только через Flash (помер ?) |
QUIC + Custom signaling |
- UDP из коробки - Встроенные технологии шифрования (замена TCP+TLS поверх UDP) - Сервер на Go |
- Нет стандарта p2p аудио/видео - Нет браузерных API для медиа - Нет NAT traversal - Нет совместимости между клиентами разных разработчиков - Поддерживается только Chromium |
Таблица 2. Односторонние технологии (поток в одну сторону, трансляция экрана)
Технология |
Плюсы |
Минусы |
HLS (HTTP Live Streaming) |
- Легко масштабируется - Использует HTTP — поддержка всеми браузерами |
- Высокая задержка (5–30 сек), хотя в 2019 было анонсировано Low Latency HLS - Обратная сторона масштабирования — браузерное распределение |
MPEG-DASH |
- Аналогичные плюсы HLS |
- Аналогичные минусы HLS - Меньшая поддержка, технология устарела (по моему скромному анализу) |
RTSP |
- Контроль потока: пауза, стоп - Поддержка временного доступа к файлам на сервере - перемотка назад |
- Нет поддержки браузерами - Специфичен для видеонаблюдения - Нет сжатия потока, возможна большая задержка |
Кастомный протокол через WebSocket + TCP/UDP |
- Можете гордиться собой - Полный контроль над потоком и легкий дебаг - Это кастом - можно реализовать под свои нужды |
- Изобретение велосипеда - Слабое или отсутствие сжатия, проще использовать готовое - Нужно учитывать шифрование (WSS, TLS) - Подходит только для больших озабоченным ИБ корпораций и госструктур |
Почему мы все-таки с WebRTC?
Несмотря на преимущества технологий сверху и описанные костыли еще выше, WebRTC побеждает и вот почему:
Peer-to-Peer соединение — сервер нужен только обмена данными соединения
Низкая задержка (~50–200 мс)
Автоматическая обработка NAT traversal
Шифрование по-умолчанию
Работает из коробки на всех браузерах
Помимо передачи аудио и видео трансляций есть встроенный функционал передачи файлов
WebRTC побеждает доступным функционалом, документацией, минимальной задержкой, кроссплатформенностью и кроссбраузерностью и возможностью p2p-соединения. Если эти особенности отобразить на диаграмме Эйлера, то для этой технологии конкурентов нет.

Комментарии (10)
apevzner
21.07.2025 13:48Почему мы все-таки с WebRTC?
А разве WebRTC - не единстванная p2p-технология, доступная в веб-бровсере?
Низкая задержка (~50–200 мс)
А сколько времени тратит WebRTC на установление прямого p2p соединения, включая NAT traversal?
rastop123
21.07.2025 13:48p2p в достоинствах это хорошо, но стоит учитывать что такой подход работает только при очень низком числе соединений, дальше только сервер (sfu и прочие технологии). И да даже в ситуации установки связи между двумя устройствами, когда действительно нужно соединение клиент-клиент это почти никогда не будет работать напрямую без turn серверов в публичных сетях, а это уже тоже не совсем p2p.
DanilKomyshev Автор
21.07.2025 13:48Есть такой минус, да, но я его в том числе и описываю
Поэтому нам сервер нужен, согласен, не чистый p2p, но он нужен, как и turn, разово, только для подключения, дальше его ресурсы уходят в ожидание
Для минимизации участия сервера до минимума, действительно, целесообразно переводить требуемый функционал типа файлообмен, чат и т.д. на p2p технологии
MAXH0
А как весь этот p2p работает в условиях непредсказуемо фильтрации пакетов?
DanilKomyshev Автор
А можно пример такой фильтрации? Не очень понимаю ситуацию
У нас рамках закрытой локальной сети все ок
MAXH0
https://habr.com/ru/companies/amnezia/articles/928378/
DanilKomyshev Автор
Ну, тут пример блокировок VPN
У нас же локальные сети, в которые даже пристальная забота нашего государства не заберётся)
CrazyHackGUT
Ну, об этом-то и речь.
Если пытаться мучать жопу в Интернетах с WebRTC, как оно все в этой плоскости начинает работать?
DanilKomyshev Автор
Ну, мне кажется, это проблема более глобальная, чем проблема только webrtc, ведь в таком случае ошибка не на стороне технологии, а на стороне провайдера, который исполняет законы
Просто это вопрос вообще не по теме, если начнется великий русский файерволл и белые списки, то хана не только p2p соединениям, а вообще всем из недоверенных источников