Files
utun2/doc/call_audio_batch.txt
T

127 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Адаптивная упаковка 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-тестов.