diff --git a/android/src/services/wakeword.ts b/android/src/services/wakeword.ts index 5d32f1f..b9c53e1 100644 --- a/android/src/services/wakeword.ts +++ b/android/src/services/wakeword.ts @@ -390,15 +390,35 @@ class WakeWordService { return true; } - /** Nach ARIA-Antwort (TTS fertig): naechste Aufnahme im Conversation-Window starten */ + /** Nach ARIA-Antwort (TTS fertig): naechste Aufnahme im Conversation-Window starten. + * + * WICHTIG: setTimeout(800ms) kann im Hintergrund (Display aus) verspaetet + * feuern — JS-Thread ist geparkt. Wenn der Timer >2s ueberfaellig ist, + * hat der User offensichtlich die App verlassen und kommt erst spaeter + * wieder — wir oeffnen das Mikro dann NICHT, sondern beenden die + * Konversation. Sonst sieht der User nach dem App-Resume "Mikro plus- + * aufnahme laeuft" obwohl er gar nichts gesagt hat → wirkt wie Phantom- + * Wake-Word. Klassische Doze-Throttling-Falle wie bei wake.detect frueher. */ async resume(): Promise { if (this.state !== 'conversing') return; + const scheduledAt = Date.now(); // Kurze Pause damit TTS-Audio nicht ins Mikrofon geht await new Promise(resolve => setTimeout(resolve, 800)); - if (this.state === 'conversing') { - console.log('[WakeWord] TTS fertig — naechste Aufnahme im Conversation-Window'); - this.wakeCallbacks.forEach(cb => cb()); + if (this.state !== 'conversing') return; + const delay = Date.now() - scheduledAt; + if (delay > 2800) { + // Timer war stark verspaetet — JS-Thread war im Hintergrund geparkt. + // Conversation als beendet behandeln statt das Mikro zu oeffnen. + console.log('[WakeWord] resume(): %dms statt ~800ms — App war im Background. endConversation statt mic-open', delay); + import('./logger').then(m => m.reportAppDebug('wake.resume', + `delayed ${delay}ms (>2800) — endConversation statt mic-open`)).catch(()=>{}); + // Asynchroner Aufruf — endConversation ist async, kein await damit wir + // hier nicht in einem Promise-Chain haengen. + this.endConversation().catch(() => {}); + return; } + console.log('[WakeWord] TTS fertig — naechste Aufnahme im Conversation-Window (delay=%dms)', delay); + this.wakeCallbacks.forEach(cb => cb()); } /** True solange das Ohr aktiv ist (armed ODER conversing). */