RTP-метки времени, RTCP-отчёты отправителя и синхронизация по NTP

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

Коротко

В реальном звонке аудио и видео передаются как два отдельных потока RTP-пакетов, и каждый из них использует свои собственные временные метки, которые начинаются со случайного значения и отсчитываются в собственных единицах – поэтому напрямую сравнивать эти временные шкалы невозможно. Решение – RTCP-отчёт отправителя (sender report, SR): небольшой управляющий пакет, который каждый отправитель отправляет раз в несколько секунд. В нём указывается: «моя временная метка медиа X соответствует определённому моменту реального времени по стенным часам», выраженному в формате Network Time Protocol (NTP) как количество секунд с 1 января 1900 года. Приёмник собирает по одному такому соответствию для каждого потока, переводит оба потока на единую временную шкалу и только после этого может корректно синхронизировать нужный аудиосэмпл с нужным видеоадром. Если это соответствие настроено правильно – синхронизация губ (lip-sync) сохраняется часами; если же оно потеряно (из-за неверных SR, дрейфа временных меток или их полного отсутствия) – звук начнёт отставать или опережать изображение, даже если каждый поток по отдельности выглядит идеально.

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

Если вы разрабатываете что-либо, что передаёт живые медиа через интернет – приложение для видеоконференций, платформу телемедицины, SFU для трансляций, WebRTC-игру, – синхронизация аудио и видео не возникает автоматически. Механизм, обеспечивающий её, – это метка времени RTP плюс отчёт отправителя RTCP. Продакт-менеджеру важно знать об их существовании, чтобы понимать: «аудио и видео по отдельности работают нормально, но не синхронизированы» – это реальный, частый и исправимый класс багов, а не загадка. Инженеру нужно понимать, что именно измеряет метка времени RTP, что содержит отчёт SR и как приёмник объединяет два независимых временных потока в единую шкалу, чтобы проанализировать дамп статистики WebRTC и отличить сбой синхронизации от обычного джиттера. Эта статья даёт обоим читателям единую модель: у каждого потока свои часы, отчёт отправителя – это своего рода «записка», привязывающая эти часы к реальному времени, а синхронизация губ (lip-sync) – это приёмник, выполняющий арифметические вычисления на основе этих записок.

Задача: два потока, двое часов, нет общего нуля

Начнём с факта, который удивляет тех, кто впервые сталкивается с медиа в реальном времени. Когда вы заходите в видеозвонок, аудио с микрофона и видео с камеры не передаются одновременно. Их кодируют отдельно, упаковывают в пакеты и отправляют как два независимых потока небольших пакетов по протоколу Real-time Transport Protocol (RTP). Каждый пакет снабжён меткой времени RTP – числом, указывающим, когда, по часам отправителя, был оцифрован звук или кадр в этом пакете. Казалось бы, этого достаточно, чтобы синхронизировать потоки. Но этого не происходит – по двум причинам, которые усиливают друг друга.

Первая причина – в том, что два таймера работают в разных единицах. По давней традиции частота счётчиков времени в аудиопотоке и видеопотоке отличается, поэтому «RTP-метка 96000» означает разные промежутки времени для аудио и видео. Вторая причина ещё серьёзнее: согласно RFC 3550, стандарту, описывающему RTP, метка времени каждого потока должна начинаться со случайного значения. Это намеренная мера безопасности – предсказуемая стартовая точка могла бы облегчить определённые атаки, – но она означает, что ноль в аудиосчётчике и ноль в видеосчётчике никак не связаны между собой. Два таймера, две разные скорости, две случайные стартовые точки. Сравнить их невозможно.

Этот пробел и заполняет RTCP-отчёт отправителя. Рядом с медиапотоками каждый отправитель периодически отправляет небольшой управляющий пакет по протоколу RTP Control Protocol (RTCP). Самый важный из них – отчёт отправителя, SR. Он содержит одну ключевую пару чисел: значение RTP-таймера этого потока и реальное время по системным часам в тот же момент, зафиксированное в универсальном формате. Соберите по одной такой паре для аудиопотока и для видеопотока – и вдруг оказывается, что ранее несинхронизированные, идущие с разной скоростью часы привязаны к одной внешней шкале. RTP-метка говорит приёмнику, когда относительно начала самого потока; отчёт отправителя говорит, что это значит в реальном времени. Lip-sync – это то, что получается, когда вы делаете это для двух потоков одновременно.

