Индикатор качества канала серверного webrtc через tcp

Структура CDN

Сервер в CDN может выполнять одну из следующих ролей:

  • Origin — сервер, предназначенный для публикации медиапотоков. Раздает потоки другим серверам, может раздавать и подписчикам.
  • Transcoder — сервер, выделенный для транскодирования потоков. Забирает потоки с Origin серверов и раздает транскодированные потоки на Edge. С этой ролью мы разберемся в следующей части.
  • Edge — сервер, предназначенный для раздачи потоков подписчикам. Забирает потоки с Origin или Transcoder серверов, не раздает потоки другим серверам CDN.

На Origin сервер можно публиковать WebRTC и RTMP потоки, либо захватывать потоки с других источников по RTMP, RTSP и другими возможными способами.

Подписчики могут играть потоки с Edge серверов по WebRTC, RTMP, RTSP, HLS

Между серверами CDN желательно передавать потоки по WebRTC, для снижения задержки.

Статическая CDN полностью описывается на этапе конфигурирования. По сути, настройка статической CDN похожа на настройку балансировщика нагрузки: в настройках сервера-источника потоков перечисляются все приемники.

Например, у нас есть Origin сервер во Франкфурте, один Edge в Нью-Йорке и один в Сингапуре

В этом случае Origin настраивается примерно так:

Вот и первая проблема статической CDN: для того, чтобы добавить в такую CDN новый Edge сервер, или вывести сервер из CDN, требуется изменение настроек и перезапуск всех Origin серверов.

Потоки, опубликованные на Origin, транслируются на все перечисленные в настройках Edge серверы. Решение о том, к какому из Edge серверов подключится подписчик, также принимается на Origin сервере. Вот и вторая проблема: если зрителей нет или очень мало, например, в Сингапуре ранний вечер, а в Нью-Йорке глубокая ночь, потоки все равно транслируются на Edge 1. Трафик расходуется вхолостую, и совсем не бесплатно.

Эти две проблемы может решить динамическая CDN.

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

В идеале, в настройках должно быть достаточно указать точку входа, сервер, с которого начинается CDN. К этой точке входа каждый сервер при запуске должен отправить запрос и получить в ответ список узлов CDN и список опубликованных потоков. Если точка входа недоступна, сервер должен ожидать сообщений от других серверов.

Любые изменения своего состояния сервер должен рассылать другим серверам в CDN.

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

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

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

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

Решение — WebRTC и Janus

Приняли решение использовать браузерную платформу для peer-to-peer видеосвязи WebRTC. Она отвечает за установку соединения, кодирование и декодирование потоков, синхронизацию дорожек и контроль качества с обработкой сетевых глюков. Со своей стороны мы должны обеспечить считывание потоков с камеры и микрофона, отрисовку видео, управление соединением, установку WebRTC-подключения и передачу ему потоков, а также передачу сигнальных сообщений между клиентами для установки соединения (сам WebRTC описывает только формат данных, но не механизм их передачи). В случае, если клиенты находятся за NAT, WebRTC подключает STUN-серверы, если это не помогает, TURN-серверы.

Обычного p2p соединения нам недостаточно, ведь мы хотим записывать уроки для дальнейшего анализа в случае жалоб. Поэтому мы отправляем потоки WebRTC через ретранслятор Janus Gateway от Meetecho. В результате клиенты не знают адресов друг друга, видя только адрес сервера Janus; он же выполняет и функции сигнального сервера. Janus обладает множеством нужных нам фич: автоматически переходит в TCP, если у клиента заблокирован UDP; умеет записывать потоки и UDP, и TCP; масштабируется; есть даже встроенный плагин для эхо-тестов. В случае необходимости автоматически подключаются STUN и TURN серверы от Twilio.

Летом 2017-го года у нас работало два сервера Janus плюс дополнительный сервер для обработки записанных сырых файлов аудио и видео, чтобы не занимать процессоры основных. При подключении серверы Janus выбирались по принципу чет-нечет (номер соединения). На тот момент этого хватало, по нашим ощущениям давало примерно четырехкратный запас прочности, процент внедрения составил около 80. При этом цена сократилась до ~2 рублей за урок, плюс разработка и поддержка.

