From 0f05890d1203f7aaa50b7431696d3046fdffc289 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Thu, 26 Feb 2026 15:45:27 +0800 Subject: [PATCH] fix: iOS TTS unlock on user gesture, use \r for terminal Enter --- dashboard/frontend/src/lib/voice.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dashboard/frontend/src/lib/voice.js b/dashboard/frontend/src/lib/voice.js index e0752e0..bdcbdcb 100644 --- a/dashboard/frontend/src/lib/voice.js +++ b/dashboard/frontend/src/lib/voice.js @@ -16,6 +16,7 @@ export class VoiceSession { this._debounce = null; this._recog = null; this._onWriteDispose = null; + this._ttsUnlocked = false; } get lang() { return LANGS[this.langIdx]; } @@ -68,9 +69,17 @@ export class VoiceSession { toggleTts() { this.ttsEnabled = !this.ttsEnabled; if (!this.ttsEnabled) { speechSynthesis.cancel(); this.speaking = false; } - if (this.ttsEnabled && this.term) { - const buf = this.term.buffer.active; - this._lastLine = buf.baseY + buf.cursorY; + if (this.ttsEnabled) { + // iOS Safari requires first speak() in a user gesture to unlock audio + if (!this._ttsUnlocked) { + const u = new SpeechSynthesisUtterance(""); + speechSynthesis.speak(u); + this._ttsUnlocked = true; + } + if (this.term) { + const buf = this.term.buffer.active; + this._lastLine = buf.baseY + buf.cursorY; + } } this._notify(); } @@ -93,7 +102,7 @@ export class VoiceSession { if (e.results[i].isFinal) { const text = e.results[i][0].transcript.trim(); if (text && this.ws?.readyState === 1) { - this.ws.send(new TextEncoder().encode(text + "\n")); + this.ws.send(new TextEncoder().encode(text + "\r")); } } }