From 47033718ad5f66419b0ff43f28161c2af8187bb2 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 19 Oct 2026 18:23:25 +0200 Subject: [PATCH] Apply capture gap recovery cadence consistently on Android --- .../app/src/main/java/com/utun/chat/data/CallVideoNative.kt | 2 +- .../app/src/main/java/com/utun/chat/data/CallVideoPlayer.kt | 6 +++--- tools/chatgui-android/jni_bridge/android_call_video_jni.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoNative.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoNative.kt index b5dd3170..361cd11e 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoNative.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoNative.kt @@ -17,7 +17,7 @@ internal object CallVideoNative { external fun playoutReset(handle: Long) /** >0: ждать микросекунды; 0: показать; <0: пропустить только показ. */ external fun playoutStep(handle: Long, pts: Long, received: Long, nextPts: Long, nextReceived: Long, - now: Long): Long + now: Long, intervalUs: Int): Long external fun requestKey(id: Long) external fun range(id: Long, minimum: Int, maximum: Int): Boolean external fun inspect(codec: Int, bytes: ByteArray): LongArray? diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoPlayer.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoPlayer.kt index 8bc4165b..600173a5 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoPlayer.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoPlayer.kt @@ -35,7 +35,7 @@ internal class CallVideoPlayer(private val id: Long, private val failure: (Strin fun stop() { synchronized(this) { running = false }; worker.join() } private fun loop() { - data class Timing(val pts: Long, val received: Long) + data class Timing(val pts: Long, val received: Long, val interval: Int) data class Picture(val index: Int, val timing: Timing) val playout = CallVideoNative.playoutCreate(id) if (playout == 0L) { failure("Video playout allocation failed"); return } @@ -100,7 +100,7 @@ internal class CallVideoPlayer(private val id: Long, private val failure: (Strin val first = if (awaitingPts < 0) pictures.peekFirst() else null val nextPicture = if (first != null && pictures.size > 1) pictures.peekLast() else null val decision = CallVideoNative.playoutStep(playout, first?.timing?.pts ?: -1, first?.timing?.received ?: 0, - nextPicture?.timing?.pts ?: -1, nextPicture?.timing?.received ?: 0, now / 1000) + nextPicture?.timing?.pts ?: -1, nextPicture?.timing?.received ?: 0, now / 1000, first?.timing?.interval ?: 0) if (decision > 0) wakeUs = now / 1000 + decision else if (first != null) { val render = decision == 0L @@ -153,7 +153,7 @@ internal class CallVideoPlayer(private val id: Long, private val failure: (Strin } else data val buffer = checkNotNull(decoder!!.getInputBuffer(index)); check(bytes.size <= buffer.capacity()) buffer.put(bytes); decoder!!.queueInputBuffer(index, 0, bytes.size, meta[10], 0) - inputs.addLast(Timing(meta[10], meta[12])); pending = null; queued++; worked = true + inputs.addLast(Timing(meta[10], meta[12], 1000000 / next.fps)); pending = null; queued++; worked = true } } } else if (data != null && surface == null) { pending = null; CallVideoNative.requestKey(id) } diff --git a/tools/chatgui-android/jni_bridge/android_call_video_jni.c b/tools/chatgui-android/jni_bridge/android_call_video_jni.c index 2efac24b..4338abe3 100644 --- a/tools/chatgui-android/jni_bridge/android_call_video_jni.c +++ b/tools/chatgui-android/jni_bridge/android_call_video_jni.c @@ -110,10 +110,10 @@ JNIEXPORT void JNICALL Java_com_utun_chat_data_CallVideoNative_playoutReset(JNIE call_video_playout_init(p, p->call_id); } JNIEXPORT jlong JNICALL Java_com_utun_chat_data_CallVideoNative_playoutStep(JNIEnv *e, jobject o, jlong handle, - jlong pts, jlong received, jlong next_pts, jlong next_received, jlong now) { + jlong pts, jlong received, jlong next_pts, jlong next_received, jlong now, jint interval_us) { (void)e; (void)o; struct call_video_playout *p = (void *)(uintptr_t)handle; if (!p) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video playout poll without handle"); return 5000; } - struct call_video_playout_frame f = {pts, received}, next = {next_pts, next_received}; + struct call_video_playout_frame f = {pts, received, interval_us}, next = {next_pts, next_received, interval_us}; struct call_clock_snapshot clock = {0}; call_audio_get_clock(p->call_id, now, &clock); int action = call_video_playout_poll(p, pts >= 0 ? &f : NULL, next_pts >= 0 ? &next : NULL, now, &clock); if (action == CALL_VIDEO_PLAYOUT_SHOW) return 0;