Тестируем

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

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

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

Объединение серверов в сеть обработки контента CDN

Один сервер имеет как правило ограниченное количество ресурсов. Поэтому для крупных онлайн-трансляций, где счет зрителей идет на тысячи и десятки тысяч, необходимо масштабирование. Несколько серверов WCS могут быть объединены в одну сеть доставки контента CDN. Внутри CDN будет работать через WebRTC для сохранения низкой задержки при стриминге.

Сервер может быть сконфигурирован в одной из следующих ролей: Origin, Edge, Transcoder. Серверы типа Origin — принимают трафик и раздают его на краевые узлы Edge-серверы, отвечающие за доставку потока зрителям. При необходимости подготовить поток в нескольких разрешениях, в схему включаются Transcoder-узлы, которые берут на себя ресурсозатратную миссию по транскодированию потоков.

«Я достойна большего!»

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

Количество подписчиков vCPUs RAM, Gb Трафик, TB Пример использования
до 200 4 8 5 Система видеонаблюдения
до 500 8 16 6 Вебинары
до 1000 16 64 9 Видеочат
до 2000 20 96 10 Стриминг HD видео

Если планируется дальнейший рост, придется развернуть CDN из расчета 1 Edge сервер на 2000 подписчиков. Предположим, нам требуется раздавать HD видео, планируемое число зрителей 10000. В этом случае потребуется 2 Origin сервера для публикации и 5 Edge серверов для просмотра.

Пример настройки:

CDN также может быть полезной, если подписчики распределены географически, например, наши потенциальные зрители проживают в Европе и Америке.

Пример настройки:

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

Пример настройки:

Для транскодирования, как мы выяснили во время теста, важно количество процессорных ядер. Из линейки конфигураций CPU-optimized больше всего подходит самая дорогая 32 vCPU, 64 Gb RAM

При этом в других линейках близкие по количеству CPU конфигурации с большим объемом памяти могут быть существенно дороже. К сожалению, сэкономить на транскодерах не получится: поскольку видео кодируется покадрово, памяти должно хватать под все картинки, а процессоров под обработку всех потоков.

При развертывании CDN, пригодится одновременное создание нескольких серверов одной и той же конфигурации. Однако, для географически распределенной CDN однотипные Edge и Transcoder серверы нужно будет разместить в разных датацентрах.

Решение на REMB

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

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

Что дальше

Стабилизация нашей платформы Vimbox — один из главных проектов компании на 2019 год. У нас большие надежды на то, что удастся сохранить динамику и больше не видеть видеосвязь в топе жалоб. Мы понимаем, что значительная часть этих жалоб связана с лагами компьютеров и интернета пользователей, но мы должны определить эту часть и решить все остальное. Все остальное — техническая проблема, кажется, мы должны уметь с ней справляться.

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

  1. сравнить видео через Janus с обычным p2p в боевых условиях. Этот эксперимент уже проведен, никакой статистически значимой разницы между нашим решением и p2p не обнаружено;
  2. поставим (дорогие) сервисы от компаний, зарабатывающих исключительно на решениях в области видеосвязи, и сравним количество негатива от них с имеющимся.

Эти два эксперимента позволят нам определить достижимую цель и сконцентрироваться на ней.

Кроме того, есть ряд задач, решаемых в рабочем порядке:

  • создаем техническую метрику качества связи вместо субъективных отзывов;
  • делаем более подробные логи сессий, чтобы точнее анализировать случающиеся сбои, понимать, когда и где именно они произошли, какие на первый взгляд не связанные события имели место в этот момент;
  • готовим автоматический тест качества связи перед уроком, а также дадим возможность клиенту вручную протестировать связь, чтобы уменьшить количество негатива, вызванного его железом и каналом;
  • разработаем и будем проводить больше нагрузочных тестов видеосвязи в плохих условиях, с переменной потерей пакетов и т. д.;
  • меняем поведение серверов в случае проблем для повышения отказоустойчивости;
  • будем предупреждать пользователя, если у него что-то не так вообще со связью, как это делает тот же «Скайп», чтобы он понимал, что проблема на его стороне.

