diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamPlayerEngine.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamPlayerEngine.kt index 262debcb..75f69a54 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamPlayerEngine.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamPlayerEngine.kt @@ -20,7 +20,8 @@ import kotlin.math.roundToInt /** Один worker владеет декодерами и AudioTrack. Hardware audio clock управляет временем показа видео. * Просроченные P-кадры декодируются без показа, чтобы сохранить references; при переполнении ждём KEY. * viewerLock сериализует stop/open разных экранов до подтверждения освобождения native owner. */ -class StreamPlayerEngine(private val group: Long, private val source: Long, private val muteAudio: Boolean = false) { +class StreamPlayerEngine(private val group: Long, private val source: Long, private val epoch: Long, + private val muteAudio: Boolean = false) { companion object { private val viewerLock = ReentrantLock() } private data class Frame(val pts: Long, val key: Boolean, val width: Int, val height: Int, val rotation: Int, val data: ByteArray) private val mutableAspect = MutableStateFlow(16f / 9f) @@ -120,7 +121,7 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv } } try { - check(NativeLib.streamOpen(id, group, source)) { "Viewer open refused" } + check(NativeLib.streamOpen(id, group, source, epoch = epoch)) { "Viewer open refused" } val openDeadline = System.nanoTime() + 10_000_000_000 var opened = false var prefillUntil = 0L @@ -131,7 +132,7 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv if (raw != null) { check(raw.size >= 20) val b = ByteBuffer.wrap(raw).order(ByteOrder.BIG_ENDIAN) - val kind = b.get().toInt(); val key = b.get().toInt() and 1 != 0 + val kind = b.get().toInt(); val flags = b.get().toInt() and 255; val key = flags and 1 != 0 val width = b.short.toInt() and 65535; val height = b.short.toInt() and 65535 val rotation = b.short.toInt() and 65535; val pts = b.long; val size = b.int check(size == b.remaining()) @@ -161,7 +162,17 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv 3 -> { LogManager.addLog("INFO", "stream", "viewer GAP id=$id"); resetVideo(); resetAudio(); videoBase = -1; prefillUntil = 0 } 4 -> opened = true 5 -> ended = true - 6 -> error("Native viewer closed") + 6 -> { + mutableStatus.value = when (flags) { + 1 -> R.string.stream_group_closed + 2 -> R.string.chat_service_stopped + 3 -> R.string.stream_source_changed + 4 -> R.string.stream_member_removed + else -> R.string.stream_failed + } + LogManager.addLog("WARN", "stream", "native viewer closed id=$id group=$group source=$source epoch=$epoch reason=$flags") + ended = true; running = false + } else -> error("Unknown media event=$kind") } } diff --git a/tools/chatgui-android/app/src/main/res/values-ru/strings.xml b/tools/chatgui-android/app/src/main/res/values-ru/strings.xml index 63b76696..4ae65ff1 100644 --- a/tools/chatgui-android/app/src/main/res/values-ru/strings.xml +++ b/tools/chatgui-android/app/src/main/res/values-ru/strings.xml @@ -1,6 +1,12 @@ Трансляции + Трансляции: %1$d + Выберите трансляцию + Не удалось получить список трансляций + Трансляция перезапущена или завершена. Выберите источник заново. + Источник больше не является участником канала + Канал закрыт Начать трансляцию Остановить трансляцию Прямая трансляция diff --git a/tools/chatgui-android/app/src/main/res/values/strings.xml b/tools/chatgui-android/app/src/main/res/values/strings.xml index e09b866d..c451e585 100644 --- a/tools/chatgui-android/app/src/main/res/values/strings.xml +++ b/tools/chatgui-android/app/src/main/res/values/strings.xml @@ -1,6 +1,12 @@ Live streams + Live streams: %1$d + Choose a stream + Could not load live streams + The stream has restarted or ended. Select a source again. + The source is no longer a channel member + The channel is closed Start stream Stop stream Streaming live