diff --git a/doc/call_audio_batch.txt b/doc/call_audio_batch.txt index d849b870..b492e9e7 100644 --- a/doc/call_audio_batch.txt +++ b/doc/call_audio_batch.txt @@ -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.