Буфер джиттера: NetEQ, мозг звука в WebRTC

Автор: Николай СапуновОбновлено: август 202627 мин чтения
Содержание статьи +

Кратко

Пакеты уходят от отправителя ровно – по одному каждые 20 миллисекунд, – но интернет доставляет их неравномерно: то сериями, то с задержкой, а иногда и вовсе теряется; этот разброс во времени прихода называют джиттером. Буфер джиттера – это своего рода «зал ожидания», который удерживает входящие звуковые пакеты ровно столько, чтобы превратить неровный поток в стабильный, пригодный для воспроизведения. В WebRTC такой буфер реализован в виде компонента NetEQ, и он адаптивный: постоянно оценивает нестабильность сети и корректирует время удержания, чтобы найти баланс между лишними миллисекундами задержки и риском «опустошения». В статье простым языком объясняется, что делает NetEQ на каждом 10-миллисекундном такте, какие пять операций он выполняет, когда пакет опаздывает или теряется, как измеряет задержку и какие метрики в продакшене покажут, что звук работает корректно.

Почему это важно

Если вы делаете видеозвонки, телемедицину, контакт-центр или онлайн-классы, самая частая жалоба ваших пользователей – «звук рвался» или «была задержка». Почти каждая из них восходит к поведению буфера джиттера на плохой сети – а в WebRTC этим буфером является NetEQ: компонент, который вы не пишете сами, но обязаны понимать. Статья написана для продакт-менеджера, основателя или операционного руководителя, которому нужно понять компромисс, которым управляет NetEQ – плавность против задержки, – чтобы прочитать диагностическую метрику и задать инженеру точный вопрос. Senior-инженер тоже найдёт здесь каждый факт, прослеженный до документации исходников WebRTC, спецификации RTP или опубликованного разбора от сопровождающих.

Проблема: ровный отправитель и неровная сеть

Начнём с того, что делает отправитель. Микрофон непрерывно записывает звук, кодер разбивает его на небольшие фрагменты – обычно по 20 миллисекунд каждый, называемые кадром (frame), – после чего система упаковывает каждый кадр в пакет и отправляет. Двадцать миллисекунд на кадр означают, что отправитель выдаёт по одному пакету каждые 20 миллисекунд – как метроном: тик, тик, тик, пятьдесят раз в секунду, идеально равномерно.

Интернет не сохраняет равномерность передачи. Пакеты проходят через маршрутизаторы, коммутаторы, Wi-Fi и сотовые сети, и каждый участок добавляет задержку, которая постоянно меняется. Поэтому пакеты, отправленные с интервалом в 20 миллисекунд, приходят к получателю неравномерно – то через 18, то через 35 миллисекунд, то два сразу, то с паузой в 60 миллисекунд. Этот разброс во времени прихода и называется джиттер – буквально «дёрганость» расписания поступления пакетов.

