@ -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-части всех выдач текущей эпохи,