diff --git a/android/src/services/audio.ts b/android/src/services/audio.ts index 6a84bde..e7b72f4 100644 --- a/android/src/services/audio.ts +++ b/android/src/services/audio.ts @@ -1731,11 +1731,39 @@ class AudioService { this._stoppedMessageId = activeMsgId; console.log('[Audio] Antwort %s als gestoppt markiert', activeMsgId); } - this.stopPlayback(); + // NUR die hoerbare Wiedergabe stoppen — Cache-Buffer behalten, damit die + // Nachricht spaeter ueber das Lautsprecher-Symbol nachgehoert werden kann. + this._silenceAudibleOutput(); } } isMuted(): boolean { return this._muted; } + /** Mund-Button: laufendes Vorlesen SOFORT verstummen lassen, aber den + * PCM-Cache NICHT verwerfen (der Stream cached zu Ende → Nachhoeren via + * Lautsprecher-Symbol bleibt moeglich). Unterschied zu stopPlayback(): + * - stopt den AudioTrack IMMER (auch wenn pcmStreamActive schon false ist, + * weil der Stream fertig empfangen wurde aber der AudioTrack seinen Buffer + * noch sekundenlang ausspielt — genau da war der Mund-Button wirkungslos), + * - laesst pcmBuffer/pcmMessageId/pcmStreamActive stehen (Cache laeuft weiter). */ + private _silenceAudibleOutput(): void { + console.log('[Audio] _silenceAudibleOutput: AudioTrack+WAV stoppen, Cache behalten'); + this.audioQueue = []; + this.isPlaying = false; + if (this.currentSound) { + try { this.currentSound.stop(); this.currentSound.release(); } catch {} + this.currentSound = null; + } + if (this.resumeSound) { + try { this.resumeSound.stop(); this.resumeSound.release(); } catch {} + this.resumeSound = null; + } + // AudioTrack IMMER hart stoppen (idempotent) — auch im Drain-Fall. + PcmStreamPlayer?.stop().catch(() => {}); + stopBackgroundAudio().catch(() => {}); + this._cancelDeferredFocusRelease(); + AudioFocus?.release().catch(() => {}); + } + /** Laufende Wiedergabe stoppen + Queue leeren */ stopPlayback(): void { // Idempotent: wenn nichts mehr aktiv ist, NICHT noch einen Focus-Release/