Publish и Play

Существует две основных функции работы WebRTC на стороне сервера в области потокового видео: публикация и воспроизведение. В случае публикации видеопоток захватывается с вебкамеры и двигается от браузера к серверу. В случае воспроизведения, поток двигается в обратном направлении — от сервера к браузеру, декодируется и воспроизводится в браузерном HTML5 <video> элементе на экране устройства.

Stream_to_server_WebRTC_TCP_NACK_RTT_REMB_browser

UDP и TCP

Видео может двигаться по двум транспортным протоколам: TCP или UDP. В случае UDP активно работают RTCP фидбеки NACK, которые несут информацию о потерянных пакетах, в связи с чем, определение ухудшения UDP канала является достаточно простой задачей и сводится к подсчету NACK (Negative ACK) для определения качества. Чем больше фидбеков NACK и PLI (Picture Loss Indicator), тем больше реальных потерь и тем хуже качество канала

NACK_Stream_to_server_WebRTC_TCP_RTT_REMB_browser

TCP без NACK

В данной статье нас будет больше интересовать протокол TCP. При использовании WebRTC через TCP, RTCP-фидбеки NACK не отправляются, а если и отправляются, то не отражают реальной картины по потерям, и выполнить определение качества канала по фидбекам не представляется возможным. Как известно, TCP является транспортным протоколом с гарантированной доставкой. По этой причине, в случае ухудшения канала, пакеты, находящиеся в сети, будут досылаться на уровне транспортного протокола. Рано или поздно они будут доставлены, но на эти потери не будет сгенерирован NACK, т.к. потерь по факту не было. Пакеты в итоге дойдут с запозданием. Опоздавшие пакеты просто не соберутся в видеофреймы и будут сброшены депакетизатором, в результате чего пользователь увидит примерно такую картинку, полную артефактов:

Video_artefact_WebRTC_TCP_RTT_REMB_browser

По фидбэкам будет все хорошо, но на картинке будут артефакты. Ниже представлены скриншоты трафика Wireshark, которые иллюстрируют поведение публикуемого стрима на зажатых TCP и UDP каналах, а также скриншоты статистики Google Chrome. На скриншотах видно, что в случае TCP не растет метрика NACK в отличии от UDP несмотря на то, что с каналом все очень плохо.

TCP

chrome_tcp_WebRTC_TCP_RTT_REMB_browser

UDP

NACK_UDP_WebRTC_TCP_NACK_RTT_REMB_browser

chrome_udp_WebRTC_TCP_RTT_REMB_browser

А зачем вообще стримить по TCP если есть UDP

Резонный вопрос. Ответ: для проталкивания больших разрешений через канал. Например при стриминге VR (Virtual Reality) разрешения могут начинаться с 4k. Протолкнуть поток такого разрешения и битрейта около 10 Mbps в обычный канал без потерь не представляется возможным, сервер выплевывает UDP пакеты и они начинают пачками теряться в сети, потом досылаться, и т.д. Большие сбросы видеопакетов портят видео, и в конечном итоге с качеством становится все плохо. По этой причине для сетей общего назначения и высоких разрешений Full HD, 4k, для доставки видео используется WebRTC через TCP чтобы исключить сетевые потери пакетов ценой некоторого увеличения коммуникационной задержки.

RTT для определения качества канала

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

Ниже иллюстрация зависимости качества канала от RTT по версии проекта callstat

Depending_on_channel_quality_RTT_RTSP_WebRTC_TCP_REMB_browser

Решение на REMB

Мы решили подойти к этой проблеме немного с другой стороны. На стороне сервера работает REMB, который подсчитывает входящий битрейт для всех входящих потоков, вычисляет его отклонение от средней и в случае большого разброса, предлагает браузеру понизить битрейт, отправляя специальные REMB-команды по протоколу RTCP. Браузер получает такое сообщение и снижает битрейт видео энкодера для рекомендуемых значений — так работает защита от перегрузки канала и деградации входящих потоков. Таким образом на стороне сервера уже был реализован механизм подсчета битрейта. Усреднение и определение разброса реализовано через фильтр Калмана. Это позволяет снимать актуальный битрейт в любой момент времени с высокой точностью и фильтровать сильные отклонения.

