diff --git a/doc/service_lifecycle.md b/doc/service_lifecycle.md index 219bfb94..f8279ecd 100644 --- a/doc/service_lifecycle.md +++ b/doc/service_lifecycle.md @@ -136,8 +136,13 @@ destroy отсоединённого cursor не обращается к store. и worker до освобождения своего DSP; borrowed handle/RS pointers между потоками не передаются. Чтение video cursor запрашивает следующий кадр по готовности decoder, независимо от -PTS показа; audio cursor сохраняет временной lookahead. Bridges готовят один ответ -на незавершённый запрос и не читают следующий кадр после получения ответа автоматически. +PTS показа; audio cursor сохраняет временной lookahead. Viewers готовят ограниченный батч +на запрос: отдельно задаются число видеокадров, audio lookahead и число всех записей. +Desktop принимает до 16 записей и обрабатывает треки по их готовности; Android запрашивает одну запись. +Получение батча погашает запрос, включая повторные обращения до pull; скрытого чтения следующего батча нет. +Callback готовности только будит desktop worker и не вызывает API ядра/bridge. Stop снимает callback +под mutex viewer до освобождения его контекста; detach будит ожидающие workers до уничтожения manager. +GUI и audio callback будят worker при движении часов/освобождении места; сна между готовыми пакетами нет. Android worker держит один рабочий input и один готовый output MediaCodec; свободный input buffer получает лишь для уже готовых данных и сразу возвращает codec. Первый decoded frame разрешает движение clock/audio. Будущий output ждёт PTS и diff --git a/doc/stream.txt b/doc/stream.txt index a55cdc64..0bcbc99e 100644 --- a/doc/stream.txt +++ b/doc/stream.txt @@ -828,7 +828,8 @@ Android: неполную пачку объединяет с аудио/видео до 20ms; продолжение работы через timer 5ms. При video pressure отбрасываются целые ожидающие кадры, P-кадры запрещены до нового KEY. Кодировщик получает отказ admission и запрашивает KEY с ограничением частоты 500ms. -- RX: stream_viewers держит отдельный handle/cursor, demand, status и один owned ответ на session ID. +- RX: stream_viewers держит отдельный handle/cursor, demand, status и ограниченный owned батч на session ID. + Android задаёт бюджет в одну запись, соответствующий одному рабочему input StreamDecodePump. Общей RX FIFO нет: остановка/отставание одного reader не задерживает остальных. Получение ответа и сетевые AVAILABLE не запускают автоматическое чтение следующего кадра. Запас остаётся в RS-кольце. want_video запрашивает следующий полный видеокадр независимо от часов показа; @@ -1026,13 +1027,21 @@ Desktop: в uasync. Протокол uAV2 и wire v5 при добавлении desktop publisher не меняются. - Одиночный StreamPlayerWindow либо StreamGridWindow с отдельным player на источник. Player содержит имя, состояние и громкость; fullscreen/close в сетке принадлежат общему окну. -- transport/stream_bridge владеет stream_viewers: независимый cursor и один ближайший ответ на reader. +- transport/stream_bridge владеет stream_viewers: независимый cursor и ближайший батч на reader. Attach/detach выполняются в uasync; команды и копирование медиаданных защищены mutex. Post отменяется до destroy ядра; GUI/decoder не хранят заимствованные instance/handle pointers. + Запрос задаёт число видеокадров, audio lookahead и максимум 16 записей. Проход reader ограничен 2ms/256KiB; + последняя целая запись может пересечь порог байтов, но один кадр не превышает 2MiB. + При WAIT/MORE готовая часть отдаётся сразу. Получение батча погашает запрос, включая его повторы до pull. + Callback готовности будит worker через condition variable; GUI/audio также будят его при освобождении места. + Stop снимает callback до уничтожения worker; detach будит ожидание перед освобождением manager. - stream_media_cursor собирает ближайший access unit выбранного кодека и выдаёт Opus 48kHz mono/stereo/20ms из RS-кольца. Android AudioTrack и desktop output работают в stereo; mono-пакеты upmix выполняет libopus. FFmpeg/Opus декодируются отдельным worker; Qt-очередь не накапливает кадры. Worker держит один рабочий AVPacket и не более двух готовых изображений. Следующий video request не ограничен часами показа. + Бюджет нового видео учитывает AVPacket, готовые изображения и оставшиеся кодированные кадры батча. + Записи аудио/видео расходуются независимо по готовности потребителя; заполненное видео не блокирует запрос звука. + GAP/FIN/CLOSED обрабатываются после предыдущих записей батча. Между готовыми пакетами нет sleep или нового round trip к ядру. FFmpeg output обслуживается перед input; EAGAIN сохраняет рабочий packet и означает backpressure, не GAP. Дальние кадры и звук не копируются из кольца. SoundTouch и устройство держат только рабочую порцию PCM. Кадры сохраняются до достижения их PTS аудиочасами; задержка показа удерживает clock только этого player. @@ -1105,6 +1114,11 @@ test_stream_playback проверяет восемь будущих кадров при повторных запросах, отсутствие скрытого prefetch и возобновление с прежней позиции. test_stream_view дополнительно задерживает четыре настоящих FFmpeg decoded frames: запуск требует кадра после 80ms, а короткий поток из трёх кадров получает все изображения после FIN, без потери decoder tail. +Батчевый сценарий проверяет накопленный поток, раздельные бюджеты треков, независимые readers, уведомления и остановку: +28 video + 50 audio записей проходят через 16 батчей без пропусков/повторов, END следует за последними данными. +Диагностика debug: viewer buffer выводит число/максимальный размер батчей и prepare/handoff (среднее/максимум); +desktop viewer work — обработанные записи, batch_max, pending_records, data_signals и wait_us (сумма/максимум). +wait_us включает полезное ожидание новых данных/места; задержка уже готового батча измеряется handoff_us. 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 сценарий проверяет реальный экран/окно,