127 lines
10 KiB
Plaintext
127 lines
10 KiB
Plaintext
Адаптивная упаковка Opus в звонке
|
||
================================
|
||
|
||
Сервис CALL_AUDIO использует одну Router-кодограмму для 1..10 Opus-кадров.
|
||
Кодек и длительность кадра (20мс) не меняются. Новый формат должен быть
|
||
на обеих сторонах; старый одиночный CALL_MEDIA не поддерживается.
|
||
|
||
Wire, packed, порядок байтов хоста как у остального CALL:
|
||
Общий header, 27 байт:
|
||
subcmd:u8, call_id:u64, track_id:u8, capture_epoch:u64,
|
||
codec_delay_samples:u32, sent_ms:u32, count:u8.
|
||
Далее count раз:
|
||
seq:u16, capture_pts_us:i64, length:u16, opus[length].
|
||
Накладные расходы: 27 + 12*N байт CALL на N кадров, плюс один Router.
|
||
|
||
count=1..10, весь CALL_MEDIA <=1024 байт. Пачка может быть меньше target из-за
|
||
размера, срока отправки или смены capture epoch/codec delay. PTS/seq каждого
|
||
кадра сохраняются; PTS может быть INT64_MIN. Парсер проверяет всю кодограмму
|
||
до выдачи первого кадра, отвергает хвостовые байты и незавершённые записи.
|
||
Headless callback по-прежнему получает отдельные Opus-кадры.
|
||
|
||
Пример для Opus по 37 байт, прямой Router с SIGN|ENCRYPT (+163 байта):
|
||
N кадров CALL payload Router wire байт Router на кадр
|
||
1 76 239 239
|
||
2 125 288 144
|
||
3 174 337 112,33
|
||
5 272 435 87
|
||
10 517 680 68
|
||
Обрамление ETCP/BLE и ACK не включены. Normalizer может объединять/разбивать
|
||
кодограммы. Старый расход: 236 байт Router на каждый такой Opus-кадр;
|
||
историческое разложение — call_audio_packet_overhead.txt.
|
||
|
||
Источник обратной связи
|
||
-----------------------
|
||
etcp_router_tx_stats(group_id, peer_node_id, ETCP_RT_ID_CALL_AUDIO).
|
||
Это конкретный логический аудиоканал, не общая сумма очередей ядра.
|
||
Интерфейс уже используется видеотреком звонка; stream_publisher использует
|
||
другой, общий снимок ETCP и для данного регулятора не подходит.
|
||
|
||
Router сохраняет исходное монотонное enqueued_us в send_q и переносит его
|
||
в inflight. Ретрансмит не меняет эту метку. При первом подтверждении:
|
||
sample = ACK time - enqueued_us;
|
||
delivery_rtt_us = EWMA sample с весом 1/8 (первый sample без сглаживания).
|
||
Снимок также отдаёт queued_age_us/inflight_age_us головы от исходного enqueue
|
||
и last_ack_us. Возраст пустой очереди равен нулю. При reset история очищается.
|
||
Прежние rtt_us/baseline_rtt_us и алгоритм видеорегулятора не меняются.
|
||
|
||
Полный delivery_rtt_us включает исходную очередь Router, нижние очереди,
|
||
путь до приёмника и возврат ACK. Базовый RTT НЕ вычитается. Это не время
|
||
доставки в динамик и не измерение односторонней задержки.
|
||
|
||
Регулятор
|
||
---------
|
||
Снимок каждые50мс в uasync; управление целиком в call_session.
|
||
D = max(delivery_rtt_us, queued_age_us, inflight_age_us).
|
||
Собственное намеренное накопление пачки в D не добавляется.
|
||
|
||
Начальное target=4, deadline60мс от первого кадра: это время сбора ещё трёх
|
||
кадров по20мс. При смене local/peer Router epoch или исчезновении канала
|
||
target/история сбрасываются. Первый пригодный ACK сразу переводит deadline
|
||
на измеренную задержку, даже до заполнения окна статистики500мс; на быстром
|
||
канале ожидание сразу выключается. Для изменения target нужно полное окно.
|
||
До первого ACK сохраняется стартовое ожидание60мс; при no_route, receive_busy
|
||
и minRTT probe ожидание и рост выключены.
|
||
|
||
При D>100мс непрерывно200мс target увеличивается на1 до10. Между изменениями
|
||
не менее max(500мс, 2*delivery_rtt_us). Высокий обычный RTT без очереди тоже
|
||
может включить упаковку — это намеренное поведение.
|
||
При D<40мс и пустом Router send_q в течение2с target уменьшается на1.
|
||
Промежуточные значения сбрасывают отсчёты high/low, сохраняя target.
|
||
Если ACK не продвигался дольше max(2с, 2*delivery_rtt_us, 500мс), рост
|
||
и намеренное ожидание выключаются; это состояние не считается свободной полосой.
|
||
|
||
Предельное время накопления:
|
||
budget = clamp((D - 40мс) / 4, 0, 40мс);
|
||
hold = min((target - 1)*20мс, budget).
|
||
На быстром канале hold сразу равен0, даже пока target постепенно уменьшается.
|
||
При150мс полного RTT допустим hold до27,5мс, при200мс и более — до40мс.
|
||
|
||
Отправка и приём
|
||
---------------
|
||
Пачка собирается из собственной FIFO до передачи Router. Переданные Router
|
||
кодограммы не изменяются и не изымаются из inflight. Подпись и оба уровня
|
||
шифрования сохраняются. При отсутствии места остаётся прежний отменяемый
|
||
waiter Router; новые кадры/наблюдение/освобождение очереди продолжают drain.
|
||
|
||
Отправляем при target кадров, достижении лимита байт, несовместимости эпохи
|
||
следующего кадра или deadline головы. Новый кадр не продлевает deadline.
|
||
40мс — предел адаптивного ожидания (до первого ACK60мс), а не предел
|
||
backpressure или полного RTT.
|
||
10 кадров — максимальный размер готовой пачки; ожидания180мс ради её наполнения нет.
|
||
Прежняя защитная FIFO750 и её удаление старейшего при overflow сохраняются;
|
||
данное изменение не обещает жёсткую задержку200мс при остановившемся канале.
|
||
|
||
sent_ms ставится перед подачей пачки Router. Приёмник передаёт его всем кадрам,
|
||
но обновляет оценку сетевого jitter только по первому. Capture PTS остаётся
|
||
отдельной временной шкалой каждого кадра; учитываются реальные сетевые паузы,
|
||
а собственное накопление пачки не создаёт N фиктивных измерений jitter.
|
||
После полной проверки кадры идут в прежние decoder/jitter/headless callbacks.
|
||
|
||
Первое воспроизведение ждёт накопления не менее200мс аудио в jitter buffer
|
||
(10 кадров по20мс), либо сетевого запаса плюс PCM-блок, если это больше.
|
||
Захват и отправка начинаются сразу. До первой выдачи PCM нет сигнала перебоя.
|
||
После старта действуют прежние адаптивный запас и плавное ускорение излишка;
|
||
200мс не закрепляются как постоянная глубина. Повторное накопление после
|
||
недостачи и сброс устройства после начала речи используют обычный запас.
|
||
Это порог начального заполнения, не ограничение полной сквозной задержки.
|
||
|
||
cleanup/ENDED/destroy отменяют оба новых таймера и прежний Router waiter до
|
||
освобождения FIFO. Доступ к ядру только в uasync; audio capture worker API
|
||
не меняется. Счётчики tx/rx кадров и пачек разделены.
|
||
|
||
Диагностика
|
||
-----------
|
||
call=info: стартовые target/hold, изменение target с причиной, D, полным RTT,
|
||
возрастами и hold; порог JB и фактическая глубина при первом воспроизведении.
|
||
call=debug: flow раз в секунду и TX/RX каждой пачки (count, bytes, seq, age).
|
||
etcp_route=debug: подтверждение с enqueue->ACK, EWMA и числом попыток.
|
||
Ошибки формата/аллокации/таймеров/отправки логируются. Нужны обе новые сборки.
|
||
|
||
Проверки: test_call_audio_batch (формат и регулятор), test_call (реальная
|
||
доставка 10 кадров/неполной пачки и teardown), test_etcp_router (ACK-метрики
|
||
после backpressure), test_call_jitter (один arrival на пачку, поздний пакет,
|
||
отсутствие декодирования при180мс и старт при200мс),
|
||
headless/admission и прежние проверки аудио. Аппаратный эффект проверяется
|
||
отдельным звонком и сравнением логов, не выводится из одних unit-тестов.
|