Рисунок 1. Зачем существуют отчёты отправителя. У каждого RTP-потока свои медиа-часы со случайным стартом; отчёт отправителя привязывает их к общим стенным часам, и только тогда два потока можно совместить.

Что на самом деле означает временная метка RTP

Самое частое заблуждение про RTP – что метка времени – это стенное время вроде «14:32:07». Это не так. RTP-метка отсчитывает тики собственных часов оцифровки этого медиа, и RFC 3550 чётко определяет, как она работает: она растёт монотонно и линейно, должна базироваться на часах с постоянной частотой и – что особенно важно – отражает медиа-время, а не количество пакетов и не реальное время.

Конкретный аудиопример проясняет это. Допустим, вы передаёте поток аудио Opus. Каждый RTP-пакет обычно содержит 20 миллисекунд звука. Формат полезной нагрузки RTP для Opus, описанный в RFC 7587, фиксирует частоту тактового генератора на 48 000 тиков в секунду для любого режима Opus и любой внутренней частоты дискретизации. Поэтому временная метка увеличивается на фиксированную величину с каждым пакетом:

тиков на пакет = частота часов × длительность пакета
              = 48 000 тиков/с × 0,020 с
              = 960 тиков на 20-мс пакет

Если метка одного пакета – 96 000, у следующего – 96 960, у следующего – 97 920 и так далее, каждый пакет на 960 тиков позже предыдущего, независимо от того, когда он реально ушёл в сеть. Последняя оговорка – самое главное. Метка фиксирует момент, когда звук был оцифрован, а не когда пакет ушёл. Если два пакета оцифрованы с интервалом 20 мс, но сеть задержала второй, их метки всё равно будут отличаться ровно на 960. Метка – это свойство медиа, а не передачи.

Видео работает так же, но с другой частотой. По традиции, закреплённой в RTP-профиле для аудио и видео RFC 3551 и соблюдаемой практически всеми видеокодеками, видеопотоки RTP используют часы с 90 000 тиков в секунду. Частоту 90 килогерц выбрали потому, что она делится нацело на распространённые частоты кадров: 90 000 ÷ 30 = 3 000 тиков на кадр при 30 fps, 90 000 ÷ 25 = 3 600 при 25 fps, 90 000 ÷ 24 = 3 750 при 24 fps – так что временной интервал между кадрами всегда выражается целым числом тиков. Это те же самые часы на 90 кГц, что используются в MPEG-2 transport stream; если вы читали PTS, DTS и метка времени элементарного потока, это та же временная шкала, просто переиспользованная.

Вот ловушка, из-за которой синхронизация становится трудной – и она проста: аудиопоток работает со скоростью 48 000 сэмплов в секунду, видеопоток – 90 000 кадров в секунду, и каждый из них начал отсчёт со своего случайного числа. Не существует такой арифметики, которую можно было бы применить к двум меткам RTP по отдельности, чтобы определить, какой аудиосэмпл соответствует какому кадру видео. Нужен внешний мост. И этим мостом является отчёт отправителя.

МедиаТипичная частота RTP-часовТиков на единицуИсточник
Аудио Opus48 000 Hz960 на 20-мс пакетRFC 7587
Телефонное аудио (G.711)8 000 Hz160 на 20-мс пакетRFC 3551
Видео (все частые кодеки)90 000 Hz3 000 на кадр при 30 fpsRFC 3551

Таблица 1. Частоты RTP-медиачасов по типу медиа. Эти частоты намеренно различаются – поэтому две сырые RTP-метки нельзя сравнивать без временной привязки из отчёта отправителя.

NTP-метка: универсальные стенные часы

Чтобы привязать медиа-часы к реальному времени, нужен способ зафиксировать момент, когда все устройства показывают одно и то же время. RTP использует формат протокола Network Time Protocol (NTP) – того самого, который поддерживает синхронизацию часов на компьютерах и телефонах. Формат NTP-метки представляет собой 64-битное число с фиксированной точкой, отсчитывающее секунды от фиксированной точки отсчёта – 0 часов UTC 1 января 1900 года. Старшие 32 бита хранят целые секунды, младшие 32 – дробную часть секунды.

