Browse Source

Document shared live publisher and desktop capture lifecycle

master
evgeny 5 days ago
parent
commit
b25070acbd
  1. 24
      doc/service_lifecycle.md
  2. 57
      doc/stream.txt

24
doc/service_lifecycle.md

@ -106,9 +106,27 @@ destroy отсоединённого cursor не обращается к store.
ACK-история принадлежит ядру и обновляется только при первом найденном подтверждении
пакета. REINIT/close соединения не стирает уже подтверждённые за последнюю секунду байты.
Android publisher владеет отдельным 100ms таймером TX-снимков; close/detach отменяют
его в uasync до уничтожения instance. JNI копирует снимок под mutex без доступа к
живым очередям транспорта из Kotlin. Экран подписан на отдельный StateFlow статистики.
Общий `stream_publisher` Android/desktop владеет отдельным 100ms таймером TX-снимков;
close/detach отменяют его в uasync до уничтожения instance. Bridges копируют снимок
под mutex, frontend не обращается к живым очередям транспорта. Android экран подписан
на отдельный StateFlow статистики; desktop обновляет статистику отдельно от сырого превью.
Publisher не регистрирует stream event callback и не подменяет callback viewer.
Bridge удерживает внешний mutex на время producer/open/stop и destroy общего publisher;
actor не вызывает frontend callbacks под своим mutex. Reserved post, media timer,
stats timer и stream handle освобождаются до контекста publisher.
Desktop `MainWindow` владеет `StreamPublishEngine`, а окно управления лишь отображает
его состояние. Закрытие окна сохраняет эфир, новый запуск запрещён до конца FIN drain.
Qt capture callback хранит только последний кадр, video/audio workers выполняют encode/DSP
вне GUI и hardware callbacks. Отдельные поколения источника и encoder позволяют менять
видеокодек/bitrate/rotation без повторного выбора экрана в портале. Ошибки Qt capture
обрабатываются через queued callback, чтобы не уничтожать backend из собственного callback.
Сначала stop запрещает producers, закрывает Qt capture и audio device, затем join workers,
освобождает microphone lease и завершает публикацию через FIN с drain 2s.
При завершении приложения engine уничтожается до SoundManager и ядра; detach в uasync
закрывает оставшийся publisher. Workers никогда не держат borrowed instance/handle.
Microphone lease публикации эксклюзивен; прежние call/radio/recorder leases совместные.
Восстановление устройства сохраняет владение и не разрешает другой capture до stop/failure.
Статус транспорта UP подтверждает восстановление физического пути. READY сессии
группы означает согласованный JOIN/ACCEPT и завершённый обмен её таблицей; именно

57
doc/stream.txt