С апреля направление видеосвязи становится полноценным отдельным проектом внутри Skyeng, занимающимся собственным продуктом, не просто частью Vimbox. А это значит, что мы начинаем искать людей на работу с видео в режиме фултайм. Ну и как всегда ищем много хороших людей.

Ну и, конечно, продолжаем активно общаться с людьми и компаниями, работающими с видеосвязью. Если вы хотите обменяться с нами опытом — мы будем рады! Комментируйте, связывайтесь — ответим всем.

Развертывание

Выбираем характеристики севера и тарифный план. По умолчанию, DO предложит нам что-нибудь из среднего сегмента, но нас интересует минимальная стоимость

Выбираем регион размещения датацентра, например, Франкфурт

Выбираем способ аутентификации, например, одноразовый пароль

Указываем количество серверов (пока нас интересует один сервер) и даем нашему серверу имя. Это имя будет записано, в том числе, в /etc/hostname

Нажимаем «Create droplet»

После создания сервер автоматически запустится. Можно подключиться к нему по SSH и, если был в качестве способа аутентификации был выбран одноразовый пароль, сменить пароль. В консоль будет выведено краткое описание Flashphoner WebCallServer со ссылками на документацию

Новое направление берется за работу

Команда выглядит примерно так:

  • Руководитель направления, он же основной разработчик.
  • QA помогают тестировать изменения, ищут новые способы создания нестабильных условий для связи, сообщают о проблемах с линии фронта.
  • Аналитик постоянно ищет разные корреляции в технических данных, улучшает анализ фидбека пользователей, проверяет результаты экспериментов.
  • Продакт-менеджер помогает с общим направлением и выделением ресурсов для экспериментов.
  • С самим программированием и смежными задачами часто помогает второй разработчик.

Для начала настроили относительно надежную метрику, которая отслеживала изменения оценки качества связи (среднее по дням, неделям, месяцам). На тот момент это были оценки от учителей, в дальнейшем к ним добавили оценки от студентов. Дальше стали строить гипотезы, что работает не так, исправлять и смотреть на изменения в динамике. Пошли по низковисящим фруктам: например, заменили кодек vp8 на vp9, показатели улучшились. Пробовали играться с настройками Janus, проводить прочие эксперименты – в большинстве случаев ни к чему не приводившие.

На втором этапе появилась гипотеза: WebRTC – решение peer-to-peer, а мы используем сервер посередине. Быть может, проблема кроется здесь? Начали копать и нашли здесь пока наиболее значительное улучшение.

В тот момент сервер из пула выбирался по довольно тупому алгоритму: у каждого был свой «вес», зависящий от канала и мощности, и мы старались отправить пользователя на тот, где «вес» больше, не обращая внимание на то, где географически находится пользователь. В результате учитель из Питера мог общаться с учеником из Сибири через Москву, а не через наш Janus-сервер в СПб

Алгоритм переделали: теперь, когда пользователь открывает нашу платформу, мы с помощью Ajax собираем пинги от него до всех серверов. При установке связи мы выбираем пару пингов (учитель-сервер и ученик-сервер) с наименьшей суммой. Меньше пинг – меньше сетевое расстояние до сервера; меньше расстояние — ниже вероятность потерять пакеты; потеря пакетов — самый большой отрицательный фактор в видеосвязи. Доля негатива за три месяца упала в два раза (справедливости ради, в это время проводились и другие эксперименты, но этот почти наверняка повлиял больше всего).

