Содержание статьи +
- Кратко
- Почему это важно
- Проблема: ёмкость, которую не видно
- Две подсказки, которые оставляет сеть
- Google Congestion Control: алгоритм в середине
- REMB, transport-cc и кто считает
- Почему звук адаптируется позже видео
- Как Opus на самом деле меняет битрейт
- Как разумно задать минимальный и максимальный битрейт
- Частая ошибка: добавление избыточности при перегрузке
- Где здесь Фора Софт
- Главное
- Что почитать дальше
Кратко
В живом звонке доступная пропускная способность сети меняется каждую секунду, поэтому приложение постоянно оценивает, сколько данных может пройти по каналу, и подстраивает битрейт звука под эти условия. Эту оценку называют оценкой полосы пропускания (bandwidth estimation), а три основных механизма, с которыми вы можете столкнуться, – это REMB, transport-cc и алгоритм, их использующий, Google Congestion Control. Звуку выделяется небольшая защищённая доля общего бюджета пропускной способности, и он кодируется последним – поэтому видео начинает «рассыпаться» на блоки задолго до того, как пропадает голос. Статья объясняет, как клиент и сервер согласовывают значение пропускной способности, почему адаптация звука происходит позже, чем у видео, и как разумно задать минимальный и максимальный битрейт, чтобы звонок оставался разборчивым даже при слабом соединении.
Почему это важно
Любой продукт реального времени – видеозвонок, вебинар, телемедицинский приём, лайв-шопинг – работает поверх сетей, которыми команда продукта не управляет. Канал между двумя людьми общий, перегруженный и изменчивый, а у софта есть лишь несколько сотен миллисекунд на реакцию, прежде чем звонок начнёт звучать сломанно. Если вы создаёте или покупаете такой продукт, вам нужно понимать, кто решает, каким будет битрейт звука, по каким сигналам и какие две ручки (минимальный и максимальный битрейт) реально меняют опыт. Статья написана так, чтобы продакт-менеджер или основатель прошёл всю петлю и задал инженеру правильные вопросы.
Проблема: ёмкость, которую не видно
Представьте однополосную дорогу между двумя городами. Иногда она пуста, а иногда по ней проезжает грузовик – и движение замедляется. Нельзя заранее позвонить и узнать, насколько сейчас загружена дорога: можно лишь смотреть, как движутся ваши машины, и по этому судить о трафике.
Сетевой путь устроен аналогично. Объём данных, который он может передать за секунду – доступная полоса пропускания, – нигде не публикуется. Она меняется, когда кто-то на той же Wi-Fi сети запускает загрузку, когда телефон переключается между сотами или когда домашний роутер заполняет очередь. Приложению приходится оценивать доступную ёмкость по косвенным признакам и выбирать скорость отправки, соответствующую этой оценке. Отправлять слишком много – очередь растёт, увеличивается задержка, а потом начинают теряться пакеты; отправлять слишком мало – теряешь качество, которое можно было бы получить.
Эту непрерывную петлю «угадай и подстройся» называют управлением перегрузкой (congestion control), а число, которое она выдаёт – лучшую оценку того, сколько бит в секунду путь может передать прямо сейчас, – называют оценкой полосы пропускания.
Две подсказки, которые оставляет сеть
Управление перегрузкой анализирует два сигнала, и качественные системы учитывают оба.
Первая подсказка – задержка. Интервал между отправкой двух пакетов должен совпадать с интервалом их получения на приёмной стороне. Если где-то на пути начинает формироваться очередь, второй пакет задерживается, и интервал между приходами увеличивается. Это удлинение – рост межпакетной задержки – является самым ранним признаком перегрузки канала, ещё до появления потерь. Оценщик, анализируя динамику задержки, заранее снижает битрейт.
Вторая подсказка – потери. Когда очередь переполняется, пакеты отбрасываются. Потери – грубый и поздний сигнал: когда вы их видите, ущерб уже нанесён, – но он однозначен. Оценщик на основе потерь реагирует на долю пропавших пакетов: при потере более ~10% он резко снижает скорость, при потере менее ~2% – осторожно пробует увеличить её, а в промежутке между этими значениями – сохраняет текущую.
Система использует меньшую из двух оценок. Сигнал задержки обычно срабатывает первым и не позволяет пути заполниться; сигнал потерь служит страховкой для путей, где измерение задержки ненадёжно.
Google Congestion Control: алгоритм в середине
Алгоритм, объединяющий эти подсказки почти в каждом браузере и WebRTC-стеке, – Google Congestion Control, обычно сокращаемый до GCC. Он описан в черновике IETF draft-ietf-rmcat-gcc-02 (Holmer, Lundin, Carlucci, De Cicco, Mascolo, июль 2016). Обратите внимание: это черновик (draft), а не утверждённый стандарт – он так и не стал RFC, но остаётся фактическим эталоном, поскольку рабочая реализация в libwebrtc следует его структуре. Код продвинулся вперёд по сравнению с черновиком, однако двухкомпонентная архитектура – контроллер на основе задержки и контроллер на основе потерь, выбирающие минимум, – сохранилась.
GCC работает как быстрая внутренняя петля. Несколько раз в секунду он получает свежую обратную связь по времени и потерям, обновляет обе оценки и выдаёт одно число – целевую скорость отправки для всех медиа на этом соединении. Затем отдельный этап распределяет это число между видео- и аудиопотоком. Именно на этом этапе проявляется особое отношение к звуку.
REMB, transport-cc и кто считает
GCC требует обратной связи от приёмника, и существует два поколения способов её передачи. Эта разница важна, потому что она изменила, где вычисляется оценка.
REMB – Receiver Estimated Maximum Bitrate. Это устаревшая конструкция, предложенная в draft-alvestrand-rmcat-remb-03. Приёмник самостоятельно рассчитывает пропускную способность на основе задержек и отправляет одно RTCP-сообщение, в котором, по сути, сообщает: «максимально я могу принять N бит в секунду». Отправитель доверяет этому значению и ограничивает им свою передачу. REMB использует RTP-расширение заголовка absolute send time, чтобы приёмник знал точное время отправки каждого пакета.
transport-cc – Transport-Wide Congestion Control. Это новая конструкция, предложенная в draft-holmer-rmcat-transport-wide-cc-extensions-01. Здесь роли меняются местами: отправитель помечает каждый исходящий пакет – и звук, и видео – единым сквозным (transport-wide) порядковым номером. Приёмник почти ничего не делает: он просто сообщает для каждого номера, когда пакет пришёл. Вся оценка состояния канала происходит на стороне отправителя. Подход «держи приёмник простым» теперь стал стандартом по умолчанию в современном WebRTC, потому что у отправителя полная картина происходящего, и он может реагировать быстрее.
Позже IETF стандартизировал чистый формат обратной связи для той же идеи в RFC 8888 (RTP Control Protocol (RTCP) Feedback for Congestion Control, январь 2021), в котором зарегистрировано сообщение обратной связи по управлению перегрузкой. Этот документ является спецификационным преемником черновика transport-cc. RFC 8888 также отмечает реальный компромисс: поскольку обратная связь сквозная и объединяет все потоки, становится сложнее определить, какой именно поток – звук или видео – потерял пакеты, поэтому при принятии решений о восстановлении по отдельным потокам требуется дополнительная осторожность.
Почему звук адаптируется позже видео
Вот вопрос, который рано или поздно задаёт каждый инженер: звонок портится, видео превращается в кашу, а голос остаётся – почему?
Ответ – приоритет распределения битрейта (bitrate allocation priority). Когда алгоритм распределения делит общий битрейт GCC между потоками, аудио обслуживается в первую очередь и гарантированно получает минимальный порог. Голосовому звонку нужно совсем немного, чтобы оставаться разборчивым: кодек Opus, используемый почти во всём аудио WebRTC, работает в широком диапазоне – от очень низкого до высокого качества, и чистый голосовой звонок комфортно существует в пределах 16–40 kbps. Видео же – «прожорливое»: оно эффективно использует сотни и даже тысячи кбит/с и постепенно ухудшается, когда ресурсы ограничены.
Поэтому логика распределителя проста и осознанна: выдели звуку его небольшую защищённую долю, а остальное – видео. Когда общая оценка качества падает, видео сжимается в широком диапазоне, а звук остаётся неизменным, пока оценка не опустится до минимального порога для звука. Только на по-настоящему сломанном канале – когда пропускная способность не превышает нескольких десятков килобит в секунду – звук начинает снижать битрейт, переходит в самый агрессивный низкобитрейтный режим и полагается на маскировку потерь пакетов (PLC), чтобы заполнить пробелы.
Этот порядок верен. Люди терпят замёрзшее или прерывистое видео гораздо лучше, чем рваную, пропадающую речь. Разговор выживает на звуке; без него он гибнет.
Есть и вторая причина, по которой звук кажется медленнее в реакции: он передаёт меньше пакетов в секунду, чем видео, поэтому у петли обратной связи меньше точек данных, и оценщик обновляет состояние реже на основе звука. Защита в основном намеренная, но более редкая обратная связь её усиливает.
Как Opus на самом деле меняет битрейт
Оценка полосы полезна только в том случае, если кодек может немедленно на неё отреагировать, и Opus как раз создан для этого. Согласно RFC 6716 (спецификация Opus, сентябрь 2012, обновлена RFC 8251) Opus поддерживает любой битрейт от 6 kbps до 510 kbps и способен изменять скорость покадрово – каждые 20 миллисекунд – без щелчков, провалов и необходимости пересогласовывать сессию. Когда распределитель задаёт Opus новую цель, следующий кадр просто передаётся на новой скорости.
Opus по умолчанию работает в режиме переменной битовой скорости (VBR) – каждый кадр использует столько бит, сколько необходимо для звука: тишина и простые тона требуют мало, а сложная речь и музыка – больше, чтобы обеспечить лучшее качество при заданной средней скорости. Поддерживается также постоянная битовая скорость (CBR), при которой все кадры имеют одинаковый размер. CBR редко подходит для звонков; RFC 6716 указывает, что его два реальных применения – транспортные протоколы, требующие фиксированного размера кадра, и определённые сценарии шифрования. Для звука в реальном времени почти всегда предпочтителен VBR – пусть буферная система сама регулирует нагрузку.
Разберём пример. Пусть общая оценка GCC падает до 250 kbps на ухудшающемся канале. Распределитель защищает звук, скажем, минимумом 24 kbps и отдаёт остаток видео:
общая оценка = 250 kbps
минимум звука (Opus VBR) = 24 kbps ← защищён, обслужен первым
видео получает = 250 − 24 = 226 kbpsЕсли канал упадёт до 40 кбит/с, звук всё равно получит свои 24 кбит/с, а видео останется на уровне 16 кбит/с – едва ли больше слайд-шоу, но голос сохранится. Опустите оценку ниже ~24 кбит/с – и только тогда Opus начнёт снижать качество, сужая полосу и битрейт звука, чтобы хоть что-то продолжало передаваться.
Как разумно задать минимальный и максимальный битрейт
У вас есть две ручки, которые действительно формируют опыт, и большинство команд оставляют их по умолчанию – и зря.
Максимальный битрейт определяет, насколько качественным может быть звук при высокой пропускной способности сети. Для голосовых приложений ограничение Opus в диапазоне 32–40 кбит/с не тратит ресурсы на неслышимые детали и освобождает полосу пропускания для видео или большего числа участников. В случае музыкальных или высококачественных аудиопродуктов рекомендуется увеличить битрейт до 64–128 кбит/с, чтобы по-настоящему эффективное соединение работало на полную мощность.
Минимальный битрейт задаёт нижнюю границу, которую система защиты канала не позволит превысить – скорость ниже этой отметки звук не получит. Слишком высокий битрейт может привести к сбоям в слабом канале, который мог бы справиться с тонким голосовым потоком, но вместо этого теряет соединение; слишком низкий – искажает звук раньше, чем это необходимо. Минимум около 16 кбит/с сохраняет разборчивость речи даже на плохих каналах; не снижайте битрейт голоса ниже ~12 кбит/с, не проверив, как это звучит.
| Сценарий | Рекоменд. min Opus | Рекоменд. max Opus | Почему |
|---|---|---|---|
| Голосовой звонок / телемед | 16 kbps | 32–40 kbps | Разборчивый голос; место под видео и устойчивость |
| Вебинар / один-ко-многим | 12–16 kbps | 32 kbps | Много слушателей; защити минимум, ограничь потолок |
| Музыка / высокая верность | 24 kbps | 64–128 kbps | Хороший канал должен звучать отлично |
| Конференция с шарингом экрана | 16 kbps | 40 kbps | Минимум звука защищён; полоса уводится на экран |
Укажите оба параметра при настройке сессии; минимум – то, что распределитель защищает, когда сеть перегружена.
Частая ошибка: добавление избыточности при перегрузке
Самая дорогая ошибка здесь – пытаться бороться с потерями, добавляя данные, когда сами потери вызваны избытком данных. Если пакеты теряются из-за перегрузки канала, включение коррекции ошибок (FEC) или избыточности лишь увеличивает поток битов в и без того перегруженный канал, усугубляя перегрузку и потери. Управление пропускной способностью должно идти в первую очередь: сначала подстройте скорость под оценку, дайте очередям опустошиться, а уже потом анализируйте, являются ли оставшиеся потери случайными (их стоит защищать) или вызваны перегрузкой (что защитой не исправить). Порядок всегда один: сначала оценка, потом защита.
Где здесь Фора Софт
Мы разрабатываем системы звука и видео в реальном времени – видеоконференции, телемедицину, онлайн-обучение, прямые трансляции и видеонаблюдение, – где соединение должно работать на любой сети, с которой столкнётся пользователь. Настройка минимального и максимального битрейта звука, выбор между REMB и transport-cc в конкретном стеке, а также приоритизация голоса над видео в распределителе – вот те незаметные решения, которые отличают продукт, способный удерживать разговор даже на гостиничном Wi-Fi, от того, что его постоянно обрывает. Такие системы мы поставляем в конференциях, OTT-платформах и телемедицине с 2005 года – в браузерах, нативных приложениях и SFU.
Главное
- Полоса пропускания невидима; софт оценивает её по задержке и потерям пакетов.
- Google Congestion Control объединяет оценщик задержки и оценщик потерь, выбирая меньшую из двух.
- REMB вычисляет оценку на стороне приёмника; transport-cc передаёт её отправителю и теперь является стандартом.
- Аудио получает небольшой защищённый минимум и кодируется в последнюю очередь – поэтому видео страдает первым.
- Opus изменяет битрейт каждые 20 мс в диапазоне от 6 до 510 кбит/с без пересогласования.
- Установите разумные значения минимума (около 16 кбит/с) и максимума (32–40 кбит/с для голоса) вместо значений по умолчанию.