|
|
|
@ -19,10 +19,13 @@ import androidx.compose.runtime.* |
|
|
|
import androidx.compose.ui.Modifier |
|
|
|
import androidx.compose.ui.Modifier |
|
|
|
import androidx.compose.ui.Alignment |
|
|
|
import androidx.compose.ui.Alignment |
|
|
|
import androidx.compose.ui.platform.LocalContext |
|
|
|
import androidx.compose.ui.platform.LocalContext |
|
|
|
|
|
|
|
import androidx.compose.ui.platform.LocalLifecycleOwner |
|
|
|
import androidx.compose.ui.res.stringResource |
|
|
|
import androidx.compose.ui.res.stringResource |
|
|
|
import androidx.compose.ui.unit.dp |
|
|
|
import androidx.compose.ui.unit.dp |
|
|
|
import androidx.compose.ui.viewinterop.AndroidView |
|
|
|
import androidx.compose.ui.viewinterop.AndroidView |
|
|
|
import androidx.core.content.ContextCompat |
|
|
|
import androidx.core.content.ContextCompat |
|
|
|
|
|
|
|
import androidx.lifecycle.Lifecycle |
|
|
|
|
|
|
|
import androidx.lifecycle.LifecycleEventObserver |
|
|
|
import com.utun.chat.R |
|
|
|
import com.utun.chat.R |
|
|
|
import com.utun.chat.data.LogManager |
|
|
|
import com.utun.chat.data.LogManager |
|
|
|
import com.utun.chat.data.NativeLib |
|
|
|
import com.utun.chat.data.NativeLib |
|
|
|
@ -131,6 +134,21 @@ fun StreamScreen(channelId: String, channelName: String, onBack: () -> Unit) { |
|
|
|
|
|
|
|
|
|
|
|
@Composable |
|
|
|
@Composable |
|
|
|
private fun LiveStreamView(group: Long, source: Long, localPreview: Boolean) { |
|
|
|
private fun LiveStreamView(group: Long, source: Long, localPreview: Boolean) { |
|
|
|
|
|
|
|
val owner = LocalLifecycleOwner.current |
|
|
|
|
|
|
|
var visible by remember(owner) { mutableStateOf(owner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) } |
|
|
|
|
|
|
|
DisposableEffect(owner) { |
|
|
|
|
|
|
|
val observer = LifecycleEventObserver { _, event -> |
|
|
|
|
|
|
|
if (event == Lifecycle.Event.ON_START) visible = true |
|
|
|
|
|
|
|
if (event == Lifecycle.Event.ON_STOP) visible = false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
owner.lifecycle.addObserver(observer) |
|
|
|
|
|
|
|
onDispose { owner.lifecycle.removeObserver(observer) } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (visible) LiveStreamSurface(group, source, localPreview) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Composable |
|
|
|
|
|
|
|
private fun LiveStreamSurface(group: Long, source: Long, localPreview: Boolean) { |
|
|
|
val engine = remember(group, source, localPreview) { StreamPlayerEngine(group, source, localPreview) } |
|
|
|
val engine = remember(group, source, localPreview) { StreamPlayerEngine(group, source, localPreview) } |
|
|
|
val aspect by engine.aspect.collectAsState() |
|
|
|
val aspect by engine.aspect.collectAsState() |
|
|
|
val status by engine.status.collectAsState() |
|
|
|
val status by engine.status.collectAsState() |
|
|
|
@ -140,21 +158,22 @@ private fun LiveStreamView(group: Long, source: Long, localPreview: Boolean) { |
|
|
|
Text(stringResource(status)) |
|
|
|
Text(stringResource(status)) |
|
|
|
Box(Modifier.weight(1f).fillMaxWidth(), contentAlignment = Alignment.Center) { |
|
|
|
Box(Modifier.weight(1f).fillMaxWidth(), contentAlignment = Alignment.Center) { |
|
|
|
AndroidView(factory = { context -> |
|
|
|
AndroidView(factory = { context -> |
|
|
|
TextureView(context).apply { |
|
|
|
TextureView(context).apply { |
|
|
|
surfaceTextureListener = object : TextureView.SurfaceTextureListener { |
|
|
|
keepScreenOn = true |
|
|
|
override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) { |
|
|
|
surfaceTextureListener = object : TextureView.SurfaceTextureListener { |
|
|
|
surface = Surface(texture); engine.start(surface!!) |
|
|
|
override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) { |
|
|
|
} |
|
|
|
surface = Surface(texture); engine.start(surface!!) |
|
|
|
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {} |
|
|
|
} |
|
|
|
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture): Boolean { |
|
|
|
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {} |
|
|
|
engine.stop(); surface?.release(); surface = null; return true |
|
|
|
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture): Boolean { |
|
|
|
|
|
|
|
engine.stop(); surface?.release(); surface = null; return true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
override fun onSurfaceTextureUpdated(texture: SurfaceTexture) {} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
override fun onSurfaceTextureUpdated(texture: SurfaceTexture) {} |
|
|
|
}, modifier = Modifier.aspectRatio(aspect, matchHeightConstraintsFirst = true), onRelease = { view -> |
|
|
|
} |
|
|
|
engine.stop(); view.surfaceTextureListener = null; surface?.release(); surface = null |
|
|
|
} |
|
|
|
}) |
|
|
|
}, modifier = Modifier.aspectRatio(aspect, matchHeightConstraintsFirst = true), onRelease = { view -> |
|
|
|
|
|
|
|
engine.stop(); view.surfaceTextureListener = null; surface?.release(); surface = null |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|