From a5fea0c5035bd1f117ed5aa5e2221eb55bf3aaa3 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 28 Oct 2026 17:47:28 +0100 Subject: [PATCH] Preserve replacement PTT requests during obsolete capture rollback --- .../com/utun/chat/data/RadioAudioEngine.kt | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/RadioAudioEngine.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/RadioAudioEngine.kt index 01578286..633e14df 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/data/RadioAudioEngine.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/data/RadioAudioEngine.kt @@ -36,7 +36,7 @@ import java.util.concurrent.Future * talkingFlow показывает запрос/наблюдаемый TX, transmittingGroup — фактический native TX своего канала. * Подписка/native capture и workers сохраняются до запуска API/Thread: частичный отказ получает rollback. * Ошибка capture останавливает его подписку/encoder, сохраняя приём; ошибка playback освобождает всю свою сессию. - * Очистка идёт на io независимо от доставки main; identity/pоколение защищают заменившую сессию. + * Очистка идёт на io независимо от доставки main; identity/поколение защищают заменившую сессию. */ class RadioAudioEngine { @@ -417,6 +417,7 @@ class RadioAudioEngine { /** Оба детектора используют одно окно по экрану/фону; измеритель не продлевает это окно. */ private fun updateCapture() { + val version = generation try { mainHandler.removeCallbacks(vadTimeout) if (!settingsReady) return @@ -440,10 +441,13 @@ class RadioAudioEngine { if (audioTrack == null) return if (captureSubscription == null && nativeCaptureOwned) stopCapture() if (captureSubscription == null && !startCapture(mode)) { - requestedTalk = false - _talkingFlow.value = false + if (generation == version) { + requestedTalk = false + _talkingFlow.value = nativeCaptureOwned && _transmittingGroup.value != null + } return } + if (generation != version) return if (requestedTalk != capturePttRequested) { if (captureSubscription?.ptt(requestedTalk) != true) { LogManager.addLog("ERROR", "radio", "PTT command rejected; stopping capture group=$audioGroup") @@ -453,9 +457,11 @@ class RadioAudioEngine { capturePttRequested = requestedTalk } } catch (e: Exception) { - requestedTalk = false - _talkingFlow.value = nativeCaptureOwned && _transmittingGroup.value != null - LogManager.addLog("ERROR", "RadioAudio", "capture update failed group=$audioGroup generation=$generation " + + if (generation == version) { + requestedTalk = false + _talkingFlow.value = nativeCaptureOwned && _transmittingGroup.value != null + } + LogManager.addLog("ERROR", "RadioAudio", "capture update failed group=$audioGroup generation=$version current=$generation " + "nativeOwned=$nativeCaptureOwned; retained for retry: $e") } } @@ -516,7 +522,7 @@ class RadioAudioEngine { LogManager.addLog("INFO", "radio", "capture started group=$captureGroup ch=$channels mode=$autoMode shared=true") return true } catch (e: Exception) { - requestedTalk = false + if (generation == version) requestedTalk = false LogManager.addLog("ERROR", "RadioAudio", "capture startup failed operation=$operation group=$captureGroup " + "generation=$version mode=$mode: $e") try { stopCapture() } catch (cleanup: Exception) {