Document adaptive full batches and Router readiness ownership

This commit is contained in:
evgeny committed 2026-10-30 19:30:12 +01:00
1 parent 215f744bbe
commit efd80949cd
1 file changed
+54 -41
+54 -41
View File
@@ -14,7 +14,7 @@ Wire, packed, порядок байтов хоста как у остально
Накладные расходы: 27 + 12*N байт CALL на N кадров, плюс один Router.
count=1..10, весь CALL_MEDIA <=1024 байт. Пачка может быть меньше target из-за
размера, срока отправки или смены capture epoch/codec delay. PTS/seq каждого
ограничения размера или смены capture epoch/codec delay. PTS/seq каждого
кадра сохраняются; PTS может быть INT64_MIN. Парсер проверяет всю кодограмму
до выдачи первого кадра, отвергает хвостовые байты и незавершённые записи.
Headless callback по-прежнему получает отдельные Opus-кадры.
@@ -55,13 +55,10 @@ Router сохраняет исходное монотонное enqueued_us в s
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 ожидание и рост выключены.
Начальное target=4. При смене local/peer Router epoch или исчезновении канала
история сбрасывается. Для изменения target нужно пригодное окно статистики.
До получения ACK сохраняется стартовое число кадров; при no_route,
receive_busy, minRTT probe или несвежих ACK target не растёт.
При D>100мс непрерывно200мс target увеличивается на1 до10. Между изменениями
не менее max(500мс, 2*delivery_rtt_us). Высокий обычный RTT без очереди тоже
@@ -69,28 +66,44 @@ target/история сбрасываются. Первый пригодный
При 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 не менее target кадров И Router готов
передать следующую кодограмму в ETCP. Таймера неполной пачки нет: даже при
свободном транспорте target-1 кадров остаются в FIFO. Захват продолжается.
При росте target уже после регистрации готовности callback повторно проверяет
число кадров. При снижении target очередной 50мс tick сразу проверяет отправку.
Отправка и приём
---------------
Пачка собирается из собственной FIFO до передачи Router. Переданные Router
кодограммы не изменяются и не изымаются из inflight. Подпись и оба уровня
шифрования сохраняются. При отсутствии места остаётся прежний отменяемый
waiter Router; новые кадры/наблюдение/освобождение очереди продолжают drain.
etcp_router_request_send регистрирует отменяемый одноразовый запрос на канал.
Повторная регистрация того же запроса не сбрасывает ожидание. Payload ещё не
создан, поэтому 64 маленьких неизменяемых пакета в send_q не накапливаются.
Router запускает handshake даже без готового payload, затем ждёт маршрут,
отсутствие RECEIVE_BUSY, свободное окно inflight и готовность send_input_q ETCP.
Запрос использует существующий round-robin; ретрансмит имеет прежний приоритет.
Отправляем при target кадров, достижении лимита байт, несовместимости эпохи
следующего кадра или deadline головы. Новый кадр не продлевает deadline.
40мс — предел адаптивного ожидания (до первого ACK60мс), а не предел
backpressure или полного RTT.
10 кадров — максимальный размер готовой пачки; ожидания180мс ради её наполнения нет.
Прежняя защитная FIFO750 и её удаление старейшего при overflow сохраняются;
данное изменение не обещает жёсткую задержку200мс при остановившемся канале.
Перед callback Router снимает регистрацию. Сервис формирует одну пачку до
целевого числа кадров, не более1024 байт и без смешивания capture epoch/delay.
Лимит байт/граница capture могут разделить накопленные target кадров на меньшую
кодограмму: причина явно пишется как bytes/capture-change. Срок ожидания и
джиттер сами по себе никогда не разрешают отправку до накопления target.
В callback conn_send только копирует и принимает кодограмму; рекурсивная
отправка запрещена внутренним send_producing. Лишь после успешного принятия
сервис удаляет исходные кадры. При отказе они остаются в FIFO для повтора.
После возврата Router кодирует и передаёт пакет в нижний слой. При ошибке
дальнейшей отправки принятая кодограмма сохраняется в Router. Переданный пакет
не изменяется; подпись, шифрование, seq и надёжная доставка сохраняются.
Для следующей пачки можно снова запросить слот, не ожидая ACK предыдущей:
число пакетов в полёте по-прежнему ограничивает окно Router.
Закрытие/reset автоматически снимает запрос и обнуляет handle; callback может
закрыть/перезапустить канал. Смена маршрута переносит ожидание на новую очередь.
Сервис отменяет запрос до освобождения контекста. Кадры при no_route/BUSY
остаются в прежней защитной FIFO750, overflow удаляет старейший с логом.
Если полезная нагрузка устойчиво превышает полосу, упаковка не гарантирует
ограниченную задержку: потребуется отдельное управление битрейтом.
sent_ms ставится перед подачей пачки Router. Приёмник передаёт его всем кадрам,
но обновляет оценку сетевого jitter только по первому. Capture PTS остаётся
@@ -106,21 +119,21 @@ sent_ms ставится перед подачей пачки Router. Приём
недостачи и сброс устройства после начала речи используют обычный запас.
Это порог начального заполнения, не ограничение полной сквозной задержки.
cleanup/ENDED/destroy отменяют оба новых таймера и прежний Router waiter до
освобождения FIFO. Доступ к ядру только в uasync; audio capture worker API
не меняется. Счётчики tx/rx кадров и пачек разделены.
cleanup/ENDED/destroy отменяют регулятор50мс и Router-запрос до освобождения FIFO.
Доступ к ядру только в uasync; audio capture worker API не меняется.
Диагностика
-----------
call=info: стартовые target/hold, изменение target с причиной, D, полным RTT,
возрастами и hold; порог JB и фактическая глубина при первом воспроизведении.
call=debug: flow раз в секунду и TX/RX каждой пачки (count, bytes, seq, age).
etcp_route=debug: подтверждение с enqueue->ACK, EWMA и числом попыток.
Ошибки формата/аллокации/таймеров/отправки логируются. Нужны обе новые сборки.
call=info: старт mode=full-and-router-ready и target; изменение target с причиной.
call=debug: раз в секунду локальные queued/oldest/wait и Router queued/inflight,
возраст enqueue->ACK, submit->ACK, ack_bytes_500ms, число кадров и пачек.
wait=frames/handshake/no-route/peer-busy/window/transport/unregistered показывает
причину ожидания. TX каждой пачки: frames/target/bytes/oldest_us/seq/reason/remaining.
etcp_route=debug: выдача/отмена слота с waited_us, подтверждение enqueue->ACK и
число попыток. Ошибки формата, выделения, регистрации и отправки логируются.
Проверки: test_call_audio_batch (формат и регулятор), test_call (реальная
доставка 10 кадров/неполной пачки и teardown), test_etcp_router (ACK-метрики
после backpressure), test_call_jitter (один arrival на пачку, поздний пакет,
отсутствие декодирования при180мс и старт при200мс),
headless/admission и прежние проверки аудио. Аппаратный эффект проверяется
отдельным звонком и сравнением логов, не выводится из одних unit-тестов.
Проверки: test_call_audio_batch (формат, прежний выбор target), test_call (накопление
полного target на свободном транспорте, задержка при backpressure, доставка и
teardown), test_etcp_router_faults (handshake без payload, BUSY, окно, смена пути,
отмена ожидающего/отложенного запроса, reset и закрытие внутри callback).
Аппаратный эффект проверяется отдельным звонком и сравнением логов Windows/Android.