Pull to refresh

Comments 21

Спасибо большое за интересную статью. А вот не подскажите ли вы насколько сложно решается обратная задача — вещать с произвольного источника, скажем ffmpeg, прямо в браузер? Для этого обязательна вся эта обвязка с установкой соединения и т.д., или можно напрямую дать WebRTC в зубы ссылку на RTP поток принимать без посредников? (для простоты допустим что все происходит в одной локальной сети и нет никаких промежуточных CDN)
вещать с произвольного источника, скажем ffmpeg, прямо в браузер?
или можно напрямую дать WebRTC в зубы ссылку на RTP поток принимать без посредников?

Если смотреть на эту задачу с точки зрения сети, то получается так:

Допустим на одном компьютере 192.168.1.10 у вас ffmpeg и он умеет WebRTC (не знаю так ли это, не тестировали), но допустим, ffmpeg умеет вести себя как Chrome и является WebRTC-пиром.

Допустим на втором компьютере 192.168.1.11 установлен Chrome (WebRTC-браузер).

Чтобы «вещать прямо в браузер», вам нужно видеотрафик так или иначе передать с устройства 192.168.1.10 на 192.168.1.11 по TCP или UDP протоколу.
Тогда браузер сможет принять видеопоток, декодировать и отобразить в плеере и вещание состоится.

Чтобы передать трафик, нужно открыть как минимум 1 порт и там и там.
Допустим, передавать будем по UDP и открываем порты .10:3310 и .11:3311 соответственно.

Ок, порты забиндили. Теперь эти два устройства должны друг другу как-то сообщить о своих портах. И здесь два варианта:

  1. Использовать третье устройство — посредник, через которого можно обменяться информацией о портах.
  2. Сделать этим посредником условный ffmpeg.


После того, как устройства .10 и .11 обменялись портами, у них есть все необходимое для установки соединения и передачи трафика.

Т.е. ответ на вопрос — да, можно вещать напрямую из источника в браузер.

Для этого источник должен:
1) Поддерживать WebRTC-стек.
2) Выступать сигнальным сервером для обмена SDP (портами).
3) Кодировать видео один раз и тиражировать браузерам копии.

Фактически, ваш источник должен быть сервером, умеющим захватывать сырое видео с камеры, подцепленной к нему через USB или другой интерфейс.

Понятно что такое вещание будет нормально работать только внутри локальной сети, т.к. если потоков тиражируется много, то они просто не пролезут в глобальную сеть. Т.е. из локальной сети вы сможете вытащить ну 10 толстых потоков на 10 браузеров снаружи, и на этом все.

Поэтому для общего случая и для продакшена рабочий вариант — доставить поток на внешний сервер и оттуда этот поток уже распространять по браузерам. В локальной сети тоже самое, только сервер устанавливается локально.
Спасибо. Концептуально понятно как работает WebRTC-стек, в целом. А есть возможность в API браузера не использовать весь стек целиком, а отдельно настроить только те компоненты, которые непосредственно принимают RTP пакеты? Попробую уточнить, ипользуя аналогию с MPEG-DASH — это тоже стек нескольких протоколов и стандартов: HTTPS, MPD, MSE, ISOBMFF и т.д., но в конечной реализации никто не заставляет принимать сегменты по HTTPS и парсить .mpd файл. Вполне можно взять отдельно MSE и скармливать ему сегменты по WEB Sockets или генерировать их на лету. Можно ли выделить аналогичное подмножество в WebRTC со стороны браузера?
Вы в принципе не можете выдать ссылку на RTP-поток, он в другую сторону работает. Вы говорите источнику, на какой ip и на какой порт гнать RTP, а не на каком порту слушать.
Из этого и следует невозможность дать WebRTC в зубы ссылку — браузер открывает свои порты, и требует нормальной аутентификации и нормального шифрования. Поэтому вам требуется полноценный WebRTC стек.
Я не точно выразился. Я не имел ввиду ссылку буквально. Я имел ввиду информацию (типа SDP), где будет описано куда я сейчас буду вещать и в каком формате. То что вы описывает, это скорее RTSP. RTP — это просто меди пакеты с небольшим заголовком, так что их вполне можно вещать на источник на указанный порт (например по UDP), без установки сессии.
Но как я уже понял проблема даже не в этом, а в том что в WebRTC, поверх UDP и TCP, еще лежит SCTP — со своими каналами и т.д., а это уже нестандартный транспорт со всеми вытекающими…
А куда вы будете вещать? Вам нужен ip и порт клиентской машины, притом порт, на котором будет слушать браузер. Их вам нужно передать на источник каким-либо образом, так что именно этим и занимается WebRTC.
SCTP вообще ни при чем, его как-раз и можно опустить за ненадобностью.

