diff --git a/doc/service_lifecycle.md b/doc/service_lifecycle.md index 3d3a49ef..7f629d04 100644 --- a/doc/service_lifecycle.md +++ b/doc/service_lifecycle.md @@ -104,6 +104,21 @@ Live media хранится в RS-кольце с общим индексом PT destroy отсоединённого cursor не обращается к store. Frontend прекращает audio callback и worker до освобождения своего DSP; borrowed handle/RS pointers между потоками не передаются. +Чтение video cursor запрашивает следующий кадр по готовности decoder, независимо от +PTS показа; audio cursor сохраняет временной lookahead. Bridges готовят один ответ +на незавершённый запрос и не читают следующий кадр после получения ответа автоматически. +Android worker держит один рабочий input и один готовый output MediaCodec; свободный +input buffer получает лишь для уже готовых данных и сразу возвращает codec. +Первый decoded frame разрешает движение clock/audio. Будущий output ждёт PTS и +приостанавливает новые video requests, сохраняя независимую обработку audio/control. +PTS поданных кадров служат диагностике/проверке запаздывания, а не лимиту заполнения codec. +Смена revision заменяет только video decoder и его измеренный защитный guard; +GAP/EXPIRED начинают новую точку KEY. Нехватка сети сохраняет decoder references. +Desktop FFmpeg держит один рабочий AVPacket и два готовых изображения; EAGAIN оставляет +packet до следующего прохода. FIN подаёт EOS и дренирует выход до decoder EOF; +конец GUI требует также показа оставшихся изображений и завершения audio tail. +Отсутствие прогресса decoder при наличии работы имеет отдельную диагностику и срок 10s. + ACK-история принадлежит ядру и обновляется только при первом найденном подтверждении пакета. REINIT/close соединения не стирает уже подтверждённые за последнюю секунду байты. Общий `stream_publisher` Android/desktop владеет отдельным 100ms таймером TX-снимков; diff --git a/doc/stream.txt b/doc/stream.txt index 605b52d4..6adcfa29 100644 --- a/doc/stream.txt +++ b/doc/stream.txt @@ -813,14 +813,26 @@ Android: неполную пачку объединяет с аудио/видео до 20ms; продолжение работы через timer 5ms. При video pressure отбрасываются целые ожидающие кадры, P-кадры запрещены до нового KEY. Кодировщик получает отказ admission и запрашивает KEY с ограничением частоты 500ms. -- RX<=4MiB/256 records, подготовлено не более двух media records. Запас остаётся в общем RS-кольце; - bridge читает ближайшие кадры по запросу worker с текущим PTS и отдельными audio/video lookahead. - Kotlin держит до четырёх входных кадров, до трёх поданных decoder PTS и один ожидающий выход. - За проход подаётся до четырёх кадров, выход декодера обслуживается до восьми раз. +- RX<=4MiB/256 records, bridge готовит один ответ на незавершённый запрос worker. + Получение ответа и сетевые AVAILABLE не запускают автоматическое чтение следующего кадра. + Запас остаётся в RS-кольце. want_video запрашивает следующий полный видеокадр независимо от часов показа; + audio_ahead ограничивает только звук относительно PTS потребителя. Управление/звук обслуживаются независимо от video pressure. + StreamDecodePump держит один рабочий кодированный кадр и один ожидающий output MediaCodec. + Decoder заполняет свой внутренний конвейер до первого выхода без ограничений по числу поданных кадров или video lookahead. + Перед каждым входом проверяется выход; свободный input buffer берётся только для уже готового рабочего кадра. + Будущий output ждёт своего PTS и приостанавливает новые video requests; уже запрошенный ответ помещается в рабочий input. + Низкая задержка запрашивается через KEY_LOW_LATENCY при заявленной поддержке, но корректность не зависит от этого режима. + За проход обслуживаются до четырёх media replies, до восьми output buffers за один вызов pump. При обычной нехватке данных decoder references сохраняются; GAP/вытеснение требуют нового KEY. Просроченный кадр при нормальной последовательности декодируется без показа. -- Фиксированного prebuffer нет. AudioTrack задаёт время показа видео по реально услышанному PCM; +- Фиксированного prebuffer нет. Начало clock/audio output разрешено после первого декодированного кадра. + AudioTrack задаёт время показа видео по реально услышанному PCM; без аудио используются монотонные часы с остановкой на границе готовых кадров. + Защитный guard минутного контроллера учитывает audio device lead и наблюдённое опережение decoder + (максимум last_input_PTS-output_PTS текущей revision плюс период кадра). Drain не обнуляет этот guard; + новый decoder начинает измерение заново. Отдельного контроллера задержки декодера нет. + Отсутствие output progress 10s при наличии работы даёт ERROR; сетевые паузы и ожидание PTS допустимы. + Состояния ожидания KEY и decoder разделены; логи показывают inputs/decoded/shown, рабочие slots, inflight и decoderLeadUs. Короткие audio gaps заполняются Opus PLC, большой разрыв сбрасывает timeline. Локальный preview использует обычную подписку на собственный источник с отключённым воспроизведением своего микрофона, чтобы исключить акустическую обратную связь. Локальный preview ориентируется по сенсору своей камеры @@ -931,16 +943,20 @@ Desktop: в uasync. Протокол uAV2 и wire v5 при добавлении desktop publisher не меняются. - Один StreamPlayerWindow на процесс. Он содержит имя источника, состояние подключения, громкость, полноэкранный режим и закрытие. Выбор нового источника закрывает предыдущего reader. -- transport/stream_bridge владеет одним viewer, готовит до двух media records и ограничивает RX 4MiB/16 записей. +- transport/stream_bridge владеет одним viewer, готовит один ответ на запрос и ограничивает RX 4MiB/16 записей. Attach/detach выполняются в uasync; команды и копирование медиаданных защищены mutex. Post отменяется до destroy ядра; GUI/decoder не хранят заимствованные instance/handle pointers. - stream_media_cursor собирает ближайший access unit выбранного кодека и выдаёт Opus 48kHz mono/stereo/20ms из RS-кольца. Android AudioTrack и desktop output работают в stereo; mono-пакеты upmix выполняет libopus. FFmpeg/Opus декодируются отдельным worker; Qt-очередь не накапливает кадры. - Worker запрашивает видео при наличии менее двух готовых изображений; защитный предел — четыре. + Worker держит один рабочий AVPacket и не более двух готовых изображений. Следующий video request не ограничен часами показа. + FFmpeg output обслуживается перед input; EAGAIN сохраняет рабочий packet и означает backpressure, не GAP. Дальние кадры и звук не копируются из кольца. SoundTouch и устройство держат только рабочую порцию PCM. Кадры сохраняются до достижения их PTS аудиочасами; при задержке GUI общий clock останавливается. Видео декодируется без задержки frame-threading. При GAP сбрасываются decoder refs и timeline до KEY. +- Первый decoded frame разрешает движение clock/audio, защитный guard учитывает наблюдённый decoder lead. + FIN отправляет decoder EOS; выход дренируется теми же ограниченными проходами до EOF, GUI продолжает показ хвоста. + Ожидающий кадр не теряется при заполненной очереди изображений. Отсутствие прогресса при наличии работы логируется как ошибка. - При начальном подключении desktop/Android прогревают Opus из кольца до первого KEY (до 500ms истории). Старый звук обрезается по PTS видео, включая начало stereo PCM-пакета; декодер не сбрасывается из-за preroll. Фиксированного prebuffer нет: показ следует физическим audio callback timestamps; @@ -955,6 +971,12 @@ Opus/громкость на настоящем null audio backend, непрер late/pressure drops, число и байты кадров, PTS границ очереди относительно часов и audio callback timing. test_stream_service также проверяет общий каталог двух независимых источников одного канала, шестисекундную паузу readers при живом сетевом приёме без restart и полное локальное/удалённое дочитывание FIN. +StreamDecodePumpTest проверяет конвейеры 4/8 кадров при неподвижных часах без low-latency, ожидание PTS, +блокировку входа, сетевую паузу, пересечение ответа чтения с будущим output, короткий FIN и сохранение guard. +test_stream_playback проверяет восемь будущих кадров из кольца без video lookahead; test_android_stream — один ответ +при повторных запросах, отсутствие скрытого prefetch и возобновление с прежней позиции. +test_stream_view дополнительно задерживает четыре настоящих FFmpeg decoded frames: запуск требует кадра после 80ms, +а короткий поток из трёх кадров получает все изображения после FIN, без потери decoder tail. 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 сценарий проверяет реальный экран/окно,