Files
utun2/doc/tasks.md
T

940 lines
120 KiB
Markdown
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.
# Задачи по проекту
Сюда пишется список задач с короткой аннотацией. Если задача большая и имеет ТЗ - то ТЗ оформляется отдельным файлом, а сюда помещается аннотация и ссылка на ТЗ.
## Текущие задачи
[ ] **Разобрать нестабильную проверку аудиопауз desktop-трансляции** — 17.10.2026:
При проверке зума test_stream_view::realH264RenderingAndClose получил silenceGaps=3 вместо gapsBefore=2.
В логе есть desktop audio gap cause=pcm_short, got=96/480; видео продолжает выводиться (50 кадров к stop).
Первый полный Qt-прогон прошёл; сбой повторился с общим check.sh и после его завершения.
Причина не установлена; нужны диагностика PCM/часов и воспроизведение под нагрузкой.
Логи: /tmp/stream-zoom-full-view-audio-gap.log, /tmp/stream-zoom-full-view.log.
[ ] **Устранить коллизию порта при перезапуске узла в test_dm_e2e** — 16.10.2026:
Общий check.sh при проверке Windows-курсора: 155/156, test_dm_e2e упал в phase=9 на создании B2.
Повторный bind 127.0.0.1:33843 вернул Address already in use; отдельный повтор теста проходит.
Проверить владение/резервирование порта между остановкой B и созданием B2 при параллельном прогоне.
Логи: /tmp/win-stream-cursor-dm-e2e-failure.log, /tmp/win-stream-cursor-dm-e2e-retry.log.
[+] **Постепенно увеличивать аудиобуфер при подтверждённых сбоях backend** — 16.10.2026:
AudioDevice получает WASAPI DATA_DISCONTINUITY, ALSA EPIPE и PulseAudio hole/overflow/underflow.
Два опроса со сбоями за 5с увеличивают период на 5мс; между изменениями минимум 5с,
первый 1с после запуска пропускается. Запрошенная полная ёмкость ограничена 100мс.
Начальные настройки Linux сохранены (capture 10мс); новая сессия/устройство возвращает исходный запрос.
Backend может округлить фактический размер: он и каждый шаг записываются в лог; повторные сбои агрегируются за 5с.
Перезапуск захвата выполняется без блокировки GUI, с сохранением RX звонка/рации и безопасным stop во время close.
Проверены реальные callback-уведомления, нижняя граница/лимит, reopen/backoff и uninit=700мс.
GUI собран; 7/7 аудиотестов PASS: /tmp/audio-buffer-final-tests.log.
Проверка слышимого результата с Windows-драйвером остаётся на следующем звонке пользователя.
[+] **Проверять поступление PCM микрофона в desktop-звонках и рации** — 16.10.2026:
Секунда без первого/очередного корректного PCM отключает захват с понятным сообщением GUI.
Цифровая тишина допустима; отсутствие callbacks, nullptr и frames=0 проверяются отдельно.
RX сохраняется, PTT снимается и блокируется до выбора другого входа или новой сессии.
Неисправный backend закрывается асинхронно; stop во время закрытия не блокирует GUI,
новый захват ждёт завершения прежнего. Контекст и callback живут до завершения worker.
Тест с uninit=700мс проверяет heartbeat GUI, stop<300мс, удержание lease звонка и отсутствие повторных открытий.
GUI собран; audio_recovery, microphone_watchdog, radio_panel, call_video_encoder, call_video_clock: 5/5 PASS.
Захват экрана 3440×1440 под Xvfb: H.264/H.265 продолжают выдавать кадры, stop=7/59мс.
check.sh: 156/156, proxy 9/9, burst/load PASS. Логи: /tmp/mic-stream-final-tests.log,
/tmp/mic-stream-core-check-unrestricted.log, /tmp/stream-h265-progress.log.
[ ] **Устранить неподвижный кадр Windows-трансляции на Android и зависание stop** — 16.10.2026:
Новый 4.log и Samsung epoch=d8252b9a534ff713 установили цикл ожидания:
KEY=20669261, первый звук=21097059 (позже на 427798мкс), lookahead=80мс, written=played=0.
Cursor теперь прогревает аудио от фиксированной первой аудиометки, сохраняя ограниченный lookahead.
Регрессия с этими PTS и реальными RS/Opus/SoundTouch выдаёт PCM и продвигает часы; reset проверен отдельно.
В Windows videoLoop пишет stopped, но GUI застревает на join после возврата из функции.
Join video/audio вынесен в отдельный worker; GUI работает до полного выхода потоков, включая native TLS.
FIN отправляется после workers параллельно асинхронному закрытию микрофона; owner/lease сохраняются до завершения.
Проверяется cleanup native TLS с BlockingQueuedConnection к GUI, обычный stop и destructor.
Финальный Xvfb 3440×1440: 32/32 PASS, включая H.264/H.265, CPU consent, watchdog и общий захват рации.
Общие playback-тесты: 2/2 PASS. check.sh: 156/156, proxy 9/9, burst/load PASS (134с).
APK и Android unit-тесты собраны, Samsung RZ8R72MG64B обновлён. Старый источник виден в каталоге,
но отдаёт только остаток seq=918 без KEY, после чего новый viewer получает open timeout.
Нужна свежая трансляция/stop из Windows после пересборки; оба исправления на исходной паре устройств ещё не подтверждены.
Отдельно libx265 3440×1440 в Windows выдаёт примерно 2–3fps: это ограничение CPU остаётся.
Новый 4.log подтвердил более позднее застревание: GUI timer работает, `videoLoop()` вернулся,
но native video thread не вышел за 20с; поэтому join worker не послал FIN.
`QVideoFrame::toImage()` перенесён в долгоживущий image worker между захватом и encoder worker.
Под Xvfb конверсия 3440×1440 занимает 51–106мс и выполняется с gui_thread=0; GUI получает лишь последний кадр.
Encoder worker вышел на всех stop; полный Xvfb-тест трансляции: 32/32 PASS, /tmp/stream-persistent-image-xvfb.log.
Осталась проверка новой сборкой Windows: в Qt Multimedia другой backend и только он подтвердит исходную машину.
Логи: 4.log, /tmp/stream-viewer-new-run.log, /tmp/late-audio-test.log,
/tmp/stream-viewer-after-update.log, /tmp/stream-persistent-image-xvfb.log,
/tmp/stream-audio-stop-full-check.log.
[+] **Проверять микрофон и спрашивать перед переходом трансляции на CPU** — 16.10.2026:
По 4.log/6.log: GPU-кодировщики недоступны, WASAPI-микрофон камеры выдаёт frames=0,
повторное закрытие устройства блокировало GUI примерно на 4 с. Список кодеков больше не запускает пробное кодирование.
До первого корректного PCM не открываются видеокодировщики; тишина в полученном PCM допустима.
При отказе GPU показывается вопрос с отказом по умолчанию; согласие действует на кодек только текущей трансляции.
При отсутствии PCM в течение секунды трансляция прекращается с сообщением, без цикла повторного открытия микрофона.
Закрытие последнего audio backend идёт в worker (Windows COM и сохранение контекста до завершения учтены).
Проверены устаревший ответ, закрытие окна с вопросом, новый запуск без сохранённого согласия,
пропажа PCM после начала, отсутствие первого PCM и отзывчивость GUI при медленном закрытии.
GUI собран; Xvfb: 29/29; call_video_encoder, call_video_clock, audio_recovery: PASS.
check.sh: 156/156, proxy 9/9, burst/load PASS. Логи: /tmp/stream-start-{x11-final,related-check,full-check}.log.
[ ] **Проверить трансляцию на Windows с RYS HFR USB2.0 Camera** — 16.10.2026:
Проверить на исходном устройстве сообщение об отсутствии PCM и отзывчивость окна при завершении WASAPI,
отказ/согласие на CPU после отказа NVENC. Автотесты воспроизводят условия отказа на Linux, не Windows-драйвер.
Причина frames=0 самого микрофона ещё не установлена; подробный AudioDiag сейчас реализован только для Linux.
[+] **Снять устаревший сон пира при пробуждении через новый линк** — 16.10.2026:
После перезапуска SM colo2 сохранял peer_phase_timer прежнего соединения; normal keepalive нового линка
не снимал его из-за ka_peer_sleeping=0. Merkle отменял сессии, объявление трансляции задерживалось примерно на 110 с.
Normal keepalive теперь отменяет фазу/таймер всего ETCP_CONN независимо от флага линка, включая будущее засыпание.
Повторный RX не отодвигает TX; ACK сна не пробуждает пира; REINIT сам по себе не меняет режим сна.
Проверены UDP/TCP, новый линк, min_sleep=90 с, быстрый hide/show, повтор normal после потери/запоздалого SLEEP.
Сценарий desktop → промежуточный узел → mobile доставил источник в каталог за 1045–1047 мс после foreground,
отменив таймер сна 120 с; удержание ACTIVE трансляцией и освобождение последнего владельца также проверены.
Семь профильных C-тестов и 106 Android unit-тестов прошли; ядро и APK собраны.
Общий check.sh: 156/156, proxy 9/9, burst/load PASS (120 с).
Логи: /tmp/stream-wake-{server,standby,catalogue,service-final,android-tests,full-check}.log.
[ ] **Проверить исправление сна на SM через обновлённый colo2** — 16.10.2026:
Пользователь обновил colo2: подтверждены fc526d16/919c3d76 и новый процесс от 13:58.
Живой SM: скрытие GUI → STANDBY; открытие в 14:02:47.098 → ядро ACTIVE в .108, colo2 awake в .750.
Пробуждение произошло через 22,5 с сна, раньше min_sleep=90 с (полный сон 120 с).
Перезапуск приложения во время сна повторил исходный сценарий: colo2 сохранил ETCP_CONN 0x2344866e0288,
новые TCP-линки 6/7 поднялись в 14:05:03.103/.158, peer awake пришёл в .158, Merkle завершился в 14:05:04.718.
При открытом GUI старые фазы больше не усыпляют соединение. Логи: /tmp/stream-wake-live-{sm,colo2}-*.log.
Осталась визуальная проверка значка свежей трансляции:
во время проверки активных источников нет (count=0); пользователю отправлен запрос запустить desktop-трансляцию.
[ ] **Равномерный показ видео с минимальной задержкой** — 15.10.2026:
Общий call_video_playout подключён к Android/desktop: абсолютные сроки 1.04x, A/V -50..+40мс,
отдельная метка доступности кадра в RX port, отсутствие накопления опозданий CPU.
Android продолжает подачу decoder во время ожидания показа; desktop публикует через coalesced UI notification.
Управляемые сценарии, реальный Qt decoder с задержками сети/CPU/UI и повторным start, codec/transport
и 103 Android unit-теста прошли; ядро/ChatGUI/APK собраны, обновление установлено на Samsung и Q8.
Живой звонок 11342339676311998023: SM ~29.2fps без drops, desktop ~26.4fps с ~10% late drops.
Остаточные паузы и обратное направление ещё требуют проверки. В финальную сводку добавлены
gap_pts_us/gap_rx_us/gap_dispatch_us для точного разделения причин; подробности в doc/call_video.txt.
Финальная сборка, звонок 9002196988226353494: последнее окно SM 29.94fps без drops,
desktop 29.61fps и 8 late drops/20с. Длинные интервалы видны уже при поступлении кадров.
Обнаружено ожидание внешнего события после лимита TX flush 16x1200 байт; крупный SM-кадр
имел queue_age=39.9мс. Добавлено отменяемое продолжение через uasync_call_soon после исчерпания
лимита 16 фрагментов, с сохранением сетевого backpressure и A/V-барьера; закрытие/discard отменяют callback.
test_call_video_flush проверяет целостность 45001 байта без audio/tick, порционность, сетевые ограничения,
audio/CAPS, конкурирующий flush и отмену перед освобождением. Он, video/rate/playout, test_call (2/2)
и Qt clock/encoder (13/13) прошли; Android unit-результаты 103/103 актуальны (Gradle up-to-date).
Ядро/ChatGUI/APK собраны, оба телефона обновлены, ChatGUI перезапущен. В секундной сводке TX появились
flush_yields/runs/wait_max_us/net_wait/audio_wait, в выборочном send — budget_yields.
Живой звонок 12694689407894286842 подтвердил продолжение: SM-кадры 42429/43309 байт,
budget_yields=2, queue_age=600/500мкс. Последние 20с: SM 29.87fps без drops, desktop 29.91fps/3 late drops.
A/V внутри границ; отдельные промежутки SM до 63.8мс остаются. Краткие invalid audio clock сбрасывают
якорь видео; причина invalid в текущем логе не видна. Следующий шаг — агрегированная диагностика причин
invalid clock и времени получения снимка, затем проверка связи с gap_*; слепое изменение часов не делать.
[+] **Измерить задержку видео desktop -> Samsung по этапам** — 15.10.2026:
Добавлена выборочная трассировка по одному окну исходного PTS в секунду: encode/send/receive,
pull/queue/decode/release, Android frame commit и desktop select/publish. Протокол и A/V-планировщик не менялись.
Проверка показала две ловушки диагностики: MediaCodec callback на Samsung возвращает source PTS в поле времени,
а TextureView.onSurfaceTextureUpdated может читать timestamp предыдущего кадра до работы RenderThread.
Для Android используется registerFrameCommitCallback; это завершение UI-рендера, ещё не физическое появление пикселей.
Звонок 14610053360084326214; полные замеры в doc/call_video.txt, раздел диагностики 15.10.2026.
На стабильном участке сеть ~4–5мс, decoder SM ~6мс. RX ждёт audio clock; в обратном направлении
камера/кодер телефона уже задерживают кадр ~125мс, поэтому desktop почти не ждёт аудио перед показом.
Уменьшение только времени encoder не убирает ожидание audio clock; произвольного сдвига видео не добавлено.
Ядро, desktop и APK собраны, 103 Android unit-теста, test_call_video_clock и 13 Qt encoder-проверок прошли.
Диагностический APK установлен на Samsung, ChatGUI перезапущен; непрерывные логи и снимки сохранены в /tmp/video-timing-*.
[ ] **Снижение минимального запаса JB звонка до 20мс** — 15.10.2026:
Нижняя граница общего call_jitter изменена с 60 до 20мс; адаптация по 10-секундному окну сохранена.
Добавлен общий модуль src/call/call_delay.h/.cpp: direct PCM с удалением одиночных сэмплов (<=2%)
и SoundTouch (<=1.6), вход/выход при избытке 120/40мс, ограниченная история исходного PCM.
Обе границы перехода точные: контекст на входе отбрасывается только до уже выданной позиции;
на выходе выдаётся весь готовый Copy, затем сохранённый raw-хвост. flush/сброс аудиочасов не используются.
Прямой режим только ускорением доводит разность входа/выхода до целого числа кадров 960 сэмплов;
учитывает тишину устройства, не расходует сетевой резерв на коррекцию. Ожидания пересборки кадров нет.
JB начинает/возобновляет PCM при наличии reserve + запрошенный блок; Opus/сетевое окно остались в JB.
Регрессия ровной доставки с запасом 20мс исправлена без ослабления проверки отсутствия underrun.
test_call_delay проверяет каждый сэмпл по Copy/Mix, 20 фаз доставки, 20 начальных пауз,
200 границ повторного переключения, хвост без flush, изменяемые pull 1..8192 сэмплов.
test_call_jitter проверяет перебой 80мс, рост/спад резерва и отсутствие новых underrun после восстановления.
Семь профильных C++-тестов и полный check.sh (ядро/proxy/burst/load) проходят; desktop/APK собраны,
Android unit-тесты проходят. В периодический лог JB добавлены режим, точный tempo, фаза и число удалений.
APK установлен на оба телефона. В живом desktop -> Samsung звонке стабильный direct: tempo=1, phase=0,
JB reserve=20мс, AudioTrack queue=20мс, hardware underrun=0; акустический end-to-end ещё не измерен.
Дополнительная задержка обнаружена в Android output: AudioFlinger 113–114мс при app queue=20мс,
обычный PRIMARY без FAST. В сохранённой трассе timestamp даёт 137–140мс при app queue=40мс.
Android теперь запрашивает PERFORMANCE_MODE_LOW_LATENCY, логирует принятый режим и задержку outputUs;
аппаратный timestamp используется для A/V независимо от debug. При потере timestamp часы устаревают,
возврат к head после аппаратного якоря запрещён; смена маршрута инвалидирует старую метку.
После нулевой AudioTrack.write повторный JNI progress не вызывается; PCM не отбрасывается.
Desktop: готовая PCM-очередь адаптируется 40 -> 20мс, учитывает полный callback, растёт при недостачах;
неудачные пробы уменьшают частоту последующих попыток. Частичный блок учитывается отдельно.
Оба UI показывают очередь приложения и полный аудиовыход (он уже включает очередь, складывать нельзя).
100 Android unit-тестов и 10 профильных C++/Qt-тестов прошли; ядро, desktop и APK собраны.
Обновление установлено на SM_A525F и Q8_DA6B8P01, приложения запущены, непрерывный logcat пишется в /tmp/call-output-*-live.log.
Живой звонок c66f218c68855546 после обновления: Samsung отклонил FAST (requested=0x4, output=0x2),
AudioPolicy назначила VOIP_RX=0x8000 на PRIMARY. При app queue=20мс outputUs в среднем 112.6мс,
при 40мс — 138.2мс; hardware underrun=0. Переключение speaker -> earpiece обновило timestamp generation;
progressCall сократился с 6–7мс до ~0.06–0.2мс на блок. Сетевой JB по-прежнему растёт при недостачах.
Desktop после пробы держит один готовый блок: pcm_after_mix в среднем ~18.6мс вместо ~38.6мс;
после начального пустого callback новых starvation нет. Стартовый callback повысил резерв 2 -> 3,
возврат 3 -> 2 -> 1 занял 40с; обучение стартового периода стоит отделить от рабочего starvation.
Отдельный APK audio-probe проверен на обоих телефонах: VOICE_COMMUNICATION/SPEECH, активный захват,
тишина на выходе, данные микрофона отбрасываются. На этапе этой пробы основное приложение использовало AudioTrack.
Samsung: AudioTrack с буфером 20мс даёт outputUs ~103мс в среднем; повторное открытие не включает FAST.
AAudio/MMAP на speaker: shared mono/stereo ~30мс, exclusive mono/stereo ~24мс, буфер 20мс, underrun=0.
Earpiece отсутствует в MMAP-профиле устройства; AAudio падает в legacy shared с буфером 40мс и outputUs ~129мс.
Проверен круг speaker -> earpiece -> speaker: обе смены дают AAUDIO_ERROR_DISCONNECTED;
повторное открытие speaker возвращает MMAP/exclusive и 24.281мс в среднем (22.471..25.700), underrun=0.
Q8: все варианты AAudio остаются legacy, outputUs ~166–172мс при буфере 40мс.
AudioTrack Q8 с 20мс нестабилен (353/352/362 underrun за три этапа по 8с);
контроль с 40мс даёт 160–162мс в среднем и ноль underrun на всех трёх этапах.
Это оценка аудиовыхода по timestamp, включая очередь приложения, не акустическая задержка всего звонка.
Изолированная проба не проверяет DSP-нагрузку реального звонка и качество AEC; перед интеграцией нужны эти проверки.
Следующий этап: один владелец выхода, повторный выбор быстрого backend после подтверждённой смены маршрута,
закрытие/открытие вне realtime callback, новая эпоха аппаратных часов при сохранении шкалы медиа/JB.
Callback должен только выдавать подготовленный PCM. Legacy AAudio не дал выигрыша: сохранять AudioTrack fallback.
Смена маршрута не должна навсегда запрещать новую пробу MMAP; неудачи ограничивать в пределах текущего маршрута.
Не обещать бесшовность аппаратного DISCONNECTED: судьбу PCM, уже переданного старому устройству, нужно определить отдельно.
Сборки ядра, :app:assembleDebug и :audio-probe:assembleDebug прошли; оба диагностических прогона освободили ресурсы.
Логи: /tmp/aaudio-probe-{sm,q8}.log; AudioFlinger: /tmp/aaudio-probe-{sm,q8}-flinger.txt;
AudioPolicy Samsung: /tmp/aaudio-probe-sm-policy.txt.
Повтор: установить audio-probe/build/outputs/apk/debug/audio-probe-debug.apk через adb install -g -r;
открыть com.utun.audioprobe/.ProbeActivity при завершённых звонках и оставить Activity видимой.
Полная матрица запускается без аргументов; для круга Samsung: --es api aaudio --ei channels 1
--es sharing exclusive --ez roundtrip true --ei seconds 20; контроль Q8: --es api track --ei buffer_ms 40.
Логи adb logcat -s AudioProbe; для нового прогона сначала am force-stop com.utun.audioprobe после завершения предыдущего.
Реализован CallAudioOutput: AAudio для подтверждённого SPEAKER, AudioTrack для остальных выходов/отказа fast.
AAudio пишет подготовленный PCM по аппаратному периоду с ограниченным общим таймаутом 100мс;
дополнительной PCM-очереди/callback нет. NON_BLOCKING заполняет ёмкость MMAP сверх рабочего bufferSize:
прямая проба дала ~63мс, штатное ожидание по периоду — ~24.4мс без underrun и с восстановлением после route change.
Источник поведения: AOSP AudioStreamInternalPlay::processDataNow и AudioStreamInternal::processData.
Подтверждённый AudioManager device ID запускает повторный выбор выхода; одинаковые уведомления игнорируются.
DISCONNECTED/DEAD_OBJECT обрабатывает playback worker, повтор ограничен текущим маршрутом, далее AudioTrack.
Новое устройство получает локальный head=0 и общий base=accepted PCM. Незаписанный хвост блока сохраняется.
Очередь уже закрытого устройства не переигрывается: pendingFrames логируется, при переключении возможен короткий разрыв.
call_audio_suspend_device инвалидирует аппаратный якорь без сброса JB/DSP/PTS. Старые timestamps отвергаются по generation.
AEC использует полную задержку выхода и возраст аппаратной метки захвата, без смешивания старого/нового frame counter.
Реальный видеозвонок на Samsung: SPEAKER ~23.1мс, wired MMAP ~23.4мс, EARPIECE AudioTrack ~137мс при буфере 40мс;
возврат EARPIECE -> SPEAKER снова выбирает MMAP. На всех выходах hardware underrun=0, ошибок аудиочасов нет.
Однако wired MMAP физически продолжал играть из динамика: Telecom, AudioPolicy и HAL показывали headset/0x4,
пользователь дважды подтвердил неверный звук. Контроль с AudioTrack исправил физический выход (подтверждено пользователем).
Поэтому быстрый backend разрешён только на SPEAKER; для гарнитур сохранён AudioTrack, несмотря на формальную доступность MMAP.
Исправлен auto-headset: ручной выбор speaker действует до следующего подключения/отключения гарнитуры,
дубликаты событий не отменяют ручной выбор. Рация явно отключает авторежим при ручном выборе, её поведение сохранено.
Добавлены INFO только при изменении списка устройств, Telecom endpoints и видимого состояния аудиокнопок.
103 Android unit-теста, test_call_timeline, test_call_video_clock, test_call_delay, test_call_jitter прошли;
ядро и APK собраны. Финальный APK установлен на оба телефона. Логи переходов: /tmp/route-sm-live.log;
противоречащий физическому звуку HAL-маршрут: /tmp/headset-failure-{audio,policy,flinger}.txt.
[ ] **Доступность разговорного динамика в UI звонка** — при подключённой проводной гарнитуре Samsung убирает
EARPIECE из Telecom endpoints, но кнопка остаётся доступной по наличию физического встроенного устройства.
Нажатие создаёт отложенный запрос, который исполняется после отключения гарнитуры. Согласовать UI с доступными endpoints.
Также выбор проводной гарнитуры в CallScreen сейчас запрашивает BLUETOOTH_CONNECT при отсутствии этого разрешения;
проверку разрешения нужно привязать к выбранному типу гарнитуры.
[x] **Завершение звонка и видеопорта после обрыва транспорта** — 15.10.2026:
Трасса test_call доказала потерю HANGUP при смене эпохи сигналинга: router reset удалял старую очередь.
HANGUP/CANCEL/DECLINE теперь подтверждаются END_ACK и повторяются каждые 300мс, максимум 20с.
Медиа/локальная TX-очередь освобождаются сразу, CM и завершённая запись — после ACK или deadline.
Проверены причины ENDED, потеря двух ACK, повторный HANGUP после удаления записи во время нового звонка,
одновременное завершение, DECLINE и освобождение без подтверждения. Поздние видеокоманды отменяются;
старый close не закрывает новый видеопорт, detach отменяет ожидающий post.
Core/desktop/APK собраны, 154 теста ядра, test_call_video_clock и 97 Android unit-тестов прошли.
Обновление установлено на Samsung RZ8R72MG64B; ChatGUI требует перезапуска для нового протокола.
Проверка реального звонка после обновления обеих сторон остаётся ручной.
[ ] **Видеозвонки Android и ChatGUI** — 14.10.2026:
H.265 с fallback H.264, смена камеры/разрешения/кодека/битрейта во время звонка.
Общая шкала захвата, приёмное видео следует аудиоряду; адаптация по ACK 500мс/50мс и задолженности.
Реализованы router ACK/debt и подключение регулятора к видеотранспорту; check.sh 154/154 + proxy/burst/load проходят.
Реализован вариант 2: фактическая карта Copy/Mix SoundTouch, CallTimeline, capture PTS/эпоха/Opus delay
в протоколе, часы воспроизведения desktop/Android. Сборки успешны, 79 Kotlin-тестов и профильные C++-тесты проходят.
Добавлены видеопротокол, CAPS/ACK, ограниченная сборка/отправка, отдельные очереди audio/video/control,
удержание TX-видео по аудио, generation-safe bitrate ACK. Сетевой тест проверяет backpressure,
смену H.265/H.264 и hangup; payload синтетический, реальные codecs/камера/UI ещё не подключены.
Выявлена нестыковка capabilities: нужны profile/level/tier и предел bitrate/VBV.
x265 может отменить reconfigure при смене level и вернуть 0; ACK требует проверки применения.
По правилу AGENTS.md подключение codecs остановлено; решение и оставшиеся этапы описаны в плане.
Добавлен атомарный диапазон битрейта в настройках аудио ChatGUI/Android: по умолчанию 300–4000 кбит/с.
Применяется во время звонка, учитывает codec cap и незавершённую команду. Модель плохой/хорошей связи
достигает обеих границ без неограниченного роста очереди; сетевой тест смены диапазона проходит.
ChatGUI собран, Android assembleDebug + 81 unit-тест прошли; итоговый check.sh 154/154 + proxy/burst/load PASS.
Камера/codec/render ещё не подключены.
Перед интеграцией H.265 найден дефект x265 4.1: reconfigure/getter сообщают 300 кбит/с,
реальный выход остаётся 4 Мбит/с. Ручная цель probe_call_x265 воспроизводит отказ.
Минимальный патч владения параметрами проверен на отдельной библиотеке в /tmp:
реальный выход 4.02 -> 0.298 -> 4.21 Мбит/с, декодируются 360/360 кадров.
Патч сохранён в tools/chatgui/ffmpeg/patches, к сборке/приложению пока не подключён.
Пользователь выбрал переключение на ближайшем плановом IDR: проверено пересоздание x265 без патча,
4.01 -> 0.310 -> 4.02 Мбит/с, 360/360 кадров декодируются с сохранёнными PTS кодера.
Обычный reconfigure на IDR не помогает. В плане уточнены ожидание <= одного GOP, pending ACK,
backpressure и сохранение аудиошкалы; подключение к платформенным workers ещё предстоит.
Реализован ChatGUI CallVideoEncoder поверх выделенного общего LiveVideoEncoder:
проверка фактического профиля декодером, pending-команда, новый контекст на IDR,
сохранение PTS/старого контекста при отказе, предел bitrate и защита generation/request.
Реальная проверка H.264/H.265: 360 кадров на codec, 4M -> 300k -> 4M, один decoder, 5/5 cases PASS.
Трансляции: 11 PASS, 1 skip (Xvfb); ChatGUI собран; check.sh 154/154 + proxy 9/9 + burst/load PASS.
Реализован CAPS envelope: фиксированные profile/tier, согласование level и пределов bitrate/VBV,
H.265 -> H.264, проверка TX/RX и неизменности формата внутри generation. CallVideoEncoder получает общий формат.
При сужении peer CAPS ожидающий кадр отбрасывается и admission закрывается; сетевой тест 2/2 PASS.
Реальная codec-проверка повторена с выбранным общим кодом level 3.0: 5/5 cases PASS, 360 кадров на codec.
Итоговые ChatGUI/Android assembleDebug собраны; check.sh 154/154, proxy 9/9, burst/load PASS (128с).
Подключены общий ограниченный call_video_port, desktop camera/encoder/decoder/audio-clock render и окно управления;
Android JNI/Camera2/YUV/MediaCodec/RX Surface, CallService и экран управления. Обе сборки проходят.
Новые сетевой port-тест 2/2 и production desktop decoder 5/5 проходят; полный видеозвонок ещё не принят.
Аппаратные блокеры устранены: общий C validator, AVC Baseline/CB, нормативный DPB,
независимые encoder/decoder probes, фактические profile/level, VBV убран из wire.
Decoder сообщает acceptance/rejection; Auto делает fallback, отдельный KEY request восстанавливает references.
Android меняет bitrate без остановки MediaCodec на IDR; при отказе API последовательно заменяет encoder с восстановлением.
Unisoc кодирует HEVC и AVC; Samsung кодирует AVC и независимо принимает HEVC.
Проверены аппаратные 4M -> 300k -> 4M, HEVC Unisoc -> Samsung, AVC Samsung -> Unisoc,
все три потока -> production decoder ChatGUI. AVC Unisoc -> Samsung пока вернул 3/4
кадров конечной пробы и требует диагностики. APK установлен на оба телефона.
Итог: check.sh 154/154 + proxy 9/9 + burst/load, Qt codecs 6/6, Kotlin 81/81 PASS.
15.10.2026: USB-камера ChatGUI отдаёт кадры; обнаружен и исправлен отказ обоих TX codecs
из-за LC_NUMERIC=ru_RU: дробный level 3.1 заменён целочисленным параметром 31.
ChatGUI пересобран; Qt codecs 10/10 PASS в C и ru_RU.UTF-8, включая 720p и смену bitrate.
UI исправлен: Android fullscreen RX + своя миниатюра, управление и диагностика отделены;
desktop — отдельное изменяемое окно видео со своей миниатюрой в углу; звонок и настройки — в своём окне.
Только при отсутствии RX своя миниатюра остаётся в окне звонка. Закрытие видеоокна не завершает звонок.
Android сохраняет ориентацию интерфейса, поворачивает только большое видео и вмещает весь кадр без обрезки.
Android: Назад из видео открывает управление звонком; две миниатюры разворачиваются нажатием,
второе видео остаётся в углу. RX TextureView/Surface сохраняются при смене режима.
Кнопки учитывают системные панели (включая боковую навигацию) и вырез экрана.
Своё видео теперь идёт напрямую Camera2 -> TextureView через общий StreamPreview: SM 29–30 fps,
без прежней Bitmap-конвертации 192 px / 5 fps; Surface удерживается camera session до закрытия.
Низкий FPS desktop -> SM: capture=30, encoded=20, accepted=5, audio_busy=15, RX late=0.
Исправлены порог 33333мкс (бюджет кадров с допуском) и ожидание аудио (FIFO до 32 кадров/500мс/2MiB).
Повторный звонок: desktop TX / SM RX около 30 fps, audio_busy=0, late=0.
Остаточные пропуски при уходе фазы камеры исправлены; регрессия охватывает 10 минут и вход 30/40/60 fps.
Исчезновение RX на desktop: SM откладывал bitrate из-за автоматических IDR до тайм-аута 12с.
Граница смены bitrate теперь отсчитывается от нашего запроса IDR, автоматический IDR её не переносит.
Тесты: KEY/P за audio barrier, порядок и переполнение; Qt cadence/codec/clock; 81 Android unit — PASS.
Видео удерживает экран включённым без proximity-overlay; EARPIECE -> SPEAKER только после FAR,
UNKNOWN/NEAR ждут, ручной выбор/выключение видео/конец звонка отменяют ожидание. HEADSET сохраняется.
Фризы: обе платформы сохраняют decoder при коррекции audio epoch; production RX 90/90 кадров,
32 коррекции часов, 0 KEY requests/rejections. Android Camera2 больше не теряет кадры на пороге 33333мкс.
Desktop готовит encoder при смене bitrate в фоне, применяет на IDR; Qt codecs 10/10 PASS.
Runtime bitrate проверен на Samsung AVC и Unisoc HEVC/AVC: все 360 кадров каждого потока,
ограничение low-rate и возврат к 4M. Android сохраняет P-кадры, ожидающие нового KEY.
Итог: Android 81/81, check.sh 154/154 + proxy 9/9 + burst/load PASS; APK обновлён на обоих телефонах.
Осталась ручная приёмка полного звонка с камерами, Surface, A/V и переключениями после исправления.
Аппаратные probes используют синтетические кадры.
Контракты, этапы и проверки: `doc/call_video.txt`.
[+] **Android live: увеличение и перемещение видео как в просмотрщике файлов** — 14.10.2026:
Общий VideoZoomState задаёт масштаб 1x..4x вокруг центра жеста, ограничение сдвига и центрирование при возврате к 1x.
File/live используют одну геометрию; смена размеров окна или aspect ограничивает текущий offset заново.
Жесты преобразуют только GraphicsLayer видео и продлевают таймер controls, без пересоздания TextureView/decoder/reader.
Добавлены пять проверок геометрии: точка под пальцами, границы сдвига, возврат к 1x, верхний предел и смена размеров.
Все 75 Kotlin-тестов и assembleDebug прошли; APK установлен на SM.
На SM проверены pinch до 4x, перемещение до границ и возврат к 1x/Offset.Zero; во время жестов viewer продолжал показ.
Логи: /tmp/stream-zoom-android-build.log, /tmp/stream-zoom-sm.log, /tmp/stream-zoom-check-final.log.
[ ] **Тесты: нестабильное завершение test_stcp_traffic** — 14.10.2026:
В полном прогоне после NCD CLOSE server получил 1029466/1048576 bytes (done=0), client — 1048576 (done=1).
Упала проверка test_stcp_traffic.c:216; отдельный повтор прошёл. Причина не установлена, сетевой код в задаче zoom не менялся.
Проверить завершение двусторонней передачи относительно закрытия handle; первичный лог сохранён: /tmp/stream-zoom-stcp-first.log.
[+] **Android live: полноэкранный просмотр с автоповоротом и скрываемым управлением** — 14.10.2026:
StreamViewerScreen выбирает sensor landscape/portrait по aspect первого KEY, уже учитывающему rotation источника.
Видео вписано целиком в экран, без зависимости от надписей; имя, статус и крестик закрытия находятся поверх изображения.
Управление скрывается через 3s live и возвращается касанием; при подключении/ошибке остаётся видно.
Выход восстанавливает ориентацию и системные панели. Capture preview сохраняет отдельное управление публикацией.
На SM подтверждены landscape, TextureView 1920x1080 в экране 2400x1080, скрытие/возврат управления,
неизменные bounds видео, закрытие крестиком и возврат в portrait. Поворот не пересоздал viewer; более 2000 кадров, underruns=0.
APK установлен на SM; 70 Kotlin-тестов, 151 тест ядра, proxy 9/9, burst и load прошли.
Логи: /tmp/stream-viewer-android-build.log, /tmp/stream-viewer-check.log, /tmp/stream-viewer-sm.log.
[ ] **Тесты: диагностировать нестабильную проверку TX snapshot в test_android_stream** — 14.10.2026:
В полном прогоне один раз упала строка 177: snapshot успешен и 0 < video_bytes < 500000 после test_clock_run_for(ua, 1000).
Сам publisher обновляет snapshot таймером 1000; текущий CHECK не выводит result/sample_us/video_bytes.
Отдельный повтор и следующий полный прогон прошли. Добавить значения и проверить ожидание конкретного снимка;
причина не установлена, Kotlin-аудиовывод этот C-тест не вызывает.
Логи прогонов: /tmp/stream-audio-check-host.log, /tmp/stream-audio-native-retry.log, /tmp/stream-audio-check-final.log.
[+] **Android live: убрать остановку просмотра SM при запуске AudioTrack** — 14.10.2026:
StreamAudioOutput владеет устройством и одним остатком PCM; WRITE_NON_BLOCKING вызывается один раз за проход worker.
Видео и control продолжают обслуживаться при частичной/нулевой записи; 100ms ожидание внутри write удалено.
Аппаратные часы берутся из playbackHeadPosition без экстраполяции; пауза сохраняет PCM, GAP сбрасывает весь timeline.
Запас PCM соответствует фактическому bufferSizeInFrames, короткий EOF получает ограниченную тишину без сдвига media PTS.
Проверены 13 регрессий аудиовывода; все 70 Kotlin-тестов и assembleDebug прошли.
APK установлен только на SM. Первый просмотр: 1203 показанных кадра за 43s, discarded=0 и underruns=0;
повторное открытие также работает, аппаратный старт занял 206ms и 185ms вместо прежнего ошибочного лимита 100ms.
Повтор полного прогона ядра: 151/151; отдельный нестабильный CHECK статистики вынесен выше.
Контракт: doc/stream.txt. Логи: /tmp/stream-audio-sm-final.log, /tmp/stream-audio-android-build.log.
[+] **Live: согласовать выдачу cursor с проверкой revision/KEY в media store** — 14.10.2026:
Каждый cursor хранит revision последнего выданного полного видео и пропускает новую только с полным KEY.
Неполный кадр прежней revision удаляется; аудио и чтение старой истории другими readers сохраняются.
После GAP, нарушения последовательности фрагментов и вытеснения reader начинает с полного KEY;
зависимые кадры и частичный KEY не выдаются. Готовый KEY не ждёт таймера.
Регрессии включены в обычный test_stream_media; отдельный запуск: `tests/test_stream_media --revision-transition`.
Неиспользуемый stream_media_receiver удалён; сборка, FEC, конфликты формата и восстановление проверяются на store/cursor.
Desktop/Android используют общий stream_media_open с проверкой выбранной эпохи и откатом нового owner при ошибке.
Дополнительный reader-объект не нужен: владение и курсор уже находятся в STREAM_HANDLE.
[+] **Live: оценить оставшиеся оптимизации архитектурного плана** — 14.10.2026:
stream_member_supernode читает adm_tags конкретного node_id при deleted=0, без списка канала, сортировки и снимков узлов.
Синтетический замер SQLite в памяти: проверка роли 1024 участников — около 540 мс прежним способом против 2,9 мс рабочим API.
test_stream_service проверяет подписанные выдачу/отзыв роли, изоляцию каналов, absent/deleted и независимость от чужого snapshot.
Полная проверка корректного профиля stream_member_load занимает около 0,30 мс на этом стенде; проверки подписей сохранены.
Кэш авторизации не добавлен: он требует учёта участников, подписантов и ключей канала, одной версии профиля недостаточно.
Relay/network оставлены вместе: общий транспорт, учёт активных выдач и срок жизни подписки уже имеют единое владение.
Механический перенос потребовал бы дополнительных внутренних интерфейсов без упрощения жизненного цикла.
[+] **Live: прямое превью Android без собственного decoder** — 14.10.2026:
Камера одновременно выводит в encoder Surface и TextureView; собственное превью больше не открывает
stream viewer/cursor, MediaCodec decoder, AudioTrack и адаптивные часы воспроизведения.
Attach/detach меняет только camera session, сохраняя encoder, audio, revision и origin;
ON_STOP снимает preview output сразу, без ожидания Compose recomposition. Отказ preview сохраняет encoder-only эфир.
Surface/texture удерживаются UI, ожидающими командами и camera sessions до окончания использования;
CameraDevice.onClosed освобождает также sessions, для которых Android не доставил отдельный onClosed.
TextureView сам учитывает sensor orientation; дополнительный UI rotation компенсирует лишь поворот дисплея.
Повторный поворот сенсора убран, DisplayListener учитывает также 180° без изменения размеров окна.
Диагностика показывает native transform, sensor/display/UI rotation, first frame, FPS, возраст кадров и освобождение outputs.
REALTIME timestamp сравнивается с elapsedRealtimeNanos; UNKNOWN не выдаёт выдуманный абсолютный возраст.
На SM проверены AV1, задняя/передняя камеры, ручной поворот, фон/возврат, закрытие/открытие preview,
полная остановка и повторный запуск. Нет собственного decoder; типичный возраст кадров около 130ms
вместо накопленных 6s; перед stop median=133.7ms, p95=175.7ms по 297 диагностическим samples.
Stop освободил codec и все sessions, camera HandlerThread завершён; после проверки восстановлены AV1/main/0°.
151 тест ядра и Kotlin unit tests прошли, в том числе 6 проверок preview; APK установлен на SM.
Архитектура: `doc/stream.txt`, `doc/service_lifecycle.md`.
Логи: `/tmp/direct-preview-{full-check,android-orientation-build,sm-live}.log`.
[+] **Live: независимая подача decoder и устранение вечного ожидания AV1 на SM** — 14.10.2026:
Причина: Android подавал максимум три кадра и читал видео только на 80ms вперёд от остановившегося clock;
c2.android.av1-dav1d.decoder требовал заполнения своего конвейера. KEY уже был принят, но UI продолжал ждать KEY.
Общий cursor теперь запрашивает следующий видеокадр независимо от PTS показа; audio сохраняет временной lookahead.
Bridges готовят один ответ на запрос, получение ответа/AVAILABLE не создают скрытого prefetch.
Android StreamDecodePump держит один input и один output, обслуживает выход перед входом и использует готовность codec.
KEY/decoder ожидания разделены; старт clock/audio после первого decoded frame, low latency при поддержке.
Защитный guard учитывает наблюдённый decoder lead; EOF освобождает inflight metadata и не блокирует audio tail.
Desktop использует тот же контракт: один рабочий AVPacket, два готовых изображения, EAGAIN сохраняет вход,
FIN дренирует decoder до EOF. Кодек/rotation меняют video revision, аудиошкала сохраняется.
151 тест ядра без ошибок/пропусков, proxy/integration/burst/load прошли; check.sh — 126s.
Четыре CTest stream/audio timing прошли; восемь Kotlin pump-сценариев прошли, APK обоих ABI и vibechat собраны.
Проверены 4/8 входных кадров при замороженном clock, сетевые паузы, поздний ответ чтения, пустой EOS и guard.
Настоящие FFmpeg кадры с задержкой выхода в четыре кадра: запуск после 80ms и полный drain короткого потока из трёх кадров.
Реальный AV1 на SM-A525F: первый decoded frame через 67–117ms после KEY в проверенных запусках,
длительный показ и поворот работают; завершённый запуск показал 21609/21609 decoded/shown, без discarded.
Исправленный APK установлен на SM. Сетевой протокол и формат RS остаются прежними; colo2/Q8 не обновлялись.
Архитектура: `doc/stream.txt`, `doc/service_lifecycle.md`.
Логи: `/tmp/av1-pump-{full-check,ring-test,bridge-test,service-test,gui-tests,android-final-build,sm-live}.log`.
[+] **Live: публикация с desktop ChatGUI** — 14.10.2026:
Камера, микрофон, экран и окно через Qt >=6.6 Multimedia/FFmpeg; Wayland/XWayland использует системный портал.
Отдельный controller сохраняет эфир при закрытии окна, сырое превью обновляется до 30Hz независимо от encode.
Выбор рабочего H.264/H.265/VP9/AV1/H.266, разрешения/FPS, bitrate и поворота 0/90/270 с отметкой верха.
Encoder проверяет два принудительных KEY, затем открывает чистую сессию; hardware имеет приоритет.
Смена видеонастроек сохраняет capture, звук и source_epoch; libx264 меняет bitrate без смены encoder.
Ошибка видеорежима откатывает последнюю подтверждённую конфигурацию; fatal Opus завершает эфир и освобождает микрофон.
Stereo Opus/128kbps с общим gain и текущими настройками компрессора рации; mono input обозначается явно.
Общий C stream_publisher для Android/desktop: ограниченные очереди/admission/KEY recovery, uAV2/RS, FIN/drain 2s,
согласованные 100ms TX snapshots (video queue, all-connection inflight, send buffer, ACK_1s). Протокол не меняется.
Microphone lease публикации эксклюзивен, прежняя совместная работа голосовых функций сохраняется.
151 тест ядра и proxy/integration/burst/load прошли; полный check.sh — 129s. Все 32 CTest ChatGUI прошли.
Publisher отдельно: 11 проверок прошли, экранный сценарий запущен отдельно под Xvfb/private D-Bus — без пропусков.
Проверены реальные H.264/H.265/VP9/AV1 encoder/decoder, сохранение decoder при изменении libx264 bitrate,
настоящий X11 screen/window capture, непрерывный неподвижный экран, сырое превью, два стереотона,
H.264 → VP9 и rollback без смены audio/source_epoch, Opus failure, FIN и concurrent detach/leak count.
vibechat и APK arm64-v8a/x86_64 собраны, Kotlin unit tests прошли; Windows runtime/installer fixtures прошли.
Физическая камера, захват через Wayland portal и Windows runtime вручную не проверялись; VVC encoder отсутствует.
Устройства/colo2 не обновлялись. Архитектура: `doc/stream.txt`, `doc/service_lifecycle.md`.
Логи: `/tmp/desktop-stream-{full-check,final-gui-tests,final-publish-test,screen-test,android-build,runtime-test,installer-test}.log`.
[+] **Live: выбор видеокодека/битрейта и статистика отправки 10Hz** — 14.10.2026:
Android показывает доступные Surface encoder в порядке H.264/H.265/VP9/AV1/H.266,
проверяя профиль, разрешение/FPS и диапазон bitrate; аппаратные encoder имеют приоритет.
Битрейт выбирается отдельно (Авто либо пресет), LIVE обновляется без перезапуска encoder,
при отказе используется смена видеоконфигурации с rollback. Звук и source_epoch сохраняются.
uAV2: прежний 32-byte header, пять video_codec IDs, KEY = config_length:4BE/config/access unit.
Конфигурация повторяется при каждом KEY и защищена общей подписью/RS; оба плеера выбирают decoder по codec ID.
NAL parameter sets объединяются без дублирования, partial codec config собирается с пределом 64KiB.
Publisher каждые 100ms показывает остаток video queue, общий inflight, полный send buffer и ACK_1s.
Буфер учитывает отдельные очереди video/audio, ожидающие RS-выдачи и ETCP/normalizer без двойного учёта input_send_q;
историю кольца не включает. ACK всех соединений учитывается один раз при подтверждении найденного пакета;
окно — десять завершённых buckets по 100ms, переживает REINIT/close пира и не требует BBR link.
Статистика имеет отдельный StateFlow; строки не меняют высоту превью при обычном изменении чисел.
Реальные H.264/H.265/VP9/AV1, отдельная decoder configuration, FIN и смена revision проверены.
H.266 проверен на уровне формата/KEY; реального VVC encoder в тестовом окружении нет.
Устранена блокировка нового desktop viewer старыми control records в лимите подготовки медиа.
151 тест ядра прошёл без ошибок/пропусков; check.sh с proxy/burst/load — 119s.
Qt stream/audio timing и Kotlin-проверки прошли; vibechat и APK arm64-v8a/x86_64 собраны.
Устройства/colo2 не обновлялись. Протокол и формулы: `doc/stream.txt`, lifecycle: `doc/service_lifecycle.md`.
Логи: `/tmp/stream-codecs-{full-check,final-gui-tests,android-build,media-test,tx-test,native-test}.log`.
[+] **Live: воспроизведение из RS-кольца и минутная адаптация задержки** — 14.10.2026:
Android и desktop используют общее кольцо кодированных данных, метаданные PTS/KEY и отдельные
cursor каждого reader. Пауза player не останавливает live ingest/selector; длинные кадры собираются
ограниченными проходами с отложенным продолжением без ожидания новых пакетов.
Убрана фиксированная стартовая буферизация 150ms; вне кольца остаются ближайшие кадры и рабочая порция PCM.
Общий контроллер хранит 60 секундных минимумов запаса. История корректируется по фактическому
простою/услышанному материалу, включая аппаратную очередь и расход ранее поставленного ускоренного PCM.
После полной здоровой минуты плавный темп до x1.1 уменьшает задержку до безопасного остатка;
SoundTouch сохраняет высоту звука и стереобаланс. Обычная нехватка сохраняет decoder references;
GAP, вытеснение и разрыв медиапоследовательности начинают новый KEY и новую историю.
FIN дочитывается каждым reader; close завершённого publisher сохраняет кольцо для локальных owners.
Проверены шестисекундная пауза сетевого reader без restart, точные remote/local FIN drain,
независимые cursors, поздняя повреждённая RS-часть, большой кадр, разрывы, конфигурация и границы PTS.
Реальные H.264/Opus: 30fps при audio latency 200ms, preroll, revision/rotation, stereo x1.1 без изменения тона,
физические аудиочасы, громкость и баланс памяти. Диагностика показывает запас/минимум, коррекцию, темп и wait/resume.
150 тестов ядра прошли без ошибок/пропусков; полный check.sh с proxy/burst/load — 129s.
Три Qt stream/audio timing теста прошли; vibechat и APK arm64-v8a/x86_64 собраны.
Устройства/colo2 в этой задаче не обновлялись. Архитектура: `doc/stream.txt`, lifecycle: `doc/service_lifecycle.md`.
Логи: `/tmp/stream-playback-{clock-test,full-check}.log`, `/tmp/stream-final-{gui-tests,desktop-build,android-build}.log`.
[+] **Live: переменный размер RS и одна подпись внутри пачки** — 13.10.2026:
RS принимает фактическую длину, уменьшает все части одной пачки до одинакового минимального размера
и дополняет максимум k-1 нулями; один контекст/матрица используются повторно, без аллокаций RS на encode/decode.
Источник подписывает метаданные и содержимое один раз, затем RS защищает сообщение вместе с 64-байтной подписью.
Проверка источника выполняется после восстановления; неверная подпись/подписанные поля дают один GAP без закрытия owner.
Следующая корректная пачка принимается. Ретранслятор пересылает части до decode, сохраняя малую задержку.
Дескриптор хранит максимальный размер, кольцо/очереди/метрики — фактические длины; слоты по-прежнему резервируются по максимуму.
При 6+2 содержимое 1000 байт даёт части 243 байта вместо 1300; полная вместимость содержимого — 7345 байт.
Wire version=5; бинарники участников трансляции нужно обновить вместе. Формат описан в `doc/stream.txt`.
Проверены все 28 пар потерь, малые/полные пачки, подмена содержимого/подписи/поля времени/индекса,
padding, неверный ключ, фактический учёт байтов, пересылка до проверки и продолжение после отвергнутой пачки.
149 тестов ядра прошли без ошибок/пропусков; полный `check.sh`, включая proxy/burst/load, завершился за 131 с.
Desktop stream/audio timing прошли; vibechat и APK arm64-v8a/x86_64 собраны, новый encoder проверен в обеих native-библиотеках APK.
Логи: `/tmp/stream-batch-{core,media,service,android-native,full-check}.log`,
`/tmp/stream-batch-{desktop-build,gui-tests,apk-build}.log`.
[+] **Live: callback обнаружения поставщиков** — 13.10.2026:
Принятые изменения Merkle и BGP помечают roster оптимизаторов соответствующего канала устаревшим.
Сверка/пробы выполняются после callback одним объединённым отложенным проходом в uasync.
Новый доступный поставщик опрашивается сразу; существующие пробы, цикл и backoff ошибок сохраняются.
Временно пустой буфер повторно опрашивается через 100 мс в пределах фиксированных 5 с,
чтобы ранняя подписанная опция не оставляла недостающие субпотоки до обхода через 30 с.
Регрессия с настоящим Merkle/BGP и задержанным READY: до исправления проверка задержки падала,
после принятого объявления INFO получен через 6 мс. Повторные callbacks не размножают пробы;
общий старт 8/2 и освобождение всех tracked allocations проверены.
149 тестов ядра, 43 Android-теста и desktop stream/audio timing прошли; GUI и APK собраны.
Логи: `/tmp/stream-provider-callback-{before,retry,full-check}.log`,
`/tmp/stream-provider-callback-{gui-tests,android-build}.log`.
[+] **Live: выбранная выдача отменяла помощь до READY/ACCEPT** — 13.10.2026:
Первое открытие desktop 17:07:41.035 → первый кадр 17:07:44.500 заняло 3.464 с;
запрос помощи отправлен через 99 мс, первый FEC через 2.490 с, KEY ещё через 0.796 с,
prefill/показ заняли 0.178 с. Повторное открытие заняло 0.983 с.
Merkle объявил буфер colo2 до READY: selector выбирал его INFO, но отменял STARTING-запрос,
потому что выдача ещё не ACTIVE. Четыре CANCEL закрыли собственную выбранную выдачу.
Запрос теперь удерживается также выбранными CONNECTING/INFO/REQUESTED upstream; INFO-пробы,
ENDED/CLOSED и чужие downstream не удерживают его. Аренда/idle и проверки поколений сохранены.
Регрессия с задержанным READY и настоящим Merkle/ETCP воспроизводит ошибку до исправления
и проходит после него без преждевременного CANCEL и tracked allocation leaks.
На colo2 всё ещё работает 14e2cdc2: опрос субпотоков раз в 100 мс и секундная задержка STATUS.
В сохранённом запуске helper генерировал STATUS в 18:07:42.465 и 18:07:43.476;
для полного ускорения нужен новый бинарник сервера. Логи: `/tmp/stream-first3s-{desktop,colo2,sm}.log`,
`/tmp/stream-first3s-regression-{before,after}.log`, `/tmp/stream-first3s-colo2-version.log`.
[+] **Live: ускорить начальное подключение** — 13.10.2026:
Дедлайн помощи 100 мс и первый пригодный INFO выбирают поставщика; DATA использует один общий старт.
Управление просыпается по событиям, подтверждение поколения и новые состояния помощи не ждут 1 с.
READY требует восстановленной FEC-пачки. Регрессии: прямой/relay победитель, поздние ответы,
отмена до дедлайна, пустой источник, дубликаты, общий индекс 8/2 и освобождение ресурсов.
Начальная очередь аудио прогревает Opus и обрезается по первому KEY; prefill 150 мс начинается после него.
149 тестов ядра, 43 Android-теста и desktop stream/audio timing прошли; GUI и APK собраны.
В сетевом тесте первый восстановленный блок через помощника получен за 192 мс, n=8/r=2.
Проверены поздний прямой INFO, отмена запроса до READY, отсутствие помощи для пустого доступного источника
и отсутствие дополнительных STATUS на повторы REQUEST. Все tracked allocations освобождены.
Desktop-регрессия прогревает 800 мс реального stereo Opus до KEY: звук молчит до начала видео,
затем сохраняются 30fps, stereo balance и смена revision при физической audio latency 200 мс.
Логи: `/tmp/stream-startup-full-check.log`, `/tmp/stream-startup-service-final.log`,
`/tmp/stream-startup-desktop-tests.log`, `/tmp/stream-startup-android-final.log`.
Контракт: `doc/stream.txt`, раздел 21. Замеры приведены для тестового стенда.
[+] **Live: сквозное стерео и три компактные кнопки поворота** — 13.10.2026:
CAMCORDER/Opus/компрессор/Android AudioTrack/desktop output используют два канала,
Opus AUDIO 128kbps. audio_codec=2 обозначает stereo; 960 кадров на канал дают 1920 PCM-отсчётов.
Capture/playback timestamps считают кадры на канал; mono-пакеты upmix выполняет libopus.
Три кнопки 0/90/270 подсвечивают выбранную и показывают верх цветной гранью на самой кнопке;
положение грани учитывает камеру и экран, наложение на превью удалено.
148 тестов ядра, 43 Android-теста и desktop stream/audio timing прошли.
Проверены stereo balance после AGC/Opus и независимые каналы на audio device (отношение энергий 15.99 при исходном 16).
APK/чатгуи обновлены; SM подтвердил channels=2 и ненулевой lrDifference.
Повороты 90/270 и возврат 0 проверены во время публикации без смены audio codec handle/epoch;
desktop показал ~30fps. Логи: `/tmp/stream-stereo-sm-final.log`, `/tmp/stream-stereo-final-desktop-tests.log`.
[+] **Android live: CAMCORDER и компрессор с настройками рации** — 13.10.2026:
AudioRecord.CAMCORDER, 48kHz mono; общий audio_compressor перед Opus AUDIO/64kbps,
lookahead=0, без изменения PTS. DataStore передаёт включение, max_gain и общий rise_rate
из настроек рации в audio worker; обновления применяются без перезапуска захвата/эпохи.
43 Android-теста и 631 проверка компрессора прошли, включая реальный Opus roundtrip,
live bypass, смену gain, отсутствие накопления output и утечек. APK установлен на SM.
На SM подтверждены CAMCORDER(5), переключение on/off/on в одном codec handle и восстановление
исходных enabled=true/max_gain=45/rise=6. Desktop продолжил показ ~30fps.
Лог: `/tmp/stream-camcorder-sm-final.log`.
[ ] **Общий AGC: клиппинг после резкого роста сигнала при max_gain=45dB** —
на SM при проверке CAMCORDER с настройками рации rise=6/release=30 наблюдались
4581 обрезанный отсчёт за интервал около 1s. Это общий алгоритм radio/stream,
плавное снижение gain может не успеть за скачком входа. Проверить ограничение пиков
без щелчков и ухудшения адаптации. Лог: `/tmp/stream-camcorder-sm-live.log`.
[ ] **Desktop: выход после SIGTERM оставляет GUI после остановки ядра** — 13.10.2026:
при обновлении live-плеера старый vibechat завершил ядро/worker, но процесс остался
в QCoreApplication::exec с работающим audio output. В логах также DM SELECT после
уничтожения SQLite (`bad parameter or other API misuse`). Проверить отмену Quit
в MainWindow::closeEvent (всегда ignore), порядок уведомлений и отключение GUI от БД.
Снимок: `/tmp/stream-desktop-shutdown-backtrace.log`, лог vibechat 13:04:09.
[+] **Desktop live: очередь видео вытесняла будущие кадры до показа** — 13.10.2026:
SM → colo2 доставлял ~30fps, desktop декодировал ~30fps, но videoQ=6 постоянно
выбрасывал ближайший кадр до достижения его PTS аудиочасами. Регрессия H.264/Opus
30fps с физической audio latency 200ms на старом коде не показала ни одного кадра.
Видео ограничено 128 кадрами/256MiB; при пределе сохраняются ближайшие к показу.
Добавлены decode/show FPS, late/pressure и PTS очереди относительно часов;
поштучное нормальное вытеснение транспортного буфера перенесено в trace.
Исправленный test_stream_view: 8/8; test_audio_timing прошёл. Живой просмотр
SM → colo2 после обновления: средний showFps=29.81 за 40s, videoQ=8–9, pressure=0.
Метрики: `/tmp/stream-desktop-fixed-live-metrics.log`; краткие просадки showFps до 22.4 остаются наблюдаемыми.
[+] **Android: категории диагностики и обрезанный текст уровня** — 13.10.2026:
список берётся из native-ядра, включая stream/video/reality/dm/call/aec.
Поля уровня используют минимальную высоту вместо фиксированных 48 dp;
изменения диагностики применяются сразу без перезапуска при выходе из настроек.
Общий уровень сохраняется в [global] debug_level; оба парсера принимают все категории,
а превышение лимита логируется. Регрессия: test_config_debug, файл и INI-текст.
[ ] **Стриминг SM → colo2 → desktop: восстановление частично остановившихся субпотоков** —
13.10.2026: помощь подключилась за ~8 с, все 8 субпотоков через colo2 приняты с общего индекса 5844.
Позже шесть субпотоков перестали продвигаться около seq=111625; четыре restart не восстановили
просмотр, desktop завершился по таймауту в 11:10:48 (colo2: 12:10:48). На SM публикация продолжилась,
colo2 снял свою подписку через 3 с. В том же интервале сервер видит RX timeout/переподключения TCP к SM;
первопричина остановки выдач пока не установлена: stream на colo2 наследовал error, детальных логов не было.
Повторить с заранее включённой диагностикой stream/etcp на SM и colo2, проверить upstream handles,
аренды, позиции и повторное согласование. Логи: `/tmp/stream-live-gui-final.log`,
`/tmp/stream-live-colo2-final.log`, `/tmp/stream-live-sm-final.log`.
Повтор 13.10 со stereo: до 15:20 desktop показывал ~30fps, затем video/audio очереди опустели;
decodeFps упал до 7–18 и viewer завершился по таймауту в 15:21:13 после пяти restart.
SM при этом сохранял ~30fps без dropped. Новые логи: `/tmp/stream-stereo-desktop-delivery-stall.log`,
`/tmp/stream-stereo-colo2-delivery-stall.log`, `/tmp/stream-stereo-sm-delivery-stall.log`.
[+] **Стриминг: помощь суперузлов по запросу** — 13.10.2026: автоматический запрос
при невозможности получения k субпотоков, внутреннее владение точной эпохой,
общий буфер со зрителями, аренды и остановка без downstream. Relay-only
экземпляры не удерживают друг друга. Подписанное управление с подтверждением
поколения, таймаут READY, защита от поздних запросов и пустой END.
Routed ID перенесён на 0x3C из-за конфликта с MEMBER_FILES; wire v4.
Исправлено владение CM handles репликации медиа при смене роли суперузла.
Контракт: `doc/stream.txt`, раздел 21. 148 тестов прошли, 1 пропущен;
`test_stream_service` и отдельный `--relay-only` завершились без утечек.
[ ] **Android: отмена асинхронного запуска до готовности ядра** — при проверке
мониторинга 12.10.2026 обнаружено: `NativeLib.stop()` пропускает native stop,
если `isReady()==false`, а `instance_lite_stop()` возвращается при `g_inst==NULL`.
Поэтому запрос stop до завершения конструктора может не отменить запускаемый
поток. Согласовать отмену с состоянием потока и единым сигналом завершения;
проверить stop до SERVICE_STARTED, отказ конструктора и последующий start.
[ ] **Android: повторные отказы persisted node snapshots** — замечено 12.10.2026
на устройстве D2AR10P3600820 при проверке live media. В сохранённой БД ряд узлов
регулярно получает `invalid persisted snapshot` в `topo_node_sqlite_snapshot_load`,
затем NCD сообщает `node not found`; повторные попытки засоряют лог.
Лог: `/tmp/stream-av-device-initial.log`. Причина пока не установлена: текущий
текст объединяет отказ deserialize, несовпадение ID и отказ verify. Разделить
диагностику этих ветвей и проверить повторные попытки загрузки отвергнутого снимка.
Существующую БД устройства при проверке стриминга не очищали.
[+] **STUN IPv4: резервное определение типа NAT по IP/netif** — уточнённый план
12.10.2026 в `doc/nat_detection.txt`. Одна группа и отдельный тестовый UDP-порт
на уникальный IP/netif, общий кэш с generation/TTL. При NO_OBSERVER/NO_HELPER
применять пригодную оценку STUN с явным source; измеренный ETCP приоритетен.
mapped адрес тестового сокета не переносить на рабочий. Проверить дубликаты,
переход STUN -> ETCP, различия по портам и жизненный цикл; namespace-стенд.
Реализовано 12.10.2026: группировка, кэш/TTL, история портов через reload,
source в подписанном NODEINFO/SQLite/мониторе и приоритет частичного ETCP.
145/145 тестов; три ASAN-теста без утечек; реальные cone/restricted/dependent
NAT и переключение STUN -> ETCP прошли в изолированном стенде.
[ ] **STUN IPv6** — отдельный этап: IPv6 endpoint/config/DNS и XOR-MAPPED,
scope/netif, тесты IPv6/NAT66. IPv4-оценки не переносить на IPv6 или TCP.
[ ] **check.sh: изоляция сетевых integration-тестов** — после основного набора
автоматически запускает check-proxy/burst/load при доступном sudo. Скрипты
меняют rp_filter, таблицу 100 и iptables главного namespace; cleanup выставляет
rp_filter=1 вместо сохранённого значения. Перенести тесты в отдельный namespace
и проверять неизменность родительской сети, как в tests/stream_netns.
[ ] **Стриминг: реализация по stream.txt** — 10.10.2026:
ТЗ и этапы: doc/stream.txt, разделы 15–16. Основа данных реализована в src/stream:
подписанные FEC-блоки 1300 байт, общий буфер 32 МБ, относительные timestamp-метрики,
источник с таймером 100 мс и категория stream. test_stream_core прошёл;
./check.sh: 143 passed, 0 failed, 0 skipped; proxy/full, burst и load — PASS.
11.10.2026 подключены жизненный цикл CHAT, локальные handles/API и события потребителя,
атомарные опции мембера через Merkle, подписанные профили и BGP-фильтр кандидатов.
test_stream_service прошёл на четырёх ядрах: две группы, смена эпохи/членства, restart,
rollback профиля, закрытие из callback и нулевой остаток аллокаций после destroy.
Лог: /tmp/stream-service-test-final.log. Исправлена выявленная утечка BGP node_paths при удалении узла.
Общий ./check.sh: 144 passed, 0 failed, 0 skipped; proxy/full, burst и load — PASS.
Лог: /tmp/stream-service-check.log (107 с).
11.10.2026 подключена сетевая выдача raw ETCP через собственный NCD owner: INFO/поколения,
handles/watermark, общий старт от первого DATA, курсоры/пути/GAP/LOOP, подпись END и аренда/RENEW.
Routed REVERSE_REQ/CLOSED подписываются end-to-end. Явные receive API позволяют открыть/закрыть выдачу и начать новую попытку.
Сетевая цепочка источник -> relay -> получатель, две группы/FEC на одном ETCP, GAP/restart,
повторы/reverse, END, lease timeout и REINIT прошли под ASAN/LeakSanitizer без ошибок/утечек.
Логи: /tmp/stream-network-asan-core.log и /tmp/stream-network-asan-service.log.
После восстановления обычной сборки ./check.sh: 144 passed, 0 failed, 0 skipped;
proxy/full (9/9), burst и load — PASS. Лог: /tmp/stream-network-check.log (88 с).
Wire и численные пределы зафиксированы в doc/stream.txt, раздел 17.
11.10.2026 подключены timestamp-метрики/rates/stops, nonce/метрики INFO и RTT uint32 мс,
A/D/X/Q выдач/пиров/модуля, интервалы 200мс и история 10с, подтверждение перегрузки 500мс.
OVERLOAD с frozen rates, FEC/альтернативами при выборе, SELECT/CLOSED, неизменным сроком 2с и fallback;
глобальный бюджет нескольких пиров требует backlog и локальной загрузки, CPU отдельно не режет.
4-секундный предел возраста control/ожидающих заданий, GAP/X при истечении и наблюдаемый статус accepting.
Частичная/сильная/глобальная разгрузка, короткий глитч и поздний SELECT прошли под ASAN/LeakSanitizer без ошибок/утечек.
Логи: /tmp/stream-pressure-asan-core.log и /tmp/stream-pressure-asan-service.log.
Обычная сборка восстановлена; ./check.sh: 144 passed, 0 failed, 0 skipped;
proxy/full (9/9), burst и load — PASS. Лог: /tmp/stream-pressure-check.log (90 с).
Wire версии 2 и пределы обновлены в doc/stream.txt, раздел 17.
11.10.2026 подключён автоматический планировщик: stream_subscribe_open начинает получение,
ручной режим выделен в stream_subscribe_manual_open. INFO-only пробы, цикл 32/1с/30с,
проверенные пути/RTT/метрики/слоты, backoff, распределение FEC, перенос с перекрытием и failover.
Первый DATA задаёт общий N; пустой источник и курсор last+1 ждут данные, END без DATA также подписан и доставляется.
Сохранён желаемый режим frontend; stream owners удерживают ACTIVE до close, затем восстанавливается STANDBY.
Статус/настройки — stream_selection_get_info/configure; wire версии 3 и пределы — doc/stream.txt, раздел 17.
На четырёх ядрах проверены 400 непрерывных пачек, общий планировщик владельцев, цикл 30с,
FEC spread, overlap до проверенного DATA, остановка relay/CLOSED и восстановление без разрыва ETCP.
Core/service, NCD и standby transport прошли ASAN/LeakSanitizer; остаток аллокаций — ноль.
Логи: /tmp/stream-optimizer-asan-{core,service,ncd,standby}.log.
Односторонняя смена stream generation восстанавливается по nonce INFO без разрыва ETCP и вращения эпох другой стороны;
регрессия и весь service-тест прошли ASAN/LeakSanitizer: /tmp/stream-generation-asan-service.log.
./check.sh: 144 passed, 0 failed, 0 skipped; proxy/full (9/9), burst и load — PASS.
Лог: /tmp/stream-optimizer-check.log (97с).
Следующий этап — длительные/масштабные сетевые проверки: NAT/reverse, мультилинк,
одновременная перестройка, несколько автоматических источников/групп и mobile standby на устройстве.
[+] **test_reality_tls: коллизии порта слушателя** — 10.10.2026:
В общем прогоне 140 passed, 1 failed: stcp_server_create не смог занять порт 34922, bind errno=98 (EADDRINUSE).
Причина: выбор порта как 34000 + time(NULL) % 1000 без гарантии его доступности.
Слушатель создаётся с port=0; stcp_server_get_port возвращает назначенный ОС порт для подключения клиента.
Логи показывают фактические порты REALITY и HTTPS. Сборка прошла; 8 параллельных TLS/HTTP-тестов прошли
при занятом всём прежнем диапазоне 34000–34999. ./check.sh: 141 passed, 0 failed, 0 skipped;
proxy/full, burst и load — PASS.
[ ] **Member files: исчерпание кеша результатов массовых изменений** — 10.10.2026:
Воспроизведено test_member_files_browser::recursiveDeletion(server-busy): из 76 объектов удаляются 64,
следующая команда получает MF_BUSY, остаются 12. storage.c: STORE_RECEIPTS=64, RECEIPT_TB=1200000 (120 секунд).
Лимит общий для успешных COMMIT/MKDIR/RENAME/REMOVE; затрагивает также рекурсивное копирование.
Нужен отдельный этап управления временем жизни receipts с сохранением идемпотентности повторных запросов;
простое вытеснение старых записей нарушает гарантию повторного ответа. После исправления изменить регрессию
на успешное удаление более 64 объектов и проверить повторные запросы/потерю ответа.
[ ] **Desktop: провалы вероятности VAD при компрессии** — диагностика 09.10.2026:
Воспроизведение пользователя: длительная гласная, затем временная нечувствительность; ближе к концу лога несколько повторов.
Новый лог 14:32:14–14:34:38: на 14:34:07–18 и 14:34:20–38 все 556 окон с RMS > -30dBFS имеют p < 0.5;
PCM непрерывен, errors=0, RX-gate не мешает, clips=5 не растёт. Сигнал не исчезает, порог остаётся 0.5.
--probe-stream: C-обёртка + реальный AGC + две Silero на одинаковом PCM, отличие — один reset состояния второй модели.
Синтезированный flite ah растянут до 24.576с: без AGC/клиппинга p первой секунды следующей речи 0.027 против 0.674 после reset.
При AGC 1dB (clips=0) — 0.012 против 0.662. Влияние истории модели подтверждено, провал на десятки секунд целиком не воспроизведён.
Лог стенда: /tmp/vad-vowel-context.log; запуск: test_silero_vad lib/silero_vad.onnx --probe-stream /tmp/vad-vowel-context48.pcm 993.
Вход стенда: mono s16le/48кГц, reset_window — индекс окна 512/16кГц; режим проверяет без AGC, 1dB и 15dB.
Автоматические сбросы в рабочем VAD не добавлялись; test_silero_vad PASS.
Уточнение: низкая вероятность держится десятки секунд, затем распознавание восстанавливается; краткий клиппинг это не объясняет.
Локальный лог 14:00:10–14:00:58: 15 сбросов AEC при пропусках референса, 16 clipped samples в VAD; vad DEBUG не был включён.
Добавлены секундные уровни raw/clean/reference и причина bypass/reset AEC; отдельное предупреждение о клиппинге VAD.
Секундный отчёт захвата работает также без PCM: возраст кадра, очередь, максимальная задержка и предупреждение о простое.
TRACE каждого окна содержит DC, число нулей и gain вместе с вероятностью/уровнем/паузой между окнами; видны сбросы и RX-gate.
В локальном build/vibechat.cfg включены vad=trace, aec/radio/call=debug, general=info; после диагностики вернуть обычные уровни.
Стенд --probe повторяет одинаковый PCM без reset: AGC 15/30dB после паузы обрезает пики (468/5625 samples на чистой записи).
Полного провала всей фразы почти до нуля стенд не воспроизвёл; нужен повтор живой речи с новыми логами для связи с AEC/AGC.
Алгоритмы обработки сигнала пока не менялись; исправление причины выбирается по результатам повтора.
[ ] **Linux headless CMake: актуализировать зависимости общего ядра** — 07.10.2026:
чистая сборка tools/chatgui-android/build_headless останавливается на lib/speex_aec.c:
speex/speex_echo.h не найден. utun_setup_sources включает этот исходник, но UTUN_INCLUDE_DIRS не содержит
lib/speexdsp/include. Проверить полный состав Speex/voice зависимостей отдельного каркаса;
основная Autotools C-сборка и Android NDK-сборка проходят.
[ ] **REALITY: исправить формат ClientHello и продолжение TLS-потока** — 07.10.2026:
supported_groups и signature_algorithms не содержат внутренние двухбайтовые длины списков.
После ClientHello/ServerHello идёт STCP без TLS record framing; это распознаётся пассивным наблюдателем.
[ ] **Завершить проверку реакций и голосов на SM** — 07.10.2026:
причина отказа установлена: у записей корней `signed_by=0/NULL` были нулевые/отсутствующие подписи дерева.
Проверка корня ключом канала остаётся обязательной; добавлены причины отказа и проверка доверенного Ed25519.
Исправлено применение подтверждённой подписи при равной/старой версии профиля и её сохранение при нулевом блоке
в более свежем профиле. Создание канала проверяет обе подписи корня до записи собственного мембера.
На local восстановлены шесть подписей канальными приватными ключами без изменения остальных полей записей.
Разовый скрипт и резервная копия: `/home/user/utun2-backups/root-certificates-20261007`.
Проверены все 18 участников local и 17 участников копии SM; тесты требуют отказа при нулевой/поддельной подписи.
Linux/Android/desktop собраны; `./check.sh`: 133 passed, 0 failed, 1 skipped; proxy/full, burst, load и 7 Qt-тестов — PASS.
Осталось установить APK на SM (`RZ8R72MG64B`) и проверить реакцию/голос на устройстве: SM отключился от ADB во время работы.
[ ] **rlottie: разбор предупреждений GCC 15 в импортированных исходниках** — 05.10.2026:
при сборке `tools/chatgui/rlottie_src` GCC сообщает `-Wuninitialized` в
`VArenaAlloc::reset()`: fFirstBlock/fFirstSize/fFirstHeapAllocationSize читаются
после явного вызова деструктора. Проверить сохранение значений до разрушения
и повторный reset с реальными выделениями. Также проверить `-Wfree-nonheap-object`
в `vcow_ptr`: статическая модель default_s сохраняет базовую ссылку.
Лог: `/tmp/utun-rlottie-vendor-build.log`. Сборка библиотеки и подключение её
экспортированного CMake-пакета к ChatGUI на Linux прошли; Windows ещё не проверен.
[ ] **ChatGUI Windows: подтверждение обновления runtime компилятора** — 05.10.2026:
`cc-probe.log`: cc1 запускается из корня, но в `tools/chatgui/build` завершается
с `0xC0000139`; локальные DLL GCC/math/runtime отличаются от UCRT64.
Перед обеими точками сборки добавлено обновление существующих копий этих DLL;
раскладка FFmpeg использует для них UCRT64. Проверены обновление, повторный вызов,
сохранение кодеков и ошибки. Требуется Windows-прогон `check_cc.bat`: cc1 после
обновления, повтор команды Ninja и сборка Opus должны завершиться с кодом 0.
[ ] **ChatGUI Windows: обновление остальных DLL приложения после обновления MSYS2** — 05.10.2026:
в `cc-probe.log` также отличаются Qt и другие DLL. `tools/chatgui/build.sh`
пропускает раскладку при наличии основного комплекта, без сравнения версий;
рекурсивная раскладка копирует только отсутствующие зависимости.
Runtime GCC обновляется отдельно; для остальных DLL нужно продумать обновление
с сохранением приоритета собственной сборки FFmpeg и проверить запуск приложения.
[ ] **Android: время жизни config provider** — 03.10.2026: `utun_bridge_init()`
передаёт адрес локального `utun_config_provider_t` в `utun_config_set_provider()`,
который хранит указатель. После возврата из init он недействителен; перед
использованием `cfg_get_*` обеспечить постоянное хранение provider.
[ ] **uasync: ложные ERROR об утечке перед cleanup** — 01.10.2026:
test_dm_e2e и существующий test_conn_mgr проходят, но uasync_destroy()
пишет Timer leak до освобождения отменённых heap/immediate таймеров.
После cleanup счётчики сходятся, финальная проверка проходит. Перенести
предварительные счётчики в DEBUG; ERROR оставить для реального расхождения
после cleanup, отдельно показывать активные и отменённые таймеры.
[ ] **Общий лимит check.sh после clean** — 01.10.2026: расчёт по времени предыдущего
прогона дал 205с вместе с полной сборкой и оборвал проверку после успешных тестов
до `test_uasync_socket_race`. Повторный запуск на готовой сборке с большим лимитом
прошёл за 206с, включая proxy/burst/load. Разделить бюджет сборки и запуска тестов
либо учитывать clean при расчёте.
[ ] **Паузы аудио Qt при звонке с SM** — 01.10.2026, звонок
`939a3ea36f3eeac3`, прямой LAN TCP `192.168.40.250:44604 ↔ 192.168.40.247:44173`.
Tcpdump: общие паузы входящего трафика до 645мс; ping до роутера в среднем
100мс, до SM 128мс. ПК на 2.4ГГц, SM на 5ГГц. Одновременно `CallAudio: cb`
падает до 20–40/с вместо 100/с, буфер Qt растёт до 2с, на SM повторяется refill.
В 8с strace аудиопоток продолжает обслуживать PulseAudio без долгих syscall;
причина редких аудиоколлбэков пока не установлена. Добавить измерения интервалов
и длительности callback, кадров capture/playback и сводку CALL_STATS; сравнить
сетевые задержки после подключения ПК к 5ГГц или кабелю.
Повторный звонок `b2a423ed2d36ed83` (01:25:31–01:27:39): DIRECT сохраняется,
RTT 2–3мс; в начале на SM gap tone длится 1.8–2.0с примерно каждые 6с.
На Qt частота callback падает вплоть до 4/с, входящий PCM продолжает приходить:
буфер 65→465→1465→2079мс за 3с, затем растёт до нескольких секунд, dropped=0.
Локализовано прекращение обслуживания duplex-аудио Qt; ожидание backend и
задержка обработки PCM пока не разделены. Часы SM отстают от Qt примерно на 1.24с.
Добавлена диагностика backend/устройств, времени между callback и длительности
capture/playback, фактической частоты callback и PCM кадров за интервал.
Счётчики сбрасываются до старта устройства; нужна повторная запись с новой сборкой.
[ ] **Оставшаяся задержка запуска аудио SM** — после обновления 01.10.2026,
звонок `2b9ad4e21a54d8ba`: стартового gap tone нет на обеих сторонах; Qt
стабильно работает около 100 callback/с, max_idle=15.3мс, буфер 55мс, RTT=2мс.
На SM первый capture появляется через 1140мс от startAudio (1164мс от ACCEPT).
router.start=781мс, получение снимка устройств=0мс, AudioRecord create=24мс,
startRecording=7мс; от начала startRecording до первого кадра=328мс.
Capture worker стартует раньше playback, но общий выигрыш пока не виден.
AudioTrack create=21мс, play=327мс; система сообщает AudioPortCache contention=497мс
и восстановление AudioTrack при setPreferredDevice. Разделить замеры регистрации
callback, BT-профиля и применения маршрута; отдельно проверить первый AudioRecord.read.
На SM входящий буфер за время подготовки вырос до 1149мс и к концу звонка снизился
до 570мс; ускорение старта playback также сократит начальное накопление.
Реализован независимый запуск AudioTrack и AudioRecord в play/capture потоках;
частичный старт отменяется до освобождения устройств/native. AEC измеряется после готовности обоих.
Добавлены callbackMs/btProfileMs/applyMs/refreshMs, длительность первого read и время первой записи playback.
Резерв теперь зависит от изменения задержки доставки по timestamps CALL_MEDIA, отдельно от глубины очереди;
стартовое накопление и догон не повышают запас. Сохранность FIFO и uint32 wrap проверяются регрессиями.
Сборки ядра, Qt и Android после clean успешны; три аудиотеста прошли. Полный check:
113 PASS, 0 FAIL, 1 SKIP (auto_socket_dynamic требует root); proxy/burst/load прошли.
Регрессия refill учитывает остаток SoundTouch: два новых кадра могут уже заполнить запас 60мс.
SM и Q8 обновлены 01.10.2026 в 03:03. Выигрыш по времени требует пробного звонка с новой версией.
[ ] **Гонка invite-файла в test_chat_join_e2e** — `wait_file()` проверяет только
существование файла, а `wf()` создаёт его до записи. Читатель иногда получает
пустую ссылку и ошибку префикса `utun://`. Публиковать готовый файл атомарно.
[ ] **Некорректное время в выводе check-proxy** — успешные `basic_1mb` и
`stress_sessions` иногда печатают огромные положительные/отрицательные миллисекунды,
хотя итоговая скорость и длительность передачи выглядят нормально. Проверить расчёт вывода.
[ ] **Linux ONNX Runtime: повторная регистрация схем при запуске теста** — 03.10.2026:
test_silero_vad при загрузке модели печатает серии `Schema error: ... already registered`.
Инференс, речь, тишина и reset проходят; отдельно проверить состав и загрузку Linux-библиотек ONNX.
Диагностика: `/tmp/vad-compressor-silero-tests.log`; Android-сборка таких сообщений не содержит.
[ ] **test_tcp_proxy_full: некорректное время в диагностике** — 03.10.2026:
полный check.sh проходит, но строки basic/stress/concurrent/half_close выводят
огромные или отрицательные миллисекунды (например, -1611883348002232012ms).
Отдельно проверить формат/аргументы вывода длительности; `/tmp/vad-compressor-check.log`.
[ ] **debug_parse_config: формат и индексы категорий** — parser ожидает `:`, документация
описывает `=`; преобразование битовой маски осталось после перехода enum на индексы.
[Разбор](etcp_full_suite_findings.md).
[ ] **DM: прямой p2p чат с любым пользователем группы** — отдельная DM-подсистема.
ТЗ и архитектура: `/doc/dm_arch.md`. Статус: реализовано (dm_core/dm_mailbox/dm_crypto),
тесты `test_dm` (крипто) и `test_dm_e2e` (интеграция). Остались задачи ниже.
[ ] **Звонок (P2P аудио)** — голос 1:1, из CHAT-группы или p2p-чата (DM). Отдельный
каталог `src/call/`. Сигналинг + conn_mgr + аудиопоток (Opus) с backpressure
(локальный буфер отправки при переполнении роутера) + адаптивный джиттер-буфер
(SoundTouch, ускорение до 1.6x) + тоны (глитч/завершение) + watchdog 20с.
Android: переключение источника (трубка/громкая/гарнитура).
Архитектура: `/doc/chat_call_arch.md`.
[ ] **DM-звонки** (fallback `group_id==0`) — не сделано: `call_is_online`/`call_start`
требуют реальную группу (`topo_groups_find`), для DM (group_id==0) маршрута нет.
## Рефакторинг: per-instance chat/dm (однопоточный test_dm_e2e)
[ ] **BGP-гонка: дропнутый REQUEST_TABLE** (отдельная задача, как договорились).
**Место:** `topo_group_new_conn()` в `src/routing_layer/topo_group.c:571`. Дедуп-ветка
«conn already in senders_list» (строки 579–587) делает `return` БЕЗ повторной отправки
`topo_group_send_table_request()`.
**Зачем дедуп:** тот же `ETCP_CONN` стреляет `ETCP_CONN_STATUS_UP` дважды (UDP-линк,
затем TCP-линк). Повторная обработка задваивает `active_conn_count`, из-за чего
переподключение не стартует. Поэтому `return` в дедупе — правильный.
**В чём гонка:** REQUEST_TABLE — это то, что заставляет пира отдать свою таблицу
(NODEINFO/узлы группы). Сценарий «разнесённого старта»:
1. A↔C соединение поднято. A шлёт C `REQUEST_TABLE` для группы G (`topo_group_new_conn`
→ `topo_group_send_table_request`, `topo_group.c:602`).
2. У C группа G ещё **не создана** (создаётся позже, по мере загрузки каналов/синка).
C получает `REQUEST_TABLE`, но `topo_group_handle_request_table` не находит G →
дропает запрос.
3. C наконец создаёт G (`topo_groups_create_group` → обход connections →
`topo_group_new_conn(G, conn_A)` на стороне C) → C шлёт A свой `REQUEST_TABLE`.
A отвечает своей таблицей → **C узнаёт A**.
4. Но A больше не шлёт C `REQUEST_TABLE` → **A так и не узнаёт C** в группе G.
Итог: при разнесённом старте A не видит C в CHAT-группе (односторонняя видимость).
**Фикс (предполагаемый):** в дедуп-ветке не просто `return`, а предварительно
идемпотентно `topo_group_send_table_request(group, conn)`:
```c
if (((struct TOPO_GROUP_CONN_ITEM*)se->data)->conn == conn) {
topo_group_send_table_request(group, conn); /* повторно, идемпотентно */
DEBUG_INFO(..., "conn already in senders_list, re-request table (%s)", conn->log_name);
return;
}
```
`topo_group_send_table_request` не ведёт состояния — просто шлёт REQUEST_TABLE,
пир отвечает снимком таблицы (идемпотентно). Лишний дубль таблицы безвреден.
**Замечание:** в однопоточном `test_dm_e2e` (и `test_chat_join_e2e`) из-за
детерминированного порядка группа успевает создаться до прихода REQUEST_TABLE —
поэтому тест проходит. Реальная гонка остаётся для асинхронных сетей. Отдельный
воспроизводимый тест для этой гонки пока не написан.
[ ] **«packet undecryptable» на линках C** (вторичное). A, узнав B через BGP, через
`topo_group_connect` пытается поднять прямой A↔B линк (`seskey 4777737b`), но B не
настроен принимать A → crypto-шум каждые ~1с. Разобраться с авто-подключением
(не пытаться соединяться с узлами, для которых нет `[client]`/ncd-конфигурации,
либо обрабатывать неудачу без спама).
[ ] **lwip/proxy: утечка pcb в FIN_WAIT_2** — `tcp_shutdown(pcb,0,1)` (half-close по FIN от
exit) не ставит `TF_RXCLOSED`, поэтому таймаут FIN_WAIT_2 в `tcp_slowtmr` не срабатывает:
если браузер никогда не пришлёт FIN, pcb навсегда остаётся в FIN_WAIT_2 (утечка, не crash).
Двойной free по TIME_WAIT уже закрыт (detach по локальному закрытию + guard abort).
## Открытые флаки
[ ] **test_etcp_reconnect** — флаки под параллельной нагрузкой `make check -j4`:
phase 4 (reconnect после server restart) таймаутит (`sent=480 recv=0`), при одиночном
запуске стабильно `TEST PASSED`. Наш код (chat_join/chat_sync) его не трогает.