Fix Android stream layout and show measured publisher bitrate
This commit is contained in:
1 parent
e246357f92
commit
b8bc9b409a
7 files changed
+46
-24
No files matched your search
+15
-22
@@ -2,7 +2,6 @@ package com.utun.chat.ui.screens
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ContextWrapper
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.view.Surface
|
||||
import android.view.TextureView
|
||||
@@ -42,14 +41,13 @@ import com.utun.chat.data.LogManager
|
||||
import com.utun.chat.data.StreamPlayerEngine
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
/** Полноэкранный viewer: геометрия видео не зависит от видимости управления. */
|
||||
/** Полноэкранный viewer: видео разворачивается вдоль окна, ориентацию экрана не меняем. */
|
||||
@Composable
|
||||
internal fun StreamViewerScreen(group: Long, source: Long, epoch: Long, title: String, name: String, onClose: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val activity = remember(context) {
|
||||
generateSequence(context) { (it as? ContextWrapper)?.baseContext }.filterIsInstance<Activity>().firstOrNull()
|
||||
}
|
||||
val previousOrientation = remember(activity) { activity?.requestedOrientation }
|
||||
val owner = LocalLifecycleOwner.current
|
||||
var visible by remember(owner) { mutableStateOf(owner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) }
|
||||
var aspect by remember { mutableStateOf(0f) }
|
||||
@@ -75,25 +73,13 @@ internal fun StreamViewerScreen(group: Long, source: Long, epoch: Long, title: S
|
||||
val behavior = controller?.systemBarsBehavior
|
||||
controller?.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
controller?.hide(WindowInsetsCompat.Type.systemBars())
|
||||
LogManager.addLog("INFO", "stream", "viewer fullscreen source=$source epoch=$epoch orientation=$previousOrientation")
|
||||
LogManager.addLog("INFO", "stream", "viewer fullscreen source=$source epoch=$epoch " +
|
||||
"screenOrientation=${activity?.requestedOrientation}")
|
||||
onDispose {
|
||||
if (previousOrientation != null) activity?.requestedOrientation = previousOrientation
|
||||
if (behavior != null) controller?.systemBarsBehavior = behavior
|
||||
if (statusVisible) controller?.show(WindowInsetsCompat.Type.statusBars()) else controller?.hide(WindowInsetsCompat.Type.statusBars())
|
||||
if (navigationVisible) controller?.show(WindowInsetsCompat.Type.navigationBars()) else controller?.hide(WindowInsetsCompat.Type.navigationBars())
|
||||
LogManager.addLog("INFO", "stream", "viewer window restored source=$source orientation=$previousOrientation")
|
||||
}
|
||||
}
|
||||
LaunchedEffect(activity, aspect) {
|
||||
// Формат уже учитывает rotation источника. До первого KEY ориентацию не угадываем.
|
||||
val orientation = when {
|
||||
aspect > 1f -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
aspect > 0f && aspect < 1f -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|
||||
else -> null
|
||||
}
|
||||
if (activity != null && orientation != null && activity.requestedOrientation != orientation) {
|
||||
activity.requestedOrientation = orientation
|
||||
LogManager.addLog("INFO", "stream", "viewer orientation source=$source aspect=$aspect requested=$orientation")
|
||||
LogManager.addLog("INFO", "stream", "viewer window restored source=$source")
|
||||
}
|
||||
}
|
||||
LaunchedEffect(status) {
|
||||
@@ -114,14 +100,21 @@ internal fun StreamViewerScreen(group: Long, source: Long, epoch: Long, title: S
|
||||
|
||||
BoxWithConstraints(Modifier.fillMaxSize().background(Color.Black).clipToBounds()) {
|
||||
val ratio = aspect.takeIf { it > 0f } ?: 16f / 9f
|
||||
val width = minOf(maxWidth, maxHeight * ratio)
|
||||
val turn = aspect > 0f && minOf(maxHeight, maxWidth * ratio) > minOf(maxWidth, maxHeight * ratio)
|
||||
val width = if (turn) minOf(maxHeight, maxWidth * ratio) else minOf(maxWidth, maxHeight * ratio)
|
||||
val height = width / ratio
|
||||
val density = LocalDensity.current
|
||||
val videoSize = with(density) { Size(width.toPx(), height.toPx()) }
|
||||
// Жесты работают в координатах окна, поэтому учитывают размеры после поворота видео.
|
||||
val videoSize = with(density) { if (turn) Size(height.toPx(), width.toPx()) else Size(width.toPx(), height.toPx()) }
|
||||
val viewport = with(density) { Size(maxWidth.toPx(), maxHeight.toPx()) }
|
||||
LaunchedEffect(aspect, turn, videoSize, viewport) {
|
||||
LogManager.addLog("INFO", "stream", "viewer fit source=$source aspect=$aspect viewport=$viewport " +
|
||||
"video=$videoSize videoRotation=${if (turn) 90 else 0}")
|
||||
}
|
||||
LaunchedEffect(videoSize, viewport) { zoom.constrain(videoSize, viewport) }
|
||||
if (visible) StreamViewerPlayback(group, source, epoch, { aspect = it }, { status = it },
|
||||
Modifier.size(width, height).align(Alignment.Center).graphicsLayer {
|
||||
Modifier.requiredSize(width, height).align(Alignment.Center).graphicsLayer {
|
||||
rotationZ = if (turn) 90f else 0f
|
||||
scaleX = zoom.scale; scaleY = zoom.scale
|
||||
translationX = zoom.offset.x; translationY = zoom.offset.y
|
||||
})
|
||||
@@ -136,7 +129,7 @@ internal fun StreamViewerScreen(group: Long, source: Long, epoch: Long, title: S
|
||||
}
|
||||
})
|
||||
if (controls) {
|
||||
Row(Modifier.fillMaxWidth().align(Alignment.TopCenter).background(Color.Black.copy(alpha = 0.65f))
|
||||
Row(Modifier.fillMaxWidth().align(Alignment.TopCenter).background(Color.Black.copy(alpha = 0.325f))
|
||||
.windowInsetsPadding(WindowInsets.safeDrawing).padding(start = 16.dp, end = 4.dp, top = 4.dp, bottom = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
|
||||
Reference in new issue
Block a user