Разделение 64 бит на 32 целых и 32 дробных обеспечивает сразу большой диапазон и высокую точность. 32 бита для целых секунд позволяют отсчитывать около 136 лет (поэтому формат переполняется в 2036 году – это известное и управляемое событие). 32 бита дробной части делят каждую секунду примерно на 4,3 миллиарда интервалов, так что наименьший представимый шаг составляет около 233 пикосекунд – гораздо тоньше, чем требуется для любого медиа-тайминга. Именно этот формат использует отчёт отправителя, и тот же формат применяет WebRTC-расширение заголовка «absolute capture time», когда помечает пакет моментом исходного захвата.

Одно практическое замечание, на котором часто спотыкаются инженеры, работающие с сырыми пакетами. Полная NTP-метка занимает 64 бита, но в протоколе RTP используется компактная форма «средних битов» – она применяется в некоторых полях на стороне приёмника. Эта форма берёт младшие 16 бит секунд и старшие 16 бит дробной части, образуя 32-битное значение, которое переполняется примерно каждые несколько секунд, но подходит для краткосрочных вычислений интервалов. Когда вы видите 32-битное NTP-подобное значение в дампе статистики, это почти всегда именно такая компактная форма, а не полная 64-битная.

RTCP-отчёт отправителя: привязка временных меток к реальному времени

Теперь центральная часть. Каждый активный отправитель в RTP-сессии периодически отправляет RTCP-отчёт отправителя. В нём блок «sender info» содержит четыре числа, и два из них отвечают за синхронизацию:

NTP-метка (64 бита) – это стенное время в формате NTP на момент генерации отчёта. RTP-метка (32 бита) – это значение медиа-часов данного потока в тот же момент. RFC 3550 чётко указывает, что она соответствует тому же времени, что и NTP-метка, выражена в тех же единицах измерения и с тем же случайным сдвигом, что и RTP-метки в пакетах данных. Остальные два поля – счётчик пакетов и счётчик октетов отправителя – представляют собой нарастающие итоги для статистики и оценки потерь, но не используются для синхронизации.

Эта пара – весь фокус. Пакеты данных передают приёмнику поток RTP-меток без реального смысла. Отчёт отправителя содержит одну сопоставленную пару – «RTP-метка R произошла в NTP-время T» – и этот единственный якорь позволяет приёмнику перевести любую RTP-метку этого потока в стенное время, поскольку частота часов известна и постоянна:

Для аудиопотока с часами 48 000 Hz и отчётом отправителя,
говорящим, что RTP-метка R0 = NTP-время T0:

стенное_время(R) = T0 + (R − R0) ÷ 48 000   секунд

Примените ту же процедуру к видеопотоку с частотой 90 000 Гц и его собственным отчётом отправителя – и теперь у каждого аудиосэмпла и каждого видеофрейма есть стеновое время на одной и той же шкале. Синхронизация губ (lip-sync) сводится к поиску: когда часы воспроизведения достигают стенового времени t, нужно показать аудиосэмпл и видеофрейм, чьи вычисленные стеновые времена равны t. Эти два потока изначально были несравнимы; отчёты отправителя сделали их сопоставимыми.

WebRTC связывает два потока ещё одной деталью – CNAME, каноническим именем в RTCP, которое указывает: «эти потоки – из одного источника, их нужно воспроизводить синхронно». Приёмник по CNAME понимает, что именно этот аудиопоток и тот видеопоток образуют пару для синхронизации – без него в многоточечном звонке он не смог бы определить, какое аудио соответствует какому видео. RFC 8834, определяющий использование RTP в WebRTC, требует, чтобы все потоки одного источника имели одинаковый CNAME – именно по этой причине.

Рисунок 2. Сопоставленная NTP/RTS-пара в отчёте отправителя и то, как приёмник использует её для перевода любого значения медиа-часов в стенное время – чтобы синхронизировать оба потока.

Рабочий пример: совмещаем аудио и видео

Сделаем арифметику конкретной – одним расчётом синхронизации. Допустим, приёмник получил по одному отчёту от отправителя с каждого потока звонка:

Аудиопоток (Opus, часы 48 000 Hz):
   SR говорит: RTP-метка 720 000  ↔  NTP-время T_a

Видеопоток (часы 90 000 Hz):
   SR говорит: RTP-метка 1 350 000 ↔  NTP-время T_v   (и T_v = T_a, тот же момент)