Недавно мы обнаружили еще одну неочевидную, но, судя по всему, важную вещь: вместо одного мощного Janus-сервера на толстом канале лучше два попроще с пропускной способностью пожиже. Выяснилось это после того, как мы купили именно мощные машины в надежде запихнуть туда как можно больше комнат (сеансов связи) одновременно. У серверов есть лимит пропускной способности, который мы можем точно переводить в количество комнат — мы знаем, сколько можно открыть, например, на 300 мбит/с. Как только на сервере открыто слишком много комнат — мы перестаем выбирать его для новых занятий, пока нагрузка не снизится. Идея была в том, что, купив мощную машину, мы загрузим канал до него по максимуму, чтобы в итоге упираться в процессор и память, а не в пропускную способность. Но выяснилось, что после определенного количества открытых комнат (420), несмотря на то что загрузка процессора, памяти и диска еще очень далека от лимитов, в техподдержку начинает прилетать негатив. Судя по всему, что-то становится хуже внутри Janus, возможно, там тоже есть какие-то ограничения. Стали экспериментировать, снизили лимит пропускной способности с 300 до 200 мбит/с, проблемы ушли. Теперь купили сразу три новых сервера с невысокими лимитами и характеристиками, думаем, что это приведет к стабильному улучшению качества связи. Разбираться, в чем там было дело, мы, конечно, не стали, костыли — наше все. В свое оправдание скажем, что в тот момент надо было максимально быстро решить насущную проблему, а не сделать это красиво; к тому же Janus для нас — черный ящик, написанный на C, копаться с ним очень дорого.

Ну и в процессе мы:

  • обновили все зависимости, которые можно было обновить, как на сервере, так и на клиенте (это тоже были эксперименты, следили за результатом);
  • починили все выявленные баги, касавшиеся конкретных случаев, например, когда связь падала и не восстанавливалась автоматически;
  • провели массу встреч с компаниями, работающими в области видеосвязи и знакомыми с нашими проблемами: стримящими игры, устраивающими вебинары; опробовали все, что нам показалось полезным;
  • провели техническое ревью железа и качества связи у учителей, от которых исходило больше всего жалоб.

Проведенные эксперименты и последовавшие за ними изменения позволили снизить недовольство связью среди преподавателей с 7,1% в январе 2018 до 2,5% в январе 2019.

Ретрансляции потоков

Ретрансляция также является вариантом манипуляции над входящими на сервер стримами и заключается в принудительной передаче стрима на сторонний сервер. Синонимом ретрансляции являются такие слова как: републикация, пуш, инжект.

Ретрансляция может осуществляться по одному из следующих протоколов: WebRTC, RTMP, SIP/RTP. В таблице показано направление, по которому может быть ретранслирован поток.

WebRTC RTMP SIP/RTP
WCS RTMP server WCS SIP server

Ретрансляция WebRTC

Поток может быть ретранслирован на другой WCS-сервер если по каким-то причинам требуется сделать поток доступным на другом сервере. Ретрансляция производится через REST API методом /push. При поступлении такого REST-запроса, WCS подключается к указанному серверу и публикует на него поток сервер-сервер. После этого поток становится доступен для воспроизведения на другой машине.

— используемый REST-метод.

Ретрансляция RTMP

Как и в случае с ретрансляцией по WebRTC, возможна ретрансляция и по RTMP а другой сервер. Разница будет лишь в протоколе ретрансляции. RTMP-ретрансляция также выполняется через /push и позволяет передать поток как на сторонние RTMP серверы, так и на сервисы, поддерживающие RTMP Ingest: Youtube, Facebook streaming, и т.д. Таким образом, WebRTC стрим может быть ретранслирован в RTMP. С тем же успехом в RTMP можно ретранслировать любой другой стрим входящий на сервер, например RTSP или VOD.

Ретрансляция видеопотока на другой RTMP-сервер производится при помощи REST-вызовов

— используемый REST-вызов.

Ретрансляция SIP/RTP

Достаточно редко используемая функция. Чаще всего в энтерпрайзе. Например, когда требуется установить SIP-звонок с внешним сервером SIP-конференций и перенаправить в этот звонок аудио или видеопоток чтобы зрители конференции увидели какой-то видеоконтент: “Посмотрите пожалуйста этот ролик” или “Коллеги, а сейчас давайте посмотрим на стрим с IP-камеры со стройки объекта”. Надо понимать, что сама конференция существует и управляется в данном случае на внешнем ВКС-сервере с поддержкой SIP (Недавно тестировали решение от Polycom DMA), мы же просто подключаемся и ретранслируем на этот сервер существующий поток. Функция REST API называется /inject и служит как раз для этого случая.