Вообще, если есть ffmpeg в качестве источника, то проще воспользоваться hls или mpd. Один модуль для nginx, простая настройка, ну и плюс библиотка для mpd на клиенте.
WebRTC нужен, если критична маленькая задержка или требуется видео от пользователя.
А куда вы будете вещать?
Еще раз. Я сейчас не утверждаю что так устроен WebRTC, я рассуждаю гипотетически. Для того что бы вещать по RTP нужно только открыть порт на клиенте и вещать туда. В конце концов, можно жестко выставить порт на клиенте и источнике (я не собираюсь это делать на практике, мне просто хотелось бы разобрать стек WebRTC по косточкам).
SCTP вообще ни при чем, его как-раз и можно опустить за ненадобностью.
А вот это очень интересно. Просто у меня сложилось ощущение что SCTP там прибит гвоздями и без него никак. Т.е. вы хотите сказать что можно использовать любой другой транспорт? А каким образом и где это настраивается, вы могли бы подсказать?
Вообще, если есть ffmpeg в качестве источника, то проще воспользоваться hls или mpd. Один модуль для nginx, простая настройка, ну и плюс библиотка для mpd на клиенте.
WebRTC нужен, если критична маленькая задержка или требуется видео от пользователя.
В моем случае не проще, т.к.:
1. MSE, с некоторого времени, требует что бы в потоке границы сегментов были строго по IDR, а у меня в потоках IDR может не быть по несколько десятков минут.
2. Мои потоки запросто могут «подрываться», а из-за MSE, восстановление возможно только со следущего IDR.
Короче у меня вещание идет не с «жесткой» заранее приготовленной копии, а с реальных камер или эфирных кабелей.
Просто у меня сложилось ощущение что SCTP там прибит гвоздями и без него никак. Т.е. вы хотите сказать что можно использовать любой другой транспорт? А каким образом и где это настраивается, вы могли бы подсказать?

В WebRTC SCTP используется не для видео/аудио, а для передачи данных. Видео же гонится по обычному UDP или TCP.

просто хотелось бы разобрать стек WebRTC по косточкам

Я писал свой WebRTC сервер, для видео/аудио, могу вкратце пояснить:
1. Сначала обмениваемся SDP друг с другом, поясняем, кто какие кодеки умеет, какие будут использоваться логины/пароли для ICE
2. Обмениваемся ip и портами, как локальными, так и внешними — STUN/TURN.
3. После чего, начинаем посылать ICE пакеты друг другу по полученным адресам
4. Как только будет коннект по каким-либо ip, начинаем передачу ключей шифрования для трафика.
5. После чего берем обычные RTP пакеты, шифруем их SRTP полученными в предыдущем пункте ключами, и отправляем по ip/port, полученными в результате ICE-коннекта из пункта 3.

Все это вполне реализуемо самому. Если не хочется заморачиваться — берем чужой медиасервер (например kurento), отправляем на него RTP-поток, забираем с него по WebRTC.
Спасибо вам большое за развернутый ответ. Теперь стало еще понятнее, но осталось еще несколько вопросов:
SDP это протокол описания, а как происходит сам обмен?
Как я понимаю, ICE — Interactive Connectivity Establishment — это протокол или просто некая стандартизированная процедура?
Если я всегда нахожусь в локальной сети, могу ли я избежать работы с STUN/TURN серверами или это не обойти и это обязательно?
Как вы обмениваетесь SDP — это строго на ваше усмотрение, в WebRTC нет механизма обмена SDP.
ICE — это протокол.
Если вы всегда в локальной сети, то STUN необязателен. TURN тем более. Даже если вы укажете STUN сервера, то коннект пойдет через локальные ip адреса, у них приоритет выше.
Спасибо вам огромное за исчерпывающие ответы.
Проблему с HLS можно частично решить уменьшением размера чанка, обычно он 10 сек, от того и загрузка потока для первого да и для остальных пользователей требует больше времени. Если ваш софт позволяет, уменьшите его до 5 сек например и сравните.

Скорось подключения вырастит, но неравномернось загрузки также возрастет. Уменьшая размер чанка вы потеряете на ожидании каждого следущего, т. к. в дело вступит задержка round-trip.

С WebRTC источником проблема в том, что вы не можете контролировать генерацию ключевых кадров в стриме, а HLS чанки режутся по ключевым кадрам.

Поэтому мы не можем задать точное время чанка. Мы можем указать, например «не менее 2 секунд». В этом случае мы дождемся от Хрома по WebRTC ключевого кадра, проверим прошло ли две секунды, и если прошло, то нарежем чанк.

Мы не можем принудить браузер высылать ключевые фреймы в жестком интервале 2 секунды. Но можем каждые две секунды просить у браузера ключевой кадр через PLI фидбэк, и для этого есть специальная настройка. Браузер может дать, а может и не дать по запросу. Чаще дает.

