From bf8e591930ef56e4a579c853846385802613c1c4 Mon Sep 17 00:00:00 2001 From: Bruno Deanoz Date: Wed, 24 Jun 2026 12:44:01 +0200 Subject: [PATCH] fix Live Call: 20s connect timeout + reconnect_failed ends call CONNECTING state could hang forever if the server never responded or kept failing silently. Now: 20s timeout ends the call with a visible error, and reconnect_failed is treated as terminal. --- .../java/dev/kaizen/app/live/LiveCallService.kt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/dev/kaizen/app/live/LiveCallService.kt b/app/src/main/java/dev/kaizen/app/live/LiveCallService.kt index 042c57e..af31d27 100644 --- a/app/src/main/java/dev/kaizen/app/live/LiveCallService.kt +++ b/app/src/main/java/dev/kaizen/app/live/LiveCallService.kt @@ -93,6 +93,8 @@ class LiveCallService : Service() { // ─── Start / End ────────────────────────────────────────────────────── + private var connectTimeoutJob: Job? = null + fun startCall(baseUrl: String, token: String, model: String, voice: String, conversationId: String?) { if (_status.value != CallStatus.IDLE) return @@ -114,6 +116,15 @@ class LiveCallService : Service() { pipeline.onChunk = { base64 -> liveClient.sendAudio(base64) } + connectTimeoutJob = scope.launch { + delay(20_000) + if (_status.value == CallStatus.CONNECTING) { + _subtitle.value = "Verbindung fehlgeschlagen" + onError?.invoke("timeout", "Connection timeout after 20s") + endCall() + } + } + liveClient.connect(model, voice, conversationId) } @@ -123,6 +134,7 @@ class LiveCallService : Service() { client?.end() audio?.release() durationJob?.cancel() + connectTimeoutJob?.cancel() client?.dispose() client = null @@ -151,6 +163,7 @@ class LiveCallService : Service() { private fun handleEvent(event: ServerEvent, pipeline: AudioPipeline) { when (event) { is ServerEvent.Ready -> { + connectTimeoutJob?.cancel() _status.value = CallStatus.LISTENING if (!pipeline.initPlayback()) { @@ -230,7 +243,7 @@ class LiveCallService : Service() { is ServerEvent.Error -> { _subtitle.value = event.message ?: event.code onError?.invoke(event.code, event.message) - if (event.code in setOf("auth_failed", "restricted_model", "restricted_feature", "budget_exceeded", "concurrent_limit", "provider_error")) { + if (event.code in setOf("auth_failed", "restricted_model", "restricted_feature", "budget_exceeded", "concurrent_limit", "provider_error", "reconnect_failed")) { endCall() } }