fix(web): Web-Audio-Kontext bei Nutzergeste freischalten (iOS-Chunk-Wiedergabe)
unlockTTS() schaltete bisher nur SpeechSynthesis frei. Der Web-Audio-Kontext für die satzweise Chunk-Wiedergabe (Server-TTS-Modi) wurde erst lazy im WS-Callback erzeugt — auf iOS startet ein so erzeugter AudioContext "suspended" und resume() außerhalb einer Geste wird abgelehnt -> stumme/blockierte Chunk-Wiedergabe. Fix: unlockTTS() legt den AudioContext jetzt in der Nutzergeste an, ruft resume() und spielt einen 1-Sample-Stille-Buffer (Standard-iOS-Unlock). Beide Freischaltungen (Geräte-TTS + Web-Audio) laufen unabhängig, auch wenn SpeechSynthesis fehlt. Verifiziert (Desktop-Chrome): Kontext wird in der Geste erzeugt, ist "running" und der Stille-Buffer läuft, bevor der erste Chunk eintrifft; Chunk-Wiedergabe weiterhin gapless. Echtes iOS Safari hier nicht testbar. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
5c3deba5ac
commit
e4f0ea7199
1 changed files with 21 additions and 3 deletions
|
|
@ -151,11 +151,29 @@ function deviceSpeakBtn(text, lang, btn) {
|
|||
speechSynthesis.speak(u);
|
||||
}
|
||||
|
||||
// iOS: speechSynthesis darf nur nach einer Nutzergeste starten -> beim ersten Tap freischalten.
|
||||
// iOS: sowohl SpeechSynthesis (Geräte-TTS) als auch der Web-Audio-Kontext (Server-Chunks)
|
||||
// dürfen nur nach einer Nutzergeste starten -> beim ersten Tap beide freischalten.
|
||||
let _ttsUnlocked = false;
|
||||
let _audioUnlocked = false;
|
||||
function unlockTTS() {
|
||||
if (_ttsUnlocked || !TTS_SUPPORTED) return;
|
||||
try { speechSynthesis.speak(new SpeechSynthesisUtterance("")); _ttsUnlocked = true; } catch (e) {}
|
||||
// Geräte-TTS per Leer-Utterance freischalten.
|
||||
if (TTS_SUPPORTED && !_ttsUnlocked) {
|
||||
try { speechSynthesis.speak(new SpeechSynthesisUtterance("")); _ttsUnlocked = true; } catch (e) {}
|
||||
}
|
||||
// Web-Audio-Kontext jetzt (in der Geste) anlegen + per Stille-Buffer aufwecken, damit
|
||||
// die satzweise Chunk-Wiedergabe in den Server-Modi auch auf iOS läuft (sonst bleibt ein
|
||||
// erst im WS-Callback erzeugter AudioContext dort "suspended").
|
||||
if (!_audioUnlocked) {
|
||||
try {
|
||||
audioCtx = audioCtx || new (window.AudioContext || window.webkitAudioContext)();
|
||||
if (audioCtx.state === "suspended") audioCtx.resume();
|
||||
const src = audioCtx.createBufferSource();
|
||||
src.buffer = audioCtx.createBuffer(1, 1, 22050); // 1 Sample Stille
|
||||
src.connect(audioCtx.destination);
|
||||
src.start(0);
|
||||
_audioUnlocked = true;
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
const PLAYBACK_KEY = "va-playback"; // geräte-lokal: "device" wenn Geräte-TTS gewählt
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue