[Перевод] RTCP REMB: подкручиваем настройки видеозвонка в браузере
Находчивые ребята из Tribe не только нашли свою нишу на стыке конференсинга и gamedev«а (что само по себе уже интересно), но и хорошо знают, что творится под капотом у WebRTC. Менеджер по продукту Тимотэ Ле Борнье периодически описывает техническую сторону своего детища; мы решили перевести его статью про нестандартную, но очень любопытную функциональность WebRTC. Уверены, вам будет интересно. Ну, а пока вы читаете, мы продолжим готовить инсайд про наши обновленные видеоконференции… Но это уже другая история.
Тонкая настройка и управление качеством потока с использованием REMB
Итак, сейчас вы скорее всего знаете, что мы работали над созданием кастомного MCU для Tribe — если вдруг не знаете, то вот почему мы решили это сделать и как это у нас получается.
Но ближе к делу: давайте посмотрим, что же происходит под капотом.
- WebRTC-соединение начинается с механизма обмена под названием «SDP offer/answer» — обмен информацией о поддерживаемых кодеках и соответствующих параметрах между участниками.
- После этого участники пытаются связаться друг с другом напрямую: начинают слушать UDP-порты и используют ICE, STUN и (в дальнейшем) TURN, чтобы установить UDP-соединение.
- Когда UDP-соединение установлено, участники используют его, чтобы обменяться параметрами шифрования по протоколу DTLS-SRTP. После этого участники используют:
- Протокол SRTP (Secure RTP поверх UDP) чтобы отправлять и получать медиа
- Протокол SRTCP (Secure RTCP поверх UDP) для управления потоком и обмена внеполосными данными.
Стек WebRTC-протоколов (измененная схема, оригинал тут: webrtc-security.github.io)
Разбираемся с RTCP
Выше упомянуто, что пакеты RTP и RTCP безопасно хранятся в SRTP и SRTCP. Для чего они используются?
RTP обеспечивает сквозной транспорт для данных в реальном времени: аудио и видео. В некотором роде, RTCP это «брат RTP»: он используется вместе с RTP и улучшает протокол передачи данных за счет мониторинга доставки, а также управления и идентификации.
В сессии WebRTC MCU выступает как посредник между участниками: они соединены с MCU, но не напрямую друг с другом.
WebRTC — базовая топология MCU
Например, возьмем сессию с двумя участниками. MCU получает медиапоток от участника FOO, декодирует-кодирует его и отправляет участнику BAR. Одновременно то же самое происходит и с потоком от BAR к FOO.
Протоколы MTP и RTCP
Симметрия очевидна, поэтому сосредоточимся на одном направлении и посмотрим, что там творится:
Фокус на одной из сторон
Когда браузер BAR получает медиапоток от MCU, он также получает статистику от RTCP Sender Reports (SR). Браузер BAR будет использовать RTP«шные последовательные номера пакетов, RTP-таймштампы, собственное время и Sender Reports, чтобы подсчитать то, что мы называем RTCP Receiver Reports (RR).
Браузер со стороны BAR использует все эти данные для расчета максимального ожидаемого битрейта, а затем отправит это значение в MCU, используя RTCP REMB (Remote Estimate Maximum Bitrate).
Используем REMB (эффективно)
Формат пакета RTCP REMB tools.ietf.org/html/draft-alvestrand-rmcat-remb-00#section-2.2
Значение расчетного максимального битрейта кодируется в полях BR Exp и BR Mantissa.
Пример реализации можно посмотреть в коде Хромиум: cs.chromium.org/chromium/src/third_party/webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.cc
В языке Go мы преобразовали это сообщение в структуру PacketALFBRemb:
Когда вам нужно узнать битрейт из такой структуры, можно сделать так:
Если же наоборот, у вас есть битрейт и вы хотите заполнить поля Exp и Mantissa в структуре PacketALFBRemb, то вы сделаете что-то вроде этого:
Пропускная способность и RTCP REMB
Это одно из преимуществ MCU — возможность сделать REMB RTCP пакет для управления исходящим битрейтом в браузере:
MCU отправляет RTCP REMB, чтобы управлять исходящим битрейтом браузера FOO
Также MCU может взять оценку битрейта от получателя и в соответствии с ней поменять свои настройки кодирования, чтобы они совпали с расчетным максимальным битрейтом; также это оптимизирует исходящую пропускную способность MCU:
MCU меняет настройки кодирования, используя значения RTCP REMB от участника BAR
Управляем битрейтом
Как можно протестировать влияние RTCP REMB на битрейт браузера FOO? Довольно легко: просто отправить пакеты REMB с переменным битрейтом, (например, 64Кб и 128Кб каждые 10 секунд), а затем посмотреть на графики chrome://webrtc-internals.
На языке Go это будет так:
Открыв chrome://webrtc-internals, вы увидите что-то вроде этого:
Это явное подтверждение, что вы способны изменять и отслеживать битрейт с вашей стороны в реальном времени. Какие параметры лучше подходят для ваших нужд и надо ли оптимизировать полосу пропускания и качество потока — решать вам :)
Вероятно, вы заметили, что RTCP REMB сейчас в статусе deprecated. Идея была в том, что полосу пропускания должен контролировать источник данных (а не удаленный приемник/участник) — что ж, в статье мы показали, что это все еще возможно и как это делать.
В нашем случае это было полезно — получить точечный контроль над полосой и качеством :)