Теперь приходит пакет данных на аудиопотоке с RTP-меткой 768 000. На сколько он отстаёт от аудио-якоря в реальном времени?

Δтиков  = 768 000 − 720 000 = 48 000 тиков
Δвремя  = 48 000 ÷ 48 000 Hz = 1,000 секунда после T_a
→ это аудио оцифровано в стенное время T_a + 1,000 с

Приходит кадр видео с RTP-меткой 1 395 000. На сколько он отстаёт от видео-якоря?

Δтиков  = 1 395 000 − 1 350 000 = 45 000 тиков
Δвремя  = 45 000 ÷ 90 000 Hz = 0,500 секунды после T_v
→ этот кадр оцифрован в стенное время T_v + 0,500 с

Поскольку T_a и T_v – один и тот же момент времени на стене, аудиопакет (якорь + 1,000 с) и видеоадрес (якорь + 0,500 с) отстают друг от друга на 500 миллисекунд в реальном времени – аудио опережает видео на полсекунды. Теперь приёмник знает, что должен либо задержать аудио, либо выпустить видео раньше, чтобы нужный сэмпл и нужный кадр одновременно появились на экране и в динамике. Без двух временных отчётов отправителя две RTP-метки – 768 000 и 1 395 000 – были бы бессмысленны. А с ними сдвиг вычисляется одной строкой. В этом и заключается весь механизм.

Почему синхронизация не происходит мгновенно – и как WebRTC её ускоряет

В дизайне заложена одна существенная проблема. Отчёты отправителя не приходят с каждым пакетом – они передаются по RTCP, а трафик RTCP ограничен по скорости. Согласно RFC 3550, общий RTCP-трафик не должен превышать примерно 5% от полосы сессии, а также установлен рекомендуемый минимальный интервал в 5 секунд между отчётами одного отправителя (с меньшим значением для коротких сессий). Прямое следствие: приёмник не может синхронизировать два потока, пока не получит хотя бы один отчёт отправителя по каждому из них. Поэтому в начале звонка может возникнуть задержка до нескольких секунд, когда аудио и видео уже воспроизводятся, но ещё не синхронизированы. Вы, скорее всего, это замечали – первые секунду-другую губы и голос слегка не совпадают, а потом всё «защёлкивается» на место.

Для большинства конференций это незаметно. В приложениях, где это критично – например, при слоистом видео, быстром переключении каналов или позднем подключении к трансляции – IETF определил RFC 6051 «Rapid Synchronisation of RTP Flows». Документ предлагает три механизма: более жёсткий тайминг RTCP, чтобы первые отчёты приходили раньше; сообщение обратной связи, позволяющее серверу при переключении запросить немедленную ресинхронизацию; и новое расширение заголовка RTP, которое передаёт соответствие NTP/RTP внутри самих медиапакетов, так что приёмнику вообще не нужно ждать RTCP-отчёт.

WebRTC пошёл дальше всех в реализации расширения заголовка с помощью absolute capture time, которое помечает выбранные RTP-пакеты временем NTP – точным моментом по системным часам, когда был захвачен первый кадр в этом пакете. Это больше, чем просто ускорение. Обычная метка отчёта отправителя формируется уже в момент отправки самого отчёта – после того, как прошли захват, кодирование и буферизация, добавившие задержку. В отличие от этого, расширение absolute capture time передаёт истинный момент захвата с учётом вычтенных известных аппаратных задержек, благодаря чему синхронизация на приёмнике привязывается к реальной физической временной шкале, а не к моменту формирования отчёта. Именно это позволяет синхронизации сохранять точность даже при прохождении через микшер – SFU или MCU, которые перепаковывают потоки и иначе разрушили бы исходный тайминг. Расширение гарантирует, что исходное время захвата проходит через микшер без изменений.

Вот первая частая ошибка, которую стоит назвать, потому что мы видим её в продакшене чаще всего. Когда сервер – будь то SFU, пересылающий потоки, MCU, микширующий их, или конвейер записи, переставляющий метки пакетов, – перегенерирует RTCP-отчёты отправителя по своим часам вместо того, чтобы сохранить исходное соответствие, каждый приёмник ниже по цепочке синхронизируется с неверным якорем. Аудио и видео по отдельности выглядят идеально – просто расходятся, потому что записку, привязывавшую их к реальному времени, переписала коробка, которая никогда не видела исходного захвата. Когда клиент говорит: «Синхронизация была в порядке peer-to-peer, но ломается, как только мы пускаем через сервер» – первым делом стоит проверить обработку отчётов отправителя в этой промежуточной коробке.