REST API команда:

«Это тест. Меня видно?»

Flashphoner WebCallServer запускается полностью готовым к работе, 30-дневная ознакомительная лицензия активируется автоматически. Для тестирования всех основных функций есть веб-интерфейс, мы ограничимся проверкой публикации и проигрывания WebRTC потока.

Открываем в браузере страницу https://droplet_ip:8444/admin/. По умолчанию с сервером поставляется self-signed сертификат, поэтому придется подтвердить исключение безопасности. В дальнейшем можно заменить сертификаты на собственные. Вводим имя и пароль (по умолчанию demo)

Выбираем в боковой панели пример Two-Way Streaming, нажимаем кнопку «Connect», затем «Publish». Для проигрывания потока нажимаем «Play»

Технические тонкости

У WebRTC есть свои тонкости — он использует два сетевых протокола — TCP и UDP.

Особенность протокола TCP в том, что он передает данные без потерь: пользователь получает стабильное изображение, видео передается без потерь и повреждений. Но этот протокол имеет ограничения по объему передачи данных. Например, нельзя передавать видео Full HD пяти людям одновременно.

Эта проблема решается с помощью протокола UDP: пользователи могут передавать высококачественные изображения и видео без ограничений. Но у него есть свой недостаток: он допускает потерю пакетов. Из-за этого изображение может дрожать и сильно терять в качестве.

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

Подведем итоги

WCS 5.2 — это сервер для разработки приложений с поддержкой реалтайм аудио и видео для браузеров и мобильных устройств. Для разработки предоставляется четыре API: Web SDK, iOS SDK, Android SDK, REST API. На сервер можно публиковать (скармливать) видеопотоки по пяти протоколам: WebRTC, RTMP, RTSP, VOD, SIP/RTP. С сервера можно играть потоки плеерами также по пяти протоколам: WebRTC, RTMP, RTSP, MSE, HLS. Потоками можно управлять и производить над ними такие операции как: запись, нарезку снапшотов, микширование, транскодирование, добавление водяного знака, фильтрация FPS, трансляция поворотов видео в мобильных устройствах. Потоки можно ретранслировать на другие серверы по WebRTC и RTMP протоколам, а также перенаправлять в SIP-конференции. Серверы можно объединить в сеть доставки контента и масштабировать для обработки произвольного количества видеопотоков.

Что должна знать разработчик Алиса для работы с сервером

Разработчику необходимо уметь пользоваться Linux. Команды такого рода в
командной строке не должны вызывать замешательства:

Ванильный JavaScript тоже надо уметь, если речь идет о разработке под
Web.

Пригодится также умение работать с бэкендом.

WCS может не только получать управляющие команды через REST API, но и отправлять хуки — нотификации о событиях, которые на нем происходят.
Например, при попытке установить соединение из браузера или мобильного приложения, WCS вызовет хук /connect, а при попытке проиграть стрим, вызовет хук playStream. Поэтому разработчику придется побыть немного в шкуре бэка, который в состоянии написать как простого REST-клиента, так и небольшой REST-сервер для обработки хуков.

Пример REST API

— пример REST API вывода списка стримов на сервере

Пример REST хука

— обработка REST-хука /connect на стороне бэкенда.

Linux, JavaScript, REST Client / Server — три элемента, которых
достаточно для разработки продакшен сервиса на платформе WCS, работающего
с видео стримами.

Для разработки мобильных приложений потребуется знание Java и Objective C
для Android и iOS соответственно.

Установка и запуск

Быстрый запуск WCS на сегодняшний день можно провести тремя способами:

1) Установить на свой Centos7 или Ubuntu 16.x LTS или Ubuntu 18.x LTS, и
т.д. руководствуясь статьей из документации.

или

2) Взять готовый образ на Amazon EC2.

или же

3) Взять готовый образ сервера на DigitalOcean.

И начать увлекательную разработку проекта с функциями потокового видео.

Обзорная статья получилась достаточно объемной. Спасибо что хватило
терпения прочесть.

Хорошего стриминга!