Browse Source

Detach direct camera preview immediately when UI goes to background

master
evgeny 4 days ago
parent
commit
b8a2d7a555
  1. 13
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamPreview.kt
  2. 9
      tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamScreen.kt

13
tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamPreview.kt

@ -46,6 +46,7 @@ class StreamPreview {
private var target: StreamPreviewTarget? = null
private var owner: ((StreamPreviewTarget?) -> Unit)? = null
private var closed = false
private var visible = true
private val mutable = MutableStateFlow(StreamPreviewState())
val state: StateFlow<StreamPreviewState> = mutable
@ -53,7 +54,7 @@ class StreamPreview {
val next = StreamPreviewTarget(texture)
if (closed) { LogManager.addLog("WARN", "video", "direct preview attach after capture stopped"); return next }
val previous = target
target = next.retain(); owner?.invoke(next.retain()); previous?.release()
target = next.retain(); owner?.invoke(if (visible) next.retain() else null); previous?.release()
LogManager.addLog("INFO", "video", "direct preview attached target=${System.identityHashCode(next)} bound=${owner != null}")
return next // Первую ссылку освобождает UI в onSurfaceTextureDestroyed, возвращая false.
}
@ -67,7 +68,15 @@ class StreamPreview {
@Synchronized internal fun bind(listener: (StreamPreviewTarget?) -> Unit) {
check(!closed && owner == null)
owner = listener; listener(target?.retain())
owner = listener; listener(if (visible) target?.retain() else null)
}
/** Lifecycle отключает output сразу, даже когда Compose уже приостановил recomposition. */
@Synchronized fun setVisible(value: Boolean) {
if (visible == value || closed) return
visible = value; owner?.invoke(if (visible) target?.retain() else null)
if (!visible) mutable.value = mutable.value.copy(active = false)
LogManager.addLog("INFO", "video", "direct preview visibility=$visible target=${target?.let(System::identityHashCode)}")
}
internal fun update(format: StreamPreviewFormat?, active: Boolean = false, failed: Boolean = false) {

9
tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamScreen.kt

@ -298,13 +298,14 @@ private fun StreamRotationMark(top: Int) {
private fun LiveStreamView(group: Long, source: Long, epoch: Long, localPreview: StreamPreview?) {
val owner = LocalLifecycleOwner.current
var visible by remember(owner) { mutableStateOf(owner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) }
DisposableEffect(owner) {
DisposableEffect(owner, localPreview) {
localPreview?.setVisible(visible)
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_START) visible = true
if (event == Lifecycle.Event.ON_STOP) visible = false
if (event == Lifecycle.Event.ON_START) { localPreview?.setVisible(true); visible = true }
if (event == Lifecycle.Event.ON_STOP) { localPreview?.setVisible(false); visible = false }
}
owner.lifecycle.addObserver(observer)
onDispose { owner.lifecycle.removeObserver(observer) }
onDispose { owner.lifecycle.removeObserver(observer); localPreview?.setVisible(false) }
}
val context = LocalContext.current
val configuration = LocalConfiguration.current

Loading…
Cancel
Save