From 78246e249eb442e07e80407588614673e7b40485 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 15 Oct 2026 02:07:04 +0200 Subject: [PATCH] Document measured call FPS loss and bounded audio synchronization queue --- doc/call_video.txt | 20 +++++++++++++++++--- doc/tasks.md | 6 +++++- src/call/call_video_transport.h | 4 +++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/doc/call_video.txt b/doc/call_video.txt index 5672ed87..66ecf567 100644 --- a/doc/call_video.txt +++ b/doc/call_video.txt @@ -187,7 +187,11 @@ KEY содержит config_length:4BE + AnnexB config + access unit. Ядро границы envelope; содержимое NAL обязан проверять платформенный decoder. frame_id и capture PTS возрастают на всём протяжении звонка, включая смену generation. Новый формат требует нового generation и KEY. После пропуска кадра нужен KEY. -На TX один незавершённый кадр, на RX одна ограниченная сборка; deadline 2с. +На TX ограниченная FIFO: до 32 кадров, 500мс по PTS и 4MiB суммарно; на RX одна ограниченная сборка. +Deadline головы TX и сборки RX — 2с. Каждый TX кадр ждёт соответствующего audio_end_pts; +следующие P-кадры сохраняются в FIFO, а не теряются на обычной задержке аудиообработки. +При потере головы отбрасывается вся зависимая цепочка и запрашивается KEY. В сетевой долг +входят только готовые к отправке кадры FIFO; ожидание аудио само по себе не перегружает канал. receive_ready резервирует возможность принять целый кадр до ACK первого фрагмента. Callback копирует данные до возврата; платформенная очередь также должна быть ограничена. Старые кадры другого generation сохраняются до соответствующей позиции аудиоряда. @@ -551,8 +555,10 @@ Android: принимаемое видео сначала занимает ве навигации и временно скрытые системные кнопки. Видео по-прежнему использует весь экран. TextureView и Surface сохраняются при показе кнопок; decoder освобождает старый Surface до его release. Запоздалый detach предыдущего Surface не отключает новый. -Preview берётся из того же Camera2 YUV кадра (до 5 fps, ширина до поворота 192 px), без второй камеры. -Развёрнутое своё видео пока использует это же превью; приём сохраняет исходное качество и частоту кадров. +Preview получает прямой output той же Camera2 через общий StreamPreview/CameraPreviewView, +без Bitmap-конвертации и ограничения 5 fps. Surface удерживается до закрытия CameraCaptureSession/CameraDevice; +разворачивание/миниатюра меняют только геометрию TextureView. На SM подтверждено 29–30 fps. +Отказ preview output логируется и оставляет YUV-output передачи; encoder при attach/detach не перезапускается. Desktop: первый RX кадр открывает отдельное изменяемое окно видео, без автоматического fullscreen. Окно звонка с управлением и всеми настройками сохраняет свою геометрию и состояние настроек. Видео сохраняет пропорции, своя миниатюра — в углу окна видео. F11/двойной щелчок переключают @@ -566,6 +572,14 @@ F11/Esc, закрытие/повторное открытие без hangup, loc (/tmp/call-video-separate-preview.log). ChatGUI собран; Android assembleDebug и 81 unit-тест — PASS. Автоматическое ожидание FAR и поворот экрана требуют проверки в следующем реальном звонке. +15.10.2026, диагностика низкого FPS desktop -> Samsung: +До исправления capture=30/s, encoded=20/s, paced=10/s; TX accepted=5/s, audio_busy=15/s, +audio_ahead=140–180ms. RX pulled/decoded/rendered=5/s, late=0: кадры терялись до отправки. +Вместо порога 33333мкс от прошлого кадра desktop использует сетку 30 fps с допуском 1/4 периода; +30 fps с дрожанием сохраняются, 60 fps ограничиваются до 30. FIFO TX сохраняет кадры во время ожидания аудио. +test_call проверяет семь последовательных KEY/P кадров за audio barrier, порядок после release и предел PTS. +Диагностика: /tmp/call-fps-desktop-live.log, /tmp/call-fps-sm-live.log; unit/core/Qt проверки прошли. + Подтверждённая причина фризов раз в 1–2с: коррекция capture timestamp меняла audio source_epoch, а обе платформы сбрасывали video decoder и ждали KEY. Теперь source_epoch обновляет аудиопривязку без потери video references, готовых кадров и последнего показанного PTS. diff --git a/doc/tasks.md b/doc/tasks.md index 5321c216..d77812d1 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -62,7 +62,11 @@ Android: Назад из видео открывает управление звонком; две миниатюры разворачиваются нажатием, второе видео остаётся в углу. RX TextureView/Surface сохраняются при смене режима. Кнопки учитывают системные панели (включая боковую навигацию) и вырез экрана. - Своё развёрнутое видео пока использует прежнее превью 192 px / 5 fps; RX без снижения качества. + Своё видео теперь идёт напрямую 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мс/4MiB). + Тесты: 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 кадров, diff --git a/src/call/call_video_transport.h b/src/call/call_video_transport.h index d6b014a7..2e324471 100644 --- a/src/call/call_video_transport.h +++ b/src/call/call_video_transport.h @@ -24,7 +24,9 @@ int call_video_configure(struct UTUN_INSTANCE *inst, uint64_t call_id, const str const struct call_video_ops *ops, void *arg); /* Копирует один полный кадр. 1 принят, 0 backpressure/ожидание KEY, -1 неверный формат/сессия. * После 0 producer обязан запросить KEY: пропуск P-кадра разрывает цепочку references. - * Неполная отправка ограничена 2с; следующие кадры не увеличивают очередь. */ + * FIFO ожидания аудио/сети: до 32 кадров, 500мс PTS и CALL_VIDEO_MAX_FRAME байт суммарно. + * Каждый кадр выходит только после соответствующего аудио; deadline головы 2с. + * При истечении deadline сбрасывается вся зависимая цепочка и запрашивается KEY. */ int call_video_send_frame(struct UTUN_INSTANCE *inst, const struct call_video_frame *frame); void call_video_resume_receive(struct UTUN_INSTANCE *inst, uint64_t call_id); /* Decoder потерял references. Запрос идемпотентный, отправляется не чаще раза в 500мс. */