Поэтому, в общем случае, без транскодинга, мы можем управлять только нижней границей длины HLS чанка.

В любом случае, уменьшение длины чанков не спасает внутри CDN, а с одним сервером такой проблемы нет. Вне зависимости от размера чанков, даже если бы мы транскодировали поток и нарезали чанки по 1 секунде, в CDN между запросом плей листа и доставкой потока с Origin-сервера пройдет время и плеер перестанет играть поток. Поэтому пока рабочий вариант — только прелоадер первому зрителю.
можем каждые две секунды просить у браузера ключевой кадр через PLI фидбэк

А если каждые две секунды сигнализировать о потере кадра, то браузер начнет понижать битрейт, понижать размер картинки… Короче говоря, для двухсекундных чанков нужен транскодинг.
должно пройти какое-то время для того чтобы заказать этот стрим с Origin сервера, получить его на Edge и приступить к HLS нарезке

не очень понятно, зачем нарезать hls на edge серверах, это же оверхед – будет одна и та же обработка на разных серверах

почему не нарезать на одном сервере (источнике), а edge использовать как прокси, которые будут забирать чанки с этого одного сервера, заодно и не надо будет заказывать поток, можно его проксировать сразу при запросе, и проблем с фризами не будет

В данном случае HLS нарезается только на Edge серверах, а между Origin и Edge бегает WebRTC по UDP, что дает меньшую задержку по сравнению с проксированием HLS. Поэтому нет и оверхеда: Origin работает только на публикацию, Edge - только на раздачу зрителям. Можно еще и транскодирование вынести на отдельные железные сервера (транскодинг желателен для WebRTC стримов, чтобы выровнять FPS и keyframe интервал, HLS плееры к этим параметрам критичны, особенно native в Safari.

между Origin и Edge бегает WebRTC по UDP

а если источник в RTMP? или у вас только WebRTC?

что дает меньшую задержку по сравнению с проксированием HLS

у HLS и так задержка минимум несколько секунд, лишние 100-200мс на проксирование я думаю погоды не сделают

Поэтому нет и оверхеда: Origin работает только на публикацию, Edge — только на раздачу зрителям

Как я понимаю, у вас на Edge ведь горизонтальное масштабирование, то есть разные зрители одного стрима могут быть на разных Edge серверах?
Я про этот оверхэд и говорил, в плане архитектуры – что у вас одинаковая нарезка делается в нескольких местах, а можно сделать в одном.

Или у вас один стрим идет только на один Edge сервер, и все его зрители сидят на этом сервере? Тогда вопрос снимается.

а если источник в RTMP? или у вас только WebRTC?

внутри CDN только WebRTC или SRT, от источника публикации это не зависит

у HLS и так задержка минимум несколько секунд

у Low Latency HLS (который у нас уже реализован, кстати) задержка около трех секунд, что сопоставимо с RTMP и WebRTC over TCP

Как я понимаю, у вас на Edge ведь горизонтальное масштабирование, то есть разные зрители одного стрима могут быть на разных Edge серверах?

да, это так.

но эта архитектура затачивалась под WebRTC зрителей в первую очередь. как правило, мы рекомендуем выделять в CDN отдельные Edge сервера под WebRTC и HLS зрителей, это позволяет избежать лишнего транскодинга аудио на Edge.

и мы даем не готовое решение, а конструктор. т.е. разработчик может выделить HLS Edge, и уже с него проксировать.

внутри CDN только WebRTC или SRT, от источника публикации это не зависит

а качество не страдает от транскодинга? я когда игрался с WebRTC и Pion у меня сложилось впечатление, что он не заточен под поток высокого качества и там норма выпадение кадров и понижение качества
а CDN же на проверенных линиях, там по идее внутри не должно быть плавающей скорости, нестабильного канала и прочего, для чего делался WebRTC

у Low Latency HLS (который у нас уже реализован, кстати) задержка около трех секунд, что сопоставимо с RTMP и WebRTC over TCP

ну вот, если задержка на проксирование 100 мс (и это большая, она скорее меньше будет), то от 3 сек это будет 3%, не думаю что об этом стоит беспокоится, и насколько понимаю 3 сек это в идеальном варианте, на практике у LL-HLS и 5-10 сек спокойно может быть
и у UDP тоже ведь есть задержка, хотя и меньше, то есть в итоге разница будет еще меньше, порядка 1%

и мы даем не готовое решение, а конструктор. т.е. разработчик может выделить HLS Edge, и уже с него проксировать.

ну я просто говорю, что проблему первого зрителя можно было решить проще, сделав одно место где готовится HLS, вместо вынесения этого на Edge, заодного и нагрузка бы снизилась на Edge
Sign up to leave a comment.