Record headless PCM framing fix and full regression results

This commit is contained in:
evgeny committed 2026-10-26 16:08:35 +01:00
1 parent 0ad80f3906
commit 54a7522dd9
3 files changed
+121 -18

No files matched your search

+99 -3
View File
@@ -11,9 +11,12 @@ call_audio уменьшали pending новой привязки и обход
check202/202 PASS,proxy9/9,burst1/1,load8/8,176с. Актуальный результат — раздел10;
история/план — разделы6–7, внедрение TX — раздел8, диагностика mesh — раздел9.
Полная проверка аудио, видео и платформенных разделов не завершена.
При продолжении подтверждён дефект исходящей PCM-очереди call_headless:
переполнение оставляет header без тела и нарушает поток. Реализация ещё
не менялась; аудит остановлен перед исправлением. Подробности — раздел11.
При продолжении подтверждён и по запросу пользователя исправлен дефект
исходящей PCM-очереди call_headless: header+PCM принимаются/отбрасываются
целиком, partial send сохраняет хвост, потери имеют отдельный учёт/диагностику.
Новая постоянная регрессия11/11 и штатный headless e2e1/1 PASS;
native build и check203/203 PASS,proxy9/9,burst1/1,load8/8,188с.
Диагностика/план — раздел11, внедрение/актуальная проверка — раздел12.
База проверки: f79b9261, чистое рабочее дерево после предыдущего push stream.
1. Подтверждённый дефект: call_start не проверяет обычную занятость
@@ -697,3 +700,96 @@ Pressure завершается ожидаемым exit1; allocations0->0. Ло
call_headless.h теперь[~]. Call0[V]/11[~]/10[ ], архитектурный документ[~],
видео[ ] сохранены. Новый полный build/check, sanitizers, аппаратный GUI/Android,
Windows/FreeBSD здесь не запускались. Исправления предыдущих разделов сохранены.
12. Headless PCM: целый кадр в ограниченной очереди — 26.10.2026
Пользователь «исправляй» разрешил внедрение плана раздела11. Базаae9d3f01;
коммиты913ae531/7c4e6f99/0ad80f39. Изменены только call_headless.c/.h,
tests/test_call_headless_queue.c и его цель в tests/Makefile.am; остальные
изменения этого шага относятся к документации/чек-листу. Wire и публичный API
сохранены, реализация radio_headless и общий call_audio DSP не менялись.
Реализация
ca_write_frame собирает header11+PCM до единственного вызова ca_send_raw.
Буфер ограничен CA_PCM_FRAME_BYTES1920+CALL_AUDIO_HDR_SIZE11, находится
на стеке; oversize и ненулевой len с NULL отклоняются с ERROR до memcpy.
При ожидающем tail очередь проверяет место для целого нового кадра:
если его недостаточно, ни header, ни PCM не дописываются. Успешный partial
send сохраняет только неотправленный tail; следующие кадры стоят после него.
Нет новых динамических выделений, таймеров или дополнительных владельцев.
Переполнение увеличивает pcm_dropped клиента и c_pcm_dropped сервиса;
decode-drop остаётся отдельным показателем. WARN показывает call_id/fd,
размер кадра, send_len/offset/capacity и оба счётчика. Первый drop логируется
сразу, следующие WARN ограничены одним в секунду (10000 timebase units).
При закрытии клиента и destroy сервиса INFO выводят полные итоги pcm_drop,
включая потери между WARN. Использованный prefix буфера до полного drain
не компактизируется: это прежняя политика ёмкости, целостность не нарушается.
Постоянная регрессия
tests/test_call_headless_queue.c включён в check_PROGRAMS для !OS_WINDOWS;
нужен GNU --wrap=send. Стенд включает production .c, как другие компонентные
тесты проекта. Один настоящий uasync на поток, свежий loopback TCP listener
с port0/клиент/HELLO и настоящие Opus encoder/decoder для каждого сценария.
Минимальный instance не создаёт call_ctx/роутер: media callback вызывается
напрямую в том же потоке. Полноценный звонок двух ядер сохраняет штатный e2e.
Поля очереди только наблюдаются, она заполняется обычными media callbacks.
Wrapper задаёт EAGAIN/short write только серверному fd; успешный prefix
действительно передаётся через TCP. Независимый reference decoder обрабатывает
все Opus-пакеты, включая отброшенные для TCP, сохраняя такое же состояние.
Сравнивается весь ожидаемый wire header+PCM байт в байт, без поиска похожего
следующего header. CHECK действует и при NDEBUG.
11 сценариев PASS:
- normal:8 кадров без backpressure, затем следующий после drain;
- frame_boundary:34 попытки,33 принятых,1 целый drop;
- overflow:40 попыток,33 принятых,7 целых drops;
- partial_header:первые5 байт переданы TCP, далее EAGAIN;40/33/7;
- partial_pcm:первые113 байт переданы TCP, далее EAGAIN;40/33/7;
- exact_fit:первые118 байт переданы,34 кадра заполняют очередь ровно65536,
потерь нет; exact_overflow:35-я попытка отбрасывается целиком;
- chunked_write:prefix5, затем drain порциями не более127 байт;
- offset_overflow:после33 queued кадров отправлены118 байт, новая попытка
отбрасывается без изменения send_len/offset; оставшийся поток корректен;
- destroy_pending:8 queued кадров освобождаются без drain;
- invalid_output:oversize1921 и NULL+1920 дают ровно2 ожидаемых ERROR,
не изменяют очередь/переданные байты; следующий допустимый кадр проходит.
После каждого обычного drain проверен следующий кадр с непрерывным состоянием
Opus. В каждом сценарии проверяются точные PCM-счётчики закрытия/destroy,
наличие WARN, баланс uasync socket/timer и allocations0->0 после cleanup.
Лог /tmp/call-headless-fix-queue.log прочитан полностью:11/11 PASS;
6 первых overflow-WARN и2 намеренных ERROR, неожиданных ERROR нет.
Чувствительность теста проверена без замены production/архивов/объектов:
временная копия регрессии включает старый instrumented .c из раздела11.
Normal PASS, на frame_boundary старый код оставляет header, queued63734,
отбрасывает PCM1920 при space1802. Проверка ожидаемой длины сразу FAIL,
ожидаемый returncode=-6 (CHECK/abort), core dump отключён для этого запуска.
До abort первый fixture освобождён с allocations0->0; cleanup второго
прерван и его баланс этим негативным запуском не заявляется.
/tmp/call-headless-fix-old-test.c/.mk, ...-old-build.log, ...-old-test.log.
Проверка окончательного исходного кода
./build.sh --no-gui -j4 PASS; после финальной правки0ad80f39 целевая
make-сборка PASS, новая регрессия11/11 и штатный test_call_headless1/1 PASS.
Логи /tmp/call-headless-fix-{build,target-build,queue,e2e}.log.
Штатный e2e использует JSON control, два настоящих ядра и TCP PCM;
он дополняет компонентную проверку очереди и остаётся однокадровым.
Полный ./check.sh:203 passed,0 failed,0 skipped (203 total),exit0,188с.
Новая цель входит в этот запуск; proxy9/9,burst1/1 (8388608 байт),
load8/8 (134217728 байт), обе стороны rc0. Логи
/tmp/call-headless-fix-full-check.log, ...-netns.log,
tests/logs/test_call_headless_queue.log и test_call_headless.log.
Запуск в отдельном sudo unshare --net от user; IPv6/lo включены только там.
Настройки хоста all/default/lo disable_ipv6=1 сохранены и проверены.
После этих проверок менялись только документация/чек-лист.
Исправление фрейминга закрыто. Отдельная задача по похожему шаблону
radio_headless остаётся на диагностику, runtime-дефект там не заявляется.
Аудит остальных call-контрактов/платформ остаётся частичным:call0[V]/11[~]/10[ ],
call_headless.h[~], архитектура[~],видео[ ]. Новые sanitizer/аппаратные GUI,
Android, Windows и FreeBSD проверки этим шагом не выполнялись. Push не выполнялся.
+6 -4
View File
@@ -23,10 +23,12 @@
Реализация, проверенный план и границы — разделы6–8 отчёта; полный аудит call/ ещё не завершён.
Проверка headless: TCP-сервис call_headless имеет собственные кодеки instance и выполняет callbacks в uasync;
он не использует DSP/jitter движка call_audio. Подтверждён дефект исходящего фрейминга при переполнении:
раздельные header/PCM могут оставить в очереди заголовок без тела. Компонентный стенд с TCP/Opus/uasync
воспроизводит сбой, обычный однокадровый e2e проходит. Реализация пока не менялась;
план атомарного добавления целого кадра — раздел11 отчёта. Проверка платформенных I/O остаётся впереди.
он не использует DSP/jitter движка call_audio. Исправлен разрыв фрейма при переполнении исходящей очереди:
header/PCM собираются до отправки, принимается или отбрасывается целый кадр, partial send сохраняет его хвост.
PCM-потери учитываются отдельно для клиента/сервиса с WARN и итогом при закрытии/destroy.
Постоянная регрессия с TCP/Opus/uasync:11/11 PASS, весь поток сравнивается с независимым decoder;
старый код выявляется на границе очереди. Штатный e2e1/1 и check203/203 PASS,proxy9/9,burst1/1,load8/8.
Реализация и границы проверки — раздел12 отчёта. Полная проверка платформенных I/O остаётся впереди.
## 1. Область
+16 -11
View File
@@ -4,17 +4,22 @@
## Текущие задачи
[ ] **call_headless: сохранять целостность PCM-кадра при переполнении TCP-очереди** — подтверждено 26.10.2026.
ca_write_frame передаёт header/PCM двумя вызовами; ca_send_raw молча отбрасывает не поместившийся фрагмент.
При backpressure заголовок помещается, PCM нет: TCP-поток теряет границы следующих кадров.
Компонентный стенд с настоящими TCP/uasync/Opus и управляемым send(EAGAIN): control PASS, pressure ожидаемо FAIL,
allocations0->0. Очередь заполняется обычными вызовами media callback, её поля вручную не подменяются.
Штатный test_call_headless1/1 PASS передаёт один кадр и переполнение не покрывает.
План: один собранный кадр за один вызов отправки; при нехватке места drop целиком с логом/учётом.
Закрепить обычную/частичную отправку, EAGAIN, границу ёмкости и восстановление после drain постоянным regression.
Реализация не менялась; аудит остановлен перед исправлением по AGENTS.md:10.
Подробности: [call_audit_findings.txt](call_audit_findings.txt),раздел11;
/tmp/call-headless-audit-queue-{build,control,pressure}.log. Аппаратный GUI/Android не проверялись.
[+] **call_headless: целостность PCM-кадра при переполнении TCP-очереди** — исправлено 26.10.2026.
Header/PCM собираются до отправки; очередь принимает целый кадр или отбрасывает его целиком.
Частичная запись сохраняет хвост перед следующими кадрами. Потери учитываются отдельно для клиента/сервиса;
WARN содержит причину/состояние очереди, итоговые счётчики выводятся при закрытии/destroy.
Постоянный test_call_headless_queue:11/11 PASS — TCP/uasync/Opus, EAGAIN/short-write, точная ёмкость,
переполнение после частичного drain, следующий кадр, destroy с очередью и недопустимый размер/NULL.
Весь полученный поток сравнивается с независимым decoder, allocations0->0; старый код ожидаемо FAIL.
Штатный e2e1/1 PASS; native build PASS; check.sh203/203 PASS,0 failed/0 skipped,
proxy9/9,burst1/1,load8/8 (134217728 байт),exit0,188с. Полный аудит call остаётся частичным.
Подробности: [call_audit_findings.txt](call_audit_findings.txt),раздел12;
/tmp/call-headless-fix-{queue,e2e,full-check}.log. Аппаратный GUI/Android не проверялись.
[ ] **radio_headless: проверить целостность PCM-кадра при переполнении TCP-очереди**.
При сравнении замечен сходный шаблон раздельной отправки header/PCM в rh_write_frame/rh_send_raw.
Runtime overflow отдельно не воспроизводился; нужны диагностика и компонентная проверка до решения об исправлении.
Наблюдение: [call_audit_findings.txt](call_audit_findings.txt),раздел11. Полный аудит рации не выполнен.
[+] **feedback: исключение и отложенное удостоверение не блокируют запуск чата** — исправлено 26.10.2026.
Исключённые/ожидающие авторы скрываются из результатов, Merkle и выдачи; записи, ver и отмены сохраняются.