Несколько сессий попыток реализовать audio mixing в композитор'е.
Не достигнуто sub-секундной latency со стабильным video+audio.
Откатано на parallel mode (cfc-grid video-only, live от pipeline с audio).
Полный набор выводов и pitfall'ов — docs/LESSONS-audio-mixing-attempts.md.
Главные lesson'ы для будущей попытки:
- mpegts mux libavformat авто-инсёртит h264_mp4toannexb BSF которому
не нравится Annex-B + inline SPS/PPS — NVENC OUTPUT_SPSPPS per-frame ломает
- SPSC ring drop newest при full, не oldest (consumer's domain)
- av_new_packet (не av_malloc) для av_interleaved_write_frame ownership
- Monotonic PTS на counter (frame_idx, total_samples) — не wallclock
- mediamtx env-var path names не должны иметь '-' (parser limitation)
- Default mediamtx ReadTimeout=10s короткий для burst write'ов
Изменения в repo сохранены для будущей доработки:
- src/writer.c — mpegts backend с audio stream support
- src/audio.c — RTSP AAC consumer + lock-free SPSC ring
- include/cuframes_composer/{writer,audio}.h — public API
- examples/grid_record.c — --format=mpegts + --audio-source flags
- include/cuframes_composer/composer.h — consumer_prefix field
- docker/Dockerfile — libavformat-dev добавлен в builder/runtime
cfc-grid composer стабильно работает на видео (substantially лучше
монолитного pipeline'а с audio bag'ом). TV рекомендуется использовать
rtsp://...:554/cfc-grid + опционально rtsp://...:554/live-audio
parallel.
Результат:
46+ секунд работы, 1150 кадров, 0 drops
FPS = 25.0 СТАБИЛЬНО
GPU util = 47% (большие запасы для масштабирования)
16 active, 0 stale, 0 dead — все подписки удерживаются
ffprobe видит валидный h264 3840x2160 25/1 на mediamtx
Visual artifact в rows 2-4 (вертикальные полосы) — гипотеза:
race condition при 4 cfc_source_t подписках на одного publisher'а
(16 consumers vs 16-slot cuframes ring buffer = tight fit).
FPS не пострадало, но визуально половина ячеек испорчена.
Phase 5e-fix planned: composer должен detect одинаковые source_key
и переиспользовать один cfc_source_t для N ячеек. Это устранит
multi-consumer race и снизит memory footprint.
Подробности + снимок в docs/LOADTEST-PHASE-5e.md +
docs/phase5e-load16.jpg.
Composer настроен на 4 несуществующих cuframes-ключа. Live результат:
health: {total:4, active:0, stale:0, dead:4}
FPS: 25.2 СТАБИЛЬНО
Encoder рендерит чёрный grid с красными NO_SIGNAL подписями
+ серо-голубыми border'ами
ffprobe видит валидный h264 1920x1080 25/1 на mediamtx
Это самый жёсткий adversarial scenario — полная потеря сети камер.
Composer не падает, encoder работает на холостом ходу, RTSP-publish
непрерывен, MQTT health корректно отдаёт dead=4 (HA-алерты через
expire_after=30s).
Доказан главный production threat: обесточивание PoE-свитча /
uplink-отрезание не валит весь pipeline. TV видит NO_SIGNAL вместо
разрыва соединения, HA-оператор уведомляется.
Полный отчёт + снимок в docs/ADVERSARIAL-TEST-PHASE-5b.md +
phase5b-all-dead.jpg.
Live-validated сценарий: stop cuframes-pub-back_yard, наблюдение
через ZMQ /health.
Timeline:
t=0s: 4 active, 0 stale, 0 dead baseline
t+2s: 3 active, 1 stale STALE через 500мс threshold
t+10s: 3 active, 1 dead DEAD через 5000мс threshold
FPS = 25.0 СТАБИЛЬНО
ячейка → blackout
restart pub:
t+~13s: 4 active, 0 stale, 0 dead auto-reconnect отработал
Главный threat model подтверждён: отключение источника не валит
композитор, остальные 3 ячейки продолжают работу, RTSP не прерывается.
Полный отчёт в docs/ADVERSARIAL-TEST-PHASE-5a.md.
Phase 5b/5c (multi-source disconnect, mediamtx restart, 24h memory
test, 16-source load test) — отдельные сессии.