REMB_WebRTC_TCP_NACK_RTT_browser

У читателя наверняка возникнет вопрос — “Что даст знание битрейта, который видит сервер на входящем в него потоке?”. Это даст понимание ровно того, что на сервер заходит видео с битрейтом, значение которого удалось определить. Чтобы оценить качество канала потребуется еще одна компонента.

Исходящий битрейт и почему он важен

Статистика публикующего WebRTC потока показывает с каким битрейтом видеопоток выходит из браузера. Как в бородатом анекдоте: Админ, проверяя автомат: «С моей стороны пули вылетели. Проблемы на вашей стороне..». Идея проверки качества канала заключается в сравнении двух битрейтов: 1) битрейт, который отправляет браузер 2) битрейт, который реально получает сервер.

Админ выпускает пули и подсчитывает скорость их вылета у себя. Сервер подсчитывает скорость их получения у себя. Есть еще один участник этого мероприятия, TCP — это супергерой, который находится посередине между админом и сервером и может замедлять пули случайным образом. Например, может затормозить 10 случайных пуль из ста на 2 секунды, а потом позволит им снова лететь. Вот такая Матрица.

Admin_tcp_server_WebRTC_NACK_RTT_REMB_browser

На стороне браузера мы берем актуальный битрейт из статистики WebRTC, далее сглаживаем график фильтром Калмана в JavaScript реализации и на выходе получаем сглаженную версию клиентского браузерного битрейта. Теперь мы имеем практически все необходимое: клиентский битрейт говорит нам как уходит трафик из браузера, а серверный битрейт рассказывает, как сервер этот трафик видит и с каким битрейтом получает. Очевидно, если клиентский битрейт остается высоким, а серверный битрейт начинает проседать по отношению к клиентскому, это означает что не все “пули долетели” и сервер фактически не видит часть трафика, который был ему направлен. На основании этого делаем вывод, что с каналом что-то не так и пора переключать индикатор в красный цвет.

Еще не все

Графики коррелируют, но немного сдвинуты во времени друг относительно друга. Для полной корреляции необходимо совместить графики во времени чтобы сравнивать клиентский и серверный битрейт в одну и ту же точку времени на исторических данных. Выглядит рассинхрон примерно так:

Data_out_of_sync_WebRTC_TCP_NACK_RTT_REMB_browser

А так выглядит синхронизированный по времени график.

Time_synchronized_chart_WebRTC_TCP_NACK_RTT_REMB_browser

Тестируем

Дело за малым, осталось протестировать. Публикуем видеопоток, открываем и смотрим график публикуемых битрейтов: на стороне браузера и на стороне сервера. По графикам видим практически идеальное совпадение. Индикатор так и называется PERFECT.

PERFECT_indicator_WebRTC_TCP_NACK_RTT_REMB_browser

Далее начинаем портить канал. Для этого можно использовать такие бесплатные инструменты «winShaper» на Windows или «Network Link Conditioner» на MacOS. Они позволяют зажать канал до установленного значения. Например, если мы знаем, что поток 640×480 может разогнаться до 1Mbps, зажмем его до 300 kbs. При этом помним, что работаем с TCP. Проверяем результат теста — на графиках обратная корреляция и индикатор падает в BAD. Действительно, браузер продолжает высылать данные и даже наращивает битрейт, пытаясь протолкнуть в сеть новую порцию трафика. Эти данные оседают в сети в виде ретрансмитов и не доходят до сервера, в результате сервер показывает обратную картину и говорит, что битрейт, который он видит упал. Действительно BAD.

Bad_indicator_WebRTC_TCP_NACK_RTT_REMB_browser

Мы провели достаточно много тестов, которые показывают корректную работу индикатора. В итоге получилась фича, которая позволяет качественно и оперативно информировать пользователя о проблемах с каналом как для публикации потока, так и для воспроизведения (работает по тому же принципу). Да, ради этой зелено-красной лампочки PERFECT-BAD мы и городили весь этот огород. Но как показывает практика, этот индикатор очень важен и его отсутствие и непонимание текущего статуса может сильно испортить жизнь рядовому пользователю сервиса видеостриминга через WebRTC.

Ссылки

Документация по контролю качества канала при публикации и воспроизведении

REMB

NACK