@ -803,7 +803,9 @@ Android:
трансляции; оба канала используют общий gain, сохраняющий стереобаланс. Изменения настроек рации применяются на следующем PCM-кадре, без перезапуска микрофона,
Opus или source_epoch; compressor не добавляет задержку и не меняет capture PTS.
- Camera/codec callbacks — HandlerThread, Opus encoder — audio capture thread, decoder/AudioTrack — viewer worker.
- Native bridge держит pthread mutex, ограниченные очереди и один pending post либо timer.
- Native bridge использует общий stream_publisher для TX и собственный actor для viewer.
stream_publisher держит pthread mutex, ограниченные очереди и один pending post либо media timer;
статистика обслуживается отдельным таймером 100ms. Тот же модуль используется desktop.
attach/detach выполняются в uasync вне callbacks. detach отменяет post/timer, закрывает handles,
очищает media, снимает наблюдение каталога и запрещает producers до уничтожения instance/ua.
UI не сохраняет borrowed inst/ua. Idle без pending data не будит мобильное ядро.
@ -880,8 +882,51 @@ C-тесты проверяют новую revision, потерю первого
Это наблюдение относится к данной прошивке; metadata Camera2 сами по себе не подтверждают рабочую скорость.
Desktop:
- Значок трансляций расположен в шапке MessageList. Источники берутся из того же каталога ядра;
- Значок трансляций расположен в шапке MessageList группового канала даже без источников;
меню содержит запуск/управление собственной публикацией и выбор удалённого источника.
Собственный источник открывает управление; микрофон не воспроизводится локально.
Источники берутся из того же каталога ядра;
ответы предыдущего канала не меняют текущую шапку. Личные беседы снимают наблюдение.
- MainWindow владеет одним StreamPublishEngine. Окно StreamPublishWindow можно закрыть и открыть
снова без завершения эфира. Qt >=6.6 Multimedia/MultimediaWidgets и FFmpeg нужны для публикации;
без них сохраняются остальные функции чата. CMake сохраняет признак capture в отдельном marker,
deployment/Windows installer включают Multimedia runtime, FFmpeg plugin и транзитивные DLL.
- Видео: QCamera, QScreenCapture или QWindowCapture передают последний QVideoFrame в QVideoSink.
Под Wayland/XWayland экран выбирается через системный портал. Открытие портала не ограничивается
таймаутом подтверждения KEY до появления первого сырого кадра.
Callback только заменяет последний кадр под mutex, Qt-очередь кадров не растёт.
Сырое превью обновляется отдельно до 30Hz; encode/conversion и сетевой publisher его не задерживают.
Для камеры сохраняется относительная шкала backend PTS с привязкой к монотонному origin;
при отсутствии PTS используется время захвата callback. Это оценка, а не аппаратный timestamp сенсора.
Неподвижный экран кодируется повторно с новым монотонным PTS; последний raw кадр допустим и после
смены видеоконфигурации на backend, который уведомляет только об изменении изображения.
- Отдельный worker преобразует кадры через swscale и кодирует без B-кадров, GOP=1s.
Предлагаются H.264/H.265/VP9/AV1/H.266 в этом порядке, если реальная проба encoder успешна.
NVENC/QSV/AMF/VAAPI проверяются перед программными реализациями. Проба требует два принудительных
независимых KEY, затем encoder открывается заново, без reference frames и PTS пробной сессии.
Encoder, не выполняющий повторный запрос KEY, для live не используется. VAAPI/QSV async_depth=1.
H.264/H.265/H.266 нормализуются в Annex B; каждый KEY содержит decoder configuration.
- Настройки: разрешение/FPS, видеокодек, Авто/пресеты bitrate, три кнопки 0/90/270 с красной верхней
гранью и подсветкой активной кнопки. libx264 меняет bitrate в текущем encoder; остальные реализации
заменяют только video encoder. Смена codec/режима/rotation подтверждается новой revision с KEY.
Capture и encoder имеют отдельные поколения: смена codec/bitrate/rotation не переоткрывает источник
и не вызывает повторный выбор в портале. Origin, source_epoch, аудио и frame IDs сохраняются.
Ошибка или отсутствие KEY в течение 8s вызывает одну попытку rollback всей последней подтверждённой
конфигурации; повторная ошибка завершает эфир. Late callbacks отсеиваются по поколению источника.
- Микрофон выбирается до запуска. miniaudio захватывает 48kHz stereo; при mono вход дублируется
с явным указанием Mono в UI. Отдельный worker использует Opus AUDIO/128kbps/20ms и собственный
audio_compressor с текущими настройками рации (200ms lookback, нулевой lookahead, общий stereo gain).
Callback копирует PCM в предвыделенную очередь; DSP/Opus в нём нет. Hardware PTS используется при
наличии, иначе шкала строится по количеству отсчётов. Очередь/возраст ограничены; при разрыве
сбрасываются только неполный PCM-пакет и история компрессора. Mute передаёт тишину.
Публикация эксклюзивно занимает микрофон: звонок/рация/запись и публикация запрещают друг другу новый
capture. Прежнее совместное владение микрофоном голосовыми функциями сохраняется.
- transport/stream_bridge владеет независимым stream_publisher; shared C actor выполняет uAV2/RS,
admission, KEY recovery, FIN и TX snapshot в uasync. Очереди/pressure/drain совпадают с Android.
UI показывает video queue, суммарный inflight, send buffer и ACK_1s каждые 100ms.
Stop закрывает источники и audio callback, join обоих workers, затем FIN и ограниченный drain 2s.
Удаление engine происходит до SoundManager и ядра; detach отменяет posts/timers и закрывает publisher
в uasync. Протокол uAV2 и wire v5 при добавлении desktop publisher не меняются.
- Один StreamPlayerWindow на процесс. Он содержит имя источника, состояние подключения, громкость,
полноэкранный режим и закрытие. Выбор нового источника закрывает предыдущего reader.
- transport/stream_bridge владеет одним viewer, готовит до двух media records и ограничивает RX 4MiB/16 записей.
@ -908,9 +953,15 @@ Opus/громкость на настоящем null audio backend, непрер
late/pressure drops, число и байты кадров, PTS границ очереди относительно часов и audio callback timing.
test_stream_service также проверяет общий каталог двух независимых источников одного канала,
шестисекундную паузу readers при живом сетевом приёме без restart и полное локальное/удалённое дочитывание FIN.
test_stream_publish проверяет реальные encoder/decoder H.264/H.265/VP9/AV1, обновление libx264 bitrate
с прежним decoder, общую публикацию/RS, смену revision, pressure/KEY recovery, FIN и concurrent detach
с балансом tracked allocations. Дополнительный Xvfb/private D-Bus сценарий проверяет реальный экран/окно,
стереомикрофон с двумя разными тонами, сырое превью, закрытие окна управления, неподвижный источник,
смену codec/bitrate/rotation и rollback без смены audio/source_epoch.
Статистика отправки на экране публикации:
- Отдельный uasync timer publisher каждые 100ms делает согласованный TX snapshot и передаёт его через JNI.
- Отдельный uasync timer общего stream_publisher каждые 100ms делает согласованный TX snapshot.
Android получает его через JNI, desktop — через mutex bridge; UI не читает живые очереди транспорта.
Kotlin обновляет отдельный StateFlow, без пересоздания preview. После close/detach timer отменяется.
- video_queue_bytes — оставшиеся байты с вычитанием offset частично упакованного головного кадра.
audio_queue_bytes — целые ожидающие Opus-пакеты. stream_pending_bytes — RS-части всех выдач текущей эпохи,

Loading…
Cancel
Save