Что ломается: дрейф, джиттер и пропавший якорь

Поскольку приёмник полностью доверяет NTP/RTCP-паре отчётов отправителя, синхронизацию могут нарушить три разных сбоя, каждый со своим характерным проявлением.

Дрейф часов – медленный процесс. Медиа-часы отправителя и часы воспроизведения приёмника – это разные физические кварцы, и ни один из них не работает с абсолютно одинаковой частотой. Разница в несколько частей на миллион – норма и неизбежность. Без коррекции даже небольшая расхождение накапливается: сдвиг в 10 частей на миллион приводит к разнице в 36 миллисекунд за час – достаточно, чтобы к концу длительного звонка синхронизация была нарушена. Отчёты отправителя помогают бороться с этим: они приходят регулярно, и каждый новый отчёт заново выравнивает временные метки, позволяя приёмнику постоянно обновлять оценку «какое сейчас реальное время», не давая дрейфу накопиться. Поэтому отчёты должны передаваться на протяжении всей сессии, а не только в начале.

Сетевой джиттер – шумный. Пакеты приходят неравномерно: маршрутизаторы и коммутаторы сбивают их в кучу и растягивают. Это не портит RTP-метки – они зафиксированы у отправителя и описывают время оцифровки, а не прибытия, – но добавляет шум в измерение приёмником момента прибытия каждого пакета, что слегка размывает оценку времени. RTP определяет статистику interarrival jitter (межприбытийный джиттер), отправляемую обратно в отчётах приёмника, именно чтобы это измерить: это сглаженное среднее разницы между ожидаемым и фактическим интервалом прибытия пакетов, в единицах времени самого потока. Высокий interarrival jitter – это число, которое говорит инженеру, что проблема в сети, а не в кодере.

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

Видимые симптомы напрямую отражают причины. Медленный, монотонный сбой lip-sync, усиливающийся в ходе длительного звонка, – это дрейф часов, опережающий частоту отчётов. Синхронизация, которая «подрагивает» и нестабильна, но не уходит в одну сторону, – это сетевой джиттер, размывающий временной якорь. Полное отсутствие синхронизации – когда аудио и видео работают корректно, но навсегда сдвинуты друг относительно друга, – говорит о потерянном или перезаписанном отчёте отправителя. Что считать заметным сдвигом и какие допусковые окна должен превысить сбой, чтобы зритель это заметил, – см. Что значит «в синхроне»: ITU-R BT.1359, окна lip-sync, заметность.

ОтказЧто этоЧто видит приёмникТипичный симптом
Дрейф часовКварцы отправителя и приёмника идут с чуть разной частотойЯкорь медленно устаревает между отчётамиLip-sync уходит ровно; хуже чем дольше звонок
Сетевой джиттерПакеты приходят кучей и врастяжкуШум в измеренном времени прибытия отчётаСинхронизация дёргается, нестабильна, но не в одну сторону
Пропавший / неверный SRНет SR или он переписан мидлбоксомНет валидного NTP/RTP-якоря для потокаПотоки по отдельности в норме, вместе навсегда не в фазе
Задержка защёлкиванияRTCP ограничивает первые отчётыЯкоря ещё нет для одного или обоих потоковПервые ~1–5 с звонка слегка не в фазе, затем защёлкивается

Таблица 2. Четыре способа, которыми синхронизация RTP/RTCP отказывает, что переживает приёмник и о каком симптоме сообщает пользователь. Лимиты и статистики – из RFC 3550 (тайминг RTCP, interarrival jitter) и RFC 6051 (задержка защёлкивания).

Синхронизация RTP/RTCP против вещательной модели PCR

Стоит поставить это рядом с ответом вещательного мира на ту же задачу, потому что контраст проясняет оба подхода. Спутниковый или кабельный transport stream решает проблему «у декодера нет часов» путём передачи программных часов – PCR, то есть периодических снимков мастер-часов, которые декодер восстанавливает и затем использует для считывания каждого PTS и DTS. Один поток, одни часы, односторонний канал. Мы подробно разбираем этот механизм в статье PCR в MPEG-TS: программные часы, на которых держится вещание.

