diff --git a/doc/service_lifecycle.md b/doc/service_lifecycle.md index 7f629d04..f2bf683d 100644 --- a/doc/service_lifecycle.md +++ b/doc/service_lifecycle.md @@ -100,6 +100,13 @@ Live media хранится в RS-кольце с общим индексом PT части против вытеснения. После FIN publisher может снять своё владение, сохранив завершённый источник для оставшихся локальных readers. Последний close освобождает источник, индекс и кольцо. Новая публикация отсоединяет readers прежней эпохи. +Android preview собственного эфира не создаёт reader: Camera2 пишет прямо в TextureView +и encoder Surface. UI attach/detach меняет лишь camera session; audio/encoder/origin сохраняются. +UI, ожидающие команды camera handler и каждая camera session удерживают preview target отдельно. +TextureView возвращает false при destroy и снимает ссылку UI; Surface/SurfaceTexture освобождаются +после закрытия последней session. Capture stop запрещает attach и снимает своё владение target; +camera HandlerThread завершается после camera close и callbacks всех созданных sessions. +Отказ preview output возвращает encoder-only session и не завершает сам эфир. При stop/destroy отменяются delivery и media-index callbacks до освобождения store; destroy отсоединённого cursor не обращается к store. Frontend прекращает audio callback и worker до освобождения своего DSP; borrowed handle/RS pointers между потоками не передаются. diff --git a/doc/stream.txt b/doc/stream.txt index 6adcfa29..0aea11b5 100644 --- a/doc/stream.txt +++ b/doc/stream.txt @@ -834,13 +834,20 @@ Android: Отсутствие output progress 10s при наличии работы даёт ERROR; сетевые паузы и ожидание PTS допустимы. Состояния ожидания KEY и decoder разделены; логи показывают inputs/decoded/shown, рабочие slots, inflight и decoderLeadUs. Короткие audio gaps заполняются Opus PLC, большой разрыв сбрасывает timeline. - Локальный preview использует обычную подписку на собственный источник с отключённым воспроизведением - своего микрофона, чтобы исключить акустическую обратную связь. Локальный preview ориентируется по сенсору своей камеры - и текущему положению экрана; верх картинки зрителей отмечается красной гранью на кнопках поворота. - Положение камеры хранится per-revision отдельно от wire, чтобы queued кадры не использовали параметры новой камеры. - Ручной поворот сохраняет размеры и ориентацию локального превью; метка «Верх» на видео не рисуется. - Удалённый viewer применяет video rotation источника без локальной метки. Камера при закрытии preview продолжает работать. - Viewer закрывается на Activity ON_STOP и создаётся заново на ON_START; publisher от UI не зависит. + Локальный preview получает прямой Camera2 output в TextureView одновременно с encoder Surface. + Собственный источник не открывает viewer/cursor, decoder, AudioTrack и playback controller. + Preview ориентируется по сенсору камеры и текущему положению экрана; ручной поворот трансляции его не вращает. + Верх картинки зрителей отмечается красной гранью на кнопках поворота; метка «Верх» на видео не рисуется. + В обычном режиме preview выбирает поддерживаемый SurfaceTexture размер того же aspect, не более 1280x720; + high-speed использует размер encoder и createHighSpeedRequestList для двух targets с фиксированным FPS range. + Attach/detach preview меняет только CameraCaptureSession, сохраняя camera, encoder, audio, revision и origin. + При отказе дополнительного output логируется ERROR, UI показывает ошибку preview, камера возвращается к encoder-only session. + TextureView возвращает false из onSurfaceTextureDestroyed; UI, очередь команд camera thread и camera sessions + держат отдельные ссылки. Surface/texture освобождаются после последнего onClosed/onConfigureFailed и ухода UI. + Логи direct preview показывают first frame, FPS, возраст frame по SurfaceTexture timestamp и поворот; + camera session logs показывают generation, outputs, размер preview и сохранённый encoder/origin. + Удалённый viewer применяет video rotation источника. ON_STOP закрывает viewer либо отсоединяет прямой preview; + ON_START создаёт output заново. Камера при закрытии preview продолжает работать; publisher от UI не зависит. Видимый player удерживает экран включённым. Preview ограничен оставшимся местом, кнопки управления не перекрывает. - Source list общий для Android/desktop: stream_sources_json в uasync использует stream_member_load и stream_member_online. stream_watch_sources наблюдает один выбранный канал; group=0 снимает наблюдение. @@ -880,7 +887,7 @@ Kotlin progress — DEBUG раз в секунду; C packet-level диагно Android H264AnnexBTest (Annex B/length-prefixed NAL, SPS/PPS/IDR и усечённые данные), StreamCameraModesTest (точный режим новой камеры, снижение FPS и fallback 720p30), StreamOrientationTest (четыре положения переднего/заднего сенсора, включая SENSOR_ORIENTATION=0), -StreamPreviewTest (независимое превью, верх передней/задней камеры, экран и camera switch при queued frames). +StreamPreviewTest (поворот прямого preview по сенсору/экрану и lifetime Surface при смене session/уничтожении UI). Ручной поворот без изменения размера также проверяется test_android_stream с непрерывным аудио. C-тесты проверяют новую revision, потерю первого KEY, stale revision, сохранение аудио и source_epoch. Проверка 2026-10-12 на SM-A525F / LineageOS 23.2-20260622-NIGHTLY-a52q: