mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
fix(talk): require Android output identity for cancellation
Co-authored-by: Zhilong Zheng <zhengzhilong1115@gmail.com>
This commit is contained in:
@@ -2927,7 +2927,7 @@ class TalkModeManager internal constructor(
|
||||
private suspend fun cancelRealtimeOutput(reason: String): Boolean =
|
||||
realtimeOutputCancellationMutex.withLock {
|
||||
val sessionId = realtimeSessionId ?: return@withLock true
|
||||
val turnId = realtimeOutputTurnId
|
||||
val turnId = realtimeOutputTurnId?.trim()?.takeIf(String::isNotEmpty) ?: return@withLock false
|
||||
val clear = CompletableDeferred<String?>()
|
||||
pendingRealtimeOutputClear = clear
|
||||
try {
|
||||
@@ -2935,7 +2935,7 @@ class TalkModeManager internal constructor(
|
||||
buildJsonObject {
|
||||
put("sessionId", JsonPrimitive(sessionId))
|
||||
put("reason", JsonPrimitive(reason))
|
||||
if (turnId != null) put("turnId", JsonPrimitive(turnId))
|
||||
put("turnId", JsonPrimitive(turnId))
|
||||
}
|
||||
val response = requestGateway("talk.session.cancelOutput", params.toString(), timeoutMs = 5_000)
|
||||
val result = requireAcceptedRealtimeOutputCancellation(response, turnId)
|
||||
@@ -2943,8 +2943,7 @@ class TalkModeManager internal constructor(
|
||||
// The response confirms provider cancellation; clear confirms that the
|
||||
// old playback boundary reached Android before capture can resume.
|
||||
val clearedTurnId = withTimeout(2_000) { clear.await() }
|
||||
val expectedTurnId = turnId ?: result.turnId
|
||||
check(expectedTurnId == null || clearedTurnId == expectedTurnId) {
|
||||
check(clearedTurnId == turnId) {
|
||||
"talk.session.cancelOutput clear turnId did not match"
|
||||
}
|
||||
true
|
||||
|
||||
@@ -100,18 +100,25 @@ class TalkModeManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun stopTtsCancelsTrackedPlaybackJob() {
|
||||
val manager = createManager()
|
||||
val playbackJob = Job()
|
||||
fun stopTtsWithoutOutputIdentityCancelsPlaybackWithoutReplacingCancellationWaiter() =
|
||||
runTest {
|
||||
val manager = createManager(scope = this)
|
||||
val playbackJob = Job()
|
||||
val pendingClear = CompletableDeferred<String?>()
|
||||
|
||||
setPrivateField(manager, "ttsJob", playbackJob)
|
||||
playbackGeneration(manager).set(7L)
|
||||
setPrivateField(manager, "ttsJob", playbackJob)
|
||||
setPrivateField(manager, "realtimeSessionId", "relay-1")
|
||||
setPrivateField(manager, "realtimeOutputTurnId", " ")
|
||||
setPrivateField(manager, "pendingRealtimeOutputClear", pendingClear)
|
||||
playbackGeneration(manager).set(7L)
|
||||
|
||||
manager.stopTts()
|
||||
manager.stopTts()
|
||||
runCurrent()
|
||||
|
||||
assertTrue(playbackJob.isCancelled)
|
||||
assertEquals(8L, playbackGeneration(manager).get())
|
||||
}
|
||||
assertTrue(playbackJob.isCancelled)
|
||||
assertEquals(8L, playbackGeneration(manager).get())
|
||||
assertTrue(readPrivateField(manager, "pendingRealtimeOutputClear") === pendingClear)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun disablingPlaybackCancelsTrackedJobOnce() {
|
||||
@@ -829,7 +836,7 @@ class TalkModeManagerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unconfirmedOutputCancellationClosesRealtimeRelay() =
|
||||
fun pushToTalkWithoutOutputIdentityClosesRealtimeRelayWithoutWaitingForClear() =
|
||||
runTest {
|
||||
var stoppedByRelay = false
|
||||
val manager =
|
||||
@@ -843,6 +850,7 @@ class TalkModeManagerTest {
|
||||
manager.pauseRealtimeCaptureForPushToTalk("capture-1")
|
||||
|
||||
assertNull(readPrivateField(manager, "realtimeSessionId"))
|
||||
assertNull(readPrivateField(manager, "pendingRealtimeOutputClear"))
|
||||
val pause = readPrivateField(manager, "realtimeCapturePause")!!
|
||||
assertEquals("capture-1", readPrivateField(pause, "pttCaptureId"))
|
||||
assertTrue(readPrivateField(pause, "restartRelay") as Boolean)
|
||||
|
||||
Reference in New Issue
Block a user