RTP сталкивается с более сложной задачей. Отсутствуют единые мастер-часы и гарантированный односторонний канал – вместо этого имеется два или более независимых потока, возможно с разных хостов, поступающих по сети с потерей пакетов и наличием обратного канала. Поэтому вместо единого встроенного эталона времени RTP использует пару самоописывающих записей – отчёты отправителя – и полагается на приёмник, который объединяет потоки в единую шкалу NTP. В вещательной модели предполагается управляемый канал и единый источник времени; в модели RTP – хаос, а порядок восстанавливается на стороне приёмника. PCR – это часы, которые копирует декодер; отчёт отправителя – таблица преобразования, которую применяет приёмник. Разные каналы, разный подход, одна цель: придать каждой временной метке реальный смысл.

Когда эталонные часы действительно необходимо разделять между устройствами – например, в профессиональном живом производстве по IP, где десятки источников должны быть синхронизированы с точностью до сэмпла, – индустрия идёт ещё дальше и привязывает каждое устройство к общим часам Precision Time Protocol (PTP, IEEE 1588), сигнализируемым в описании сессии по RFC 7273 и предписанным стандартом SMPTE ST 2110 для IP-инфраструктуры студий. В таких системах NTP-метки в отчётах отправителя не просто согласованы между собой – они привязаны к единым физическим grandmaster-часам на всей территории объекта. Про контрибуцию и живое IP-производство см. Живой звук: контрибуционные кодеки, AES67, SMPTE 2110-30.

Где это в конвейере WebRTC

Полезно разместить отчёт отправителя внутри общей архитектуры системы. WebRTC-эндпоинт захватывает аудио и видео, кодирует каждый поток, упаковывает в RTP-пакеты и отправляет – параллельно RTCP-канал передаёт отчёты отправителя наружу и отчёты приёмника обратно. На стороне приёмника каждый поток проходит через свой собственный jitter buffer, который компенсирует сетевой джиттер и обеспечивает стабильное воспроизведение для каждого потока по отдельности. Слой синхронизации работает над двумя jitter buffer-ами: он использует временные метки из отчётов отправителя каждого потока и определяет, насколько один поток должен быть задержан относительно другого, чтобы аудио и видео синхронизировались на выходе. Jitter buffer отвечает за плавность внутри потока, а синхронизация на основе отчётов отправителя – за согласованность между потоками. Это разные задачи, решаемые разными компонентами. О работе буферов подробнее см. Jitter buffer: NetEQ, мозг звука WebRTC, а о всей цепочке обработки – Конвейер звука WebRTC целиком.

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

Мы разрабатываем продукты для видеоконференций, телемедицины, онлайн-обучения и трансляций на базе WebRTC ещё до того, как он стал полноценным стандартом, и межпотоковая синхронизация – это как раз та область, где конвейеры реального времени либо работают без сбоев, либо тихо дают сбой. Проблема редко кроется в кодеках: звонок идеально синхронизирован в режиме peer-to-peer, но как только добавляют медиасервер для масштабирования комнаты, аудио и видео начинают расходиться – потому что сервер перегенерирует RTCP-отчёты отправителя по своим внутренним часам, вместо того чтобы сохранить исходное соответствие момента захвата или передать расширение absolute-capture-time. Когда клиент говорит: «всё было синхронно в прототипе, а сломалось после добавления SFU», мы сразу обращаем внимание на обработку RTCP-отчётов и расширений заголовков в этом сервере – именно там происходит незаметная перепись связи между медиа-часами и реальным временем.

Главное

  • Аудио и видео передаются как отдельные RTP-потоки с независимыми временными шкалами и случайным стартом.
  • RTP-метка отражает количество отсчётов оцифрованного сигнала, а не количество пакетов или реальное время.
  • Аудио обычно тактируется на 48 000 Гц (Opus) или 8 000 Гц, видео – на 90 000 Гц.
  • RTCP-отчёт отправителя связывает одно значение RTP-таймстампа с моментом времени в формате NTP.
  • Приёмник, используя по одной такой паре на каждый поток, привязывает оба сигнала к единой временной шкале – это и обеспечивает синхронизацию звука и изображения (lip-sync).
  • Дрейф, джиттер или потеря/повторная отправка SR-пакетов нарушают синхронизацию даже при идеальных потоках.

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

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

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