From 9742772880a3c9c8851a66bc62e6741828ba0261 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 29 Jul 2026 02:20:25 +0300 Subject: [PATCH] fix: monotonic playGeneration instead of re-settable stopped flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit stopped flag was set before join() but cleared after, causing race: if thread was still blocked in decodeRead when stopped was reset, onComplete fired anyway. Monotonic playGeneration ++ never decreases, thread captures myGen at start, compares after completion — correctly skipped if generation changed (another stop/seek started). --- .../java/com/utun/chat/data/AudioRecorderManager.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/AudioRecorderManager.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/AudioRecorderManager.kt index 38193669..7d9b5367 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/AudioRecorderManager.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/AudioRecorderManager.kt @@ -185,7 +185,7 @@ class AudioRecorderManager { @Volatile var elapsedMs: Int = 0; private set var pausedElapsedMs: Int = 0; private set private var playThread: Thread? = null - @Volatile private var stopped = false + @Volatile private var playGeneration = 0 fun playVoiceFile(filePath: String, onProgress: ((Float) -> Unit)? = null, onComplete: () -> Unit = {}) { playFromPosition(filePath, 0, onProgress, onComplete) @@ -196,6 +196,7 @@ class AudioRecorderManager { isPaused = false; elapsedMs = startMs; playing = true playThread = Thread { + val myGen = playGeneration try { val info = IntArray(3) val handle = NativeLib.voiceDecodeOpen(filePath, info) @@ -246,7 +247,7 @@ class AudioRecorderManager { } catch (e: Exception) { LogManager.addLog("ERROR", "AudioPlayer", "play error: ${e.message}") } - if (!stopped) { + if (playGeneration == myGen) { playing = false; isPaused = false; onComplete() } }.apply { start() } @@ -254,14 +255,12 @@ class AudioRecorderManager { fun pausePlayback() { pausedElapsedMs = elapsedMs - stopped = true; isPaused = true; playing = false + playGeneration++; isPaused = true; playing = false playThread?.join(500); playThread = null - stopped = false } fun stopPlayback() { - stopped = true; playing = false; isPaused = false; pausedElapsedMs = 0 + playGeneration++; playing = false; isPaused = false; pausedElapsedMs = 0 playThread?.join(500); playThread = null - stopped = false } }