Инженер Meta, отвечающий за код устойчивости звука в WebRTC, описывает три формы джиттера, встречающиеся в реальных условиях. Самая распространённая – всплесковый приход (bursty): какое-то время получатель ничего не слышит, а затем несколько пакетов приходят сразу. Далее идёт мелкий джиттер: один-два пакета слегка опаздывают, но следующие быстро компенсируют задержку. И, наконец, постоянное изменение задержки: с определённого момента каждый пакет начинает передаваться дольше, и джиттер при этом не наблюдается – например, когда телефон переключается с Wi-Fi на сотовую сеть [webrtcHacks, «How WebRTC's NetEQ Jitter Buffer Provides Smooth Audio», июнь 2025].

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

Что такое буфер джиттера – на одной аналогии

Буфер джиттера – как зал ожидания у выхода на посадку. Пассажиры (пакеты) приходят к выходу по неровному графику – кто-то раньше, кто-то позже, кто-то приходит толпой. Зал ожидания удерживает их, чтобы посадка (воспроизведение) шла ровно и предсказуемо, а не прерывисто каждый раз, когда пакеты приходят скопом. Чем дольше вы держите людей в зале, тем больше запаса на опоздавший рейс – но тем дольше общий путь каждого.

Вот и весь компромисс в одной картинке. Больший буфер удерживает больше пакетов, поэтому выдержит более длительный сетевой сбой, не опустев, – но добавляет задержку в разговор. Меньший буфер делает общение живым – но при первом же сетевом всплеске, превышающем время удержания, возникает слышимый обрыв. Сделать его слишком маленьким – и звук будет рваться; слишком большим – и люди начнут перебивать друг друга, потому что круговая задержка кажется чрезмерной.

Для живого разговора допустимая задержка строго ограничена. Естественный диалог начинает разрушаться, когда односторонняя задержка превышает примерно 200 миллисекунд, а после ~500 миллисекунд становится по-настоящему трудным – за этим порогом люди перебивают друг друга, потому что пауза перед ответом воспринимается как задержка (webrtcHacks, июнь 2025). Сравните это с просмотром видео в стриминге: плеер спокойно буферизует несколько секунд, ведь вы не замечаете задержку, с которой не с чем сравнивать. Плеер фильма может держать буфер на минуты, приложение для лайв-стримов – на секунды, а реал-тайм-звонок – максимум несколько сотен миллисекунд. Поэтому буфер джиттера в WebRTC нельзя просто сделать большим и надёжным – он работает в жёстких рамках задержки.

Наивное решение и почему оно не работает

Простейший буфер джиттера – фиксированный: всегда держи, например, 100 миллисекунд звука перед началом воспроизведения и не меняй это значение. Такой подход легко реализовать и он работает на стабильной сети. Однако на реальной сети он терпит неудачу по двум противоположным причинам.

Если задержка джиттера в сети меньше 100 миллисекунд, фиксированный буфер добавляет эти 100 миллисекунд ненужной задержки – чистая потеря, воспринимаемая как вялость. Если же джиттер превышает 100 миллисекунд, буфер успевает опустеть посреди фразы, и слушатель слышит обрыв. Поэтому фиксированный буфер почти всегда работает плохо: он слишком велик для стабильных сетей и слишком мал для нестабильных. Единственный правильный подход – буфер, который меняет свой размер в зависимости от текущей сети. Именно это и означает «адаптивный», и именно в этом заключается вся сложность NetEQ.

Знакомьтесь, NetEQ

NetEQ – сокращение от «Network Equalizer» – это адаптивный буфер джиттера и компенсатор потерь пакетов в составе libWebRTC, открытой реализации WebRTC, используемой в Chrome, Edge и большинстве нативных голосовых приложений. Он был разработан в компании Global IP Solutions (GIPS), которую Google приобрела в 2011 году для создания WebRTC, и с тех пор непрерывно совершенствуется. Как указано в официальной документации проекта WebRTC, его цель – «обеспечить плавное воспроизведение входящих звуковых пакетов с минимальным количеством артефактов и при этом поддерживать задержку на максимально низком уровне» (документация WebRTC NetEq, chromium.googlesource.com). Эти две задачи – плавность воспроизведения и низкая задержка – противоречат друг другу, и именно балансировка между ними составляет суть работы NetEQ.

У NetEQ всего две публичные точки входа, и понять их – уже половина дела.

Первая – InsertPacket: сеть передаёт NetEQ только что пришедший RTP-пакет, и NetEQ откладывает его. Вторая – GetAudio: звуковое устройство запрашивает у NetEQ следующий фрагмент звука для воспроизведения, и NetEQ должен вернуть ровно 10 миллисекунд аудиоданных – не больше и не меньше. Этот метод вызывается 100 раз в секунду, строго по графику (документация WebRTC NetEq).

InsertPacket срабатывает при поступлении пакета – по нерегулярному расписанию сети. GetAudio работает как часы: 100 раз в секунду, строго по графику динамика. NetEQ – это коробка передач, соединяющая неровный входной вал с ровным выходным.

Рисунок 1. NetEQ соединяет неровный вход (пакеты из сети) с ровным выходом (10 мс звука, забираемые динамиком 100 раз в секунду).

Что происходит на каждом такте: пять (с хвостиком) операций

Вот суть. Каждые 10 миллисекунд динамик вызывает GetAudio, и NetEQ должен выдать 10 миллисекунд звука. Для этого он консультируется с двумя внутренними «мозгами» – менеджером задержки (delay manager), оценивающим, сколько буферизации сейчас требует сеть, и логикой решений (decision logic), выбирающей, что именно сделать в этом такте, – и выполняет ровно одну из небольшого набора операций. Перечислить эти операции – самое полезное в статье, потому что каждый симптом, о котором сообщат пользователи, соответствует одной из них, происходящей слишком часто.

Normal (норма). Ожидаемый пакет находится в буфере в нужный момент. NetEQ декодирует его и воспроизводит с естественной скоростью. Ничего сложного. В здоровой сети почти каждый такт – Normal, и это как раз то, что нужно.

Acceleration (ускорение). В буфере звука накопилось больше данных, чем требуется при текущей сетевой нагрузке – пакеты приходили раньше времени или в периоды простоя, – из-за чего речь слегка отставала от реального времени. NetEQ ускоряет звук на микроскопическую величину, чтобы сбросить избыток и догнать, применяя растяжение времени: звук сокращается без изменения высоты тона, чтобы динамик не звучал как «бурундук» (документация WebRTC NetEq). Одно такое ускорение вы бы не заметили; но тысячи – воспринимаются как лёгкое, неестественное ускорение.

Preemptive expand (замедление). Противоположный случай: буфер почти пуст, и существует реальный риск, что на следующем такте он опустеет. NetEQ замедляет звук на микроскопическую величину – слегка растягивая его без изменения высоты тона – чтобы выиграть время до прихода следующего пакета (документация WebRTC NetEq). Массово это воспринимается как лёгкое «затягивание».

Expand (маскировка потерь, PLC). Нужного пакета нет – он потерян или просто опоздал – и декодировать нечего. Вместо тишины NetEQ синтезирует правдоподобное продолжение звука: экстраполирует уже имеющееся, повторяя и постепенно затухая недавнюю форму волны, либо использует встроенную в кодек процедуру маскировки для её генерации (документация WebRTC NetEq). Немного – и это почти незаметно. Много – и получается тот самый роботизированный, «булькающий», размазанный звук, с которым все ассоциируют плохое качество звонка.

Merge (склейка). Когда настоящий пакет приходит сразу после того, как NetEQ синтезировал поддельный звук с помощью операции Expand, их нельзя просто соединить – на стыке возникнет щелчок. Merge плавно встраивает результат маскировки в только что декодированный настоящий звук, чтобы переход был незаметен (документация WebRTC NetEq).

Есть и шестая, особая операция – для тишины. Когда отправитель использует прерывистую передачу (DTX) – намеренно не отправляет пакеты в периоды молчания, чтобы сэкономить полосу пропускания, – NetEQ не воспринимает эти паузы как потерю данных. Вместо этого он генерирует комфортный шум (comfort noise): тихий, подобранный по уровню шипящий фон, чтобы линия не звучала «мёртвой» (документация WebRTC NetEq). Этот механизм подробно разбирается в статье про детектор речевой активности и DTX; здесь достаточно знать, что у NetEQ есть отдельная ветка обработки для таких случаев, и он не путает намеренную тишину с потерянным пакетом.

Рисунок 2. Операции, которые NetEQ может выдать на любом 10-мс такте, и условие буфера, запускающее каждую из них.

Как NetEQ решает, сколько буферизовать

Две операции растяжения – Acceleration и Preemptive expand – имеют смысл только в том случае, если NetEQ знает, сколько звука ему нужно держать. Это значение называется целевая задержка (target delay; в коде – «target level»), и от того, насколько точно оно вычисляется, зависит разница между буфером, плавно двигающимся в такт сети, и буфером, который «подпрыгивает».

Старый, интуитивный метод – измерять интервал между соседними пакетами (межпакетная задержка, inter-arrival) и настраивать буфер под самый большой зафиксированный интервал. Он работает при простом джиттере, но сбоит при накапливающейся задержке, когда каждый следующий пакет приходит чуть позже предыдущего. Анализ Meta показывает именно такой сбой: при измерении межпакетных интервалов буфер постоянно недооценивает задержку на 40 миллисекунд на каждом пакете в период медленного нарастания, что приводит к повторяющимся опустошениям, хотя алгоритм считает, что параметры выбраны верно (webrtcHacks, июнь 2025).

В 2022 году WebRTC заменил это на относительную задержку (relative delay). Вместо сравнения каждого пакета с непосредственным предшественником NetEQ теперь выбирает самый быстрый пакет в недавнем временном окне – тот, который прошёл путь быстрее всех, – и измеряет задержку каждого другого пакета относительно этого опорного значения (webrtcHacks, июнь 2025). Привязка к самому быстрому пакету означает, что медленное нарастающее увеличение задержки измеряется от действительно быстрой базы, поэтому целевая задержка увеличивается достаточно, чтобы компенсировать всё нарастание, а не постоянно отставать от него. Временное окно, определяющее «недавнее», по умолчанию составляет 2 секунды в libWebRTC – это намеренно выбранная эвристика, разделяющая временный джиттер (от которого стоит буферизоваться) и постоянный разовый сдвиг задержки (от которого буферизоваться не нужно, поскольку он не повторится) (webrtcHacks, июнь 2025).

Менеджер задержки не просто фиксирует максимальную относительную задержку, которую когда-либо наблюдал – иначе один аномальный пакет навсегда раздул бы буфер. Вместо этого он ведёт гистограмму: текущий подсчёт частоты встречаемости каждого значения задержки, где каждое новое измерение слегка сдвигает счётчик, а старые данные постепенно угасают. Процесс угасания управляется фактором забывания (forget factor), по умолчанию установленным в 0.983 – значение выбрано так, чтобы гистограмма сохраняла память о редких событиях, но не цеплялась за устаревшие (webrtcHacks, июнь 2025). Затем NetEQ считывает с гистограммы высокий перцентиль – например, задаёт цель, чтобы 95 процентов недавних пакетов доставлялись вовремя. Чем выше перцентиль – тем безопаснее и больше буфер; чем ниже – тем отзывчивее, но рискованнее. Этот перцентиль – одна из немногих настоящих «крутилок», доступных нативному приложению.

Есть и вторая гистограмма – оптимизатор переупорядочивания (reorder optimizer), – которая обрабатывает пакеты, пришедшие не по порядку и отправленные повторно. Поскольку переотправленный звуковой пакет в WebRTC выглядит идентично обычному – у них одинаковый идентификатор потока, и получатель не может их различить, – поздние повторные передачи естественно воспринимаются как джиттер и плавно увеличивают размер буфера (webrtcHacks, июнь 2025). Оптимизатор переупорядочивания оценивает целесообразность восстановления таких пакетов, сопоставляя их ценность с затратами на задержку ожидания, при этом используя явную функцию стоимости вместо фиксированного перцентиля. Менеджер задержки выбирает из двух гистограмм ту, которая требует большей буферизации, и использует её в качестве итоговой цели.

Рисунок 3. Почему относительная задержка (2022) лучше старого межпакетного метода: привязка к самому быстрому недавнему пакету покрывает накапливающуюся задержку, которую межпакетное измерение упускает.

Разбор примера: превращаем джиттер в размер буфера

Числа делают это конкретным. Пусть ваш звук использует кадры по 20 миллисекунд – то есть отправитель выдаёт 50 пакетов в секунду. Вы наблюдаете за приходом пакетов в течение двух секунд и обнаруживаете, что относительно самого быстрого пакета в этом окне задержки распределяются так: большинство пакетов приходят в пределах 20 миллисекунд от якоря, но заметная доля отстаёт сильнее.

Пусть гистограмма относительных задержек выглядит так: 60 процентов пакетов – в пределах 20 мс, 20 процентов – в пределах 40 мс, 10 процентов – в пределах 60 мс, 6 процентов – в пределах 80 мс и 4 процента – в пределах 100 мс. Чтобы покрыть 95 процентов пакетов, NetEQ просматривает гистограмму сверху вниз, пока накопленная доля впервые не превысит 0,95:

в пределах 20 мс:  0.60   (накоплено 0.60)
в пределах 40 мс:  0.20   (накоплено 0.80)
в пределах 60 мс:  0.10   (накоплено 0.90)
в пределах 80 мс:  0.06   (накоплено 0.96)  ← первая корзина за 0.95
в пределах 100 мс: 0.04   (накоплено 1.00)

Накопленная доля впервые превышает 0,95 на временной корзине в 80 миллисекунд, поэтому NetEQ устанавливает целевую задержку в 80 миллисекунд. Толкование: удержание 80 миллисекунд звука означает, что 96 процентов пакетов в этой сети будут уже находиться в буфере к моменту своей очереди на воспроизведение; оставшиеся 4 процента – самые отстающие – вызовут режим Expand. Если поднять перцентиль до 0,99, целевая задержка вырастет до 100 миллисекунд: это безопаснее по отношению к отставшим пакетам, но добавляет 20 миллисекунд задержки к каждому слову. Этот единственный арифметический шаг – выбрать перцентиль и определить размер буфера – и есть компромисс, который NetEQ совершает тысячи раз за один звонок, и тот самый, который вы настраиваете, крутя «крутилку».

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

Вы не видите работу NetEQ, но можете просмотреть его диагностику. Браузер предоставляет её через стандартный API getStats(), описанный в спецификации W3C WebRTC Statistics, и вот какие поля стоит вывести на дашборд. Каждое из них находится в отчёте по входящему звуковому потоку (W3C webrtc-stats, Candidate Recommendation).

Самое важное – средняя задержка буфера джиттера. Спецификация предоставляет два исходных счётчика: jitterBufferDelay – суммарные секунды буферизации по всем выданным сэмплам, и jitterBufferEmittedCount – количество выданных сэмплов. Чтобы получить среднюю задержку, на которую каждый сэмпл задерживался в буфере (W3C webrtc-stats), нужно разделить первое значение на второе. Это ключевая цифра: сколько задержки сейчас добавляет NetEQ. Также есть jitterBufferTargetDelay – целевое значение, к которому стремится менеджер задержки, исходя исключительно из сетевых условий, без учёта дополнительной задержки для синхронизации звука и видео (W3C webrtc-stats, RTCInboundRtpStreamStats).

Далее – счётчики маскировки. concealedSamples подсчитывает сэмплы, подделанные из-за отсутствия пакета, а concealmentEvents – сколько раз маскировка запускалась, что удобно для оценки частоты опустошения буфера (W3C webrtc-stats). Несколько событий маскировки на продолжительном звонке – норма; если же доля таких сэмплов достигает процентов от общего числа, это слышно как рваный звук.

Наконец, счётчики растяжения времени. insertedSamplesForDeceleration считает сэмплы, добавленные при замедлении воспроизведения (Preemptive expand), а removedSamplesForAcceleration – сэмплы, отброшенные при ускорении (Acceleration) (W3C webrtc-stats). Когда они одновременно растут, это обычно сигнал нестабильного буфера, который постоянно «охотится» – то замедляется, то ускоряется. Такое поведение указывает на шумную оценку сети, а не на одну чётко выраженную проблему.

Метрика (getStats)Что показываетЗдоровое направление
jitterBufferDelay / jitterBufferEmittedCountСредние мс ожидания сэмпла в буфереНизко и стабильно
jitterBufferTargetDelay / jitterBufferEmittedCountРазмер буфера, к которому стремится NetEQСледует за сетью, без скачков
concealmentEventsКак часто буфер опустевал и подделывал звукПочти ровно во времени
concealedSamplesОбъём поддельного звукаКрошечная доля от всех сэмплов
insertedSamplesForDecelerationЗвук, добавленный замедлениемНизко; рост = давление опустошения
removedSamplesForAccelerationЗвук, отброшенный ускорениемНизко; рост вместе с предыдущим = «охота»

Чтобы посмотреть NetEQ в реальном времени, откройте chrome://webrtc-internals во время любого WebRTC-звонка в Chrome и найдите раздел входящего звука – каждый счётчик там обновляется в реальном времени, и это самый быстрый способ понять, действительно ли проблема с «плохим звуком» вызвана буфером джиттера или чем-то выше по цепочке. Для анализа в оффлайне проект WebRTC предоставляет инструмент neteq_rtpplay, который обрабатывает захваченный RTP-дамп или PCAP-файл через NetEQ и выводит агрегированную статистику, так что плохой звонок клиента можно воспроизвести локально (документация WebRTC NetEq).

Частая ловушка: винить NetEQ за проблему выше по цепочке

Самая дорогая ошибка команд при диагностике буфера джиттера – считать высокую долю маскировки доказательством того, что «буфер джиттера сломан». NetEQ находится ниже по течению: после кодера, сети, контроллера перегрузки и звукового устройства. Поток операций Expand почти всегда означает, что пакеты действительно не приходят – из-за реальной потери в сети, коллапса контроля перегрузки или того, что отправитель снизил битрейт, – а не потому, что NetEQ выбрал плохую стратегию. Настройка перцентиля NetEQ, когда настоящая проблема – 8 процентов потери пакетов, лишь добавляет задержку, не устраняя провалов.

Вторая, более тонкая ловушка – взаимодействие синхронизации звука и видео. NetEQ можно намеренно заставить увеличить задержку, чтобы синхронизировать звук с более медленным видеопотоком (документация WebRTC NetEq). Если видео работает медленнее, NetEQ будет задерживать звук, подстраивая его под видео, и тогда метрика задержки буфера покажет высокое значение, хотя проблема не в сети. Решение – оптимизировать видеопоток, а не звуковой буфер. Поэтому метрику jitterBufferTargetDelay стоит анализировать отдельно – она отражает задержку, вызванную сетью, до любых корректировок на синхронизацию, что позволяет отличить реальную сетевую проблему от искусственной задержки, вызванной подстройкой.

Третья ловушка – чрезмерная настройка. Параметры по умолчанию в NetEQ – коэффициент забывания 0,983, окно 2 секунды, высокий перцентиль – были выбраны на основе огромного и разнообразного трафика. Они не являются оптимальными для каждого продукта, но представляют собой надёжную отправную точку. Команда, начинающая «крутить ручки» до того, как изучила метрики, как правило, только ухудшает ситуацию. Сначала измеряйте: правильный путь почти всегда – устранить проблему в сети или на устройстве выше по цепочке, на которую указывают метрики.

Как это связано с потерей пакетов и избыточностью

Операция Expand в NetEQ – последняя линия обороны и, по замыслу, наименее желательная: поддельный звук никогда не сравнится с настоящим. Всё, что остальные компоненты звукового стека WebRTC делают, чтобы избежать необходимости в Expand, работает выше NetEQ, и их стоит рассматривать в контексте этого механизма. Маскировка потерь пакетов – это семейство алгоритмов, делающих Expand менее заметным; современные кодеки и нейросетевые модели продвинули эту технологию удивительно далеко – об этом мы подробно рассказываем в статье про маскировку потерь пакетов. Упреждающая коррекция ошибок (FEC) передаёт немного избыточных данных, чтобы потерянный пакет можно было восстановить без повторной отправки, и NetEQ явно выделяет и приоритизирует эту избыточность при получении (документация WebRTC NetEq); компромиссы, связанные с этим подходом, мы разбираем в статье про FEC, in-band FEC и избыточность RED. Эти три темы – буферизация джиттера, маскировка и избыточность – составляют полный набор решений для работы с несовершенной доставкой, и настраивать их нужно совместно.

Где здесь Фора Софт

Фора Софт интегрирует реал-тайм-звуковое сопровождение в видеоконференции, телемедицину, онлайн-обучение и лайв-шопинг с 2005 года, и поведение NetEQ – это рутинная часть процесса диагностики и настройки таких систем. Когда клиент сообщает о прерывистом звуке, первый шаг почти никогда не связан с изменением буфера – нужно просто посмотреть счётчики маскировки и задержки в getStats и понять, в чём причина: в сети, устройстве, контроллере перегрузки или действительно в настройке буфера. Телемедицинскому вызову на больничном Wi-Fi и вебинару для 500 человек с разнообразными каналами связи требуется разное поведение буфера, и правильная настройка основывается на измеренном профиле джиттера, а не на догадках. Мы собираем эти метрики с самого начала, чтобы фраза «звук сломан» превращалась в конкретное число, которое можно измерить, а не в загадку, которую нужно воспроизводить.

Главное

  • Джиттер – это неравномерное поступление пакетов, отправленных равномерно; буфер джиттера сглаживает эту неравномерность.
  • NetEQ – адаптивный аудиобуфер джиттера в WebRTC: он подстраивает свой размер под текущие условия сети.
  • Каждые 10 мс он выполняет одно из действий: Normal, Acceleration, Preemptive expand, Expand, Merge или комфортный шум.
  • Целевая задержка определяется на основе относительной задержки (2022), рассчитанной по высокому перцентилю забывающей гистограммы.
  • Следите за jitterBufferDelay, concealmentEvents и счётчиками ускорения/замедления в getStats.
  • Высокая доля маскировки обычно указывает на реальную потерю пакетов – исправляйте сеть, а не буфер.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.