From 6ff2c329b0a401dced5df0f2dbd3c12d85fc5b3c Mon Sep 17 00:00:00 2001 From: Julian Vollmer Date: Mon, 18 May 2026 18:42:08 +0200 Subject: [PATCH] Fix audio on Android Chrome / Mi Browser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - audioCtx.resume() explizit aufrufen (Android suspendiert AudioContext) - ws:// vs wss:// dynamisch je nach Seitenprotokoll - Button zeigt "Verbinde…" bis WebSocket offen ist - onclose Handler setzt Button zurück auf "Ton an" Co-Authored-By: Claude Sonnet 4.6 --- app/templates/live.html | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/app/templates/live.html b/app/templates/live.html index 42e8589..1e2896a 100644 --- a/app/templates/live.html +++ b/app/templates/live.html @@ -206,21 +206,35 @@ btn.textContent = "🔇 Ton an"; audioOn = false; } else { + btn.textContent = "⏳ Verbinde…"; startAudio(); - btn.textContent = "🔊 Ton aus"; audioOn = true; } } function startAudio() { audioCtx = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: SAMPLE_RATE }); - nextPlayTime = audioCtx.currentTime; - const wsUrl = `ws://${location.host}/audio-ws`; + // Android/Chrome suspendiert AudioContext standardmäßig → explizit resumem + audioCtx.resume().then(() => { + nextPlayTime = audioCtx.currentTime; + connectWs(); + }); + } + + function connectWs() { + // ws:// oder wss:// je nach Seitenprotokoll + const proto = location.protocol === "https:" ? "wss" : "ws"; + const wsUrl = `${proto}://${location.host}/audio-ws`; audioWs = new WebSocket(wsUrl); audioWs.binaryType = "arraybuffer"; + audioWs.onopen = () => { + document.getElementById("audio-btn").textContent = "🔊 Ton aus"; + }; + audioWs.onmessage = (event) => { + if (!audioCtx) return; const pcm16 = new Int16Array(event.data); const buffer = audioCtx.createBuffer(1, pcm16.length, SAMPLE_RATE); const data = buffer.getChannelData(0); @@ -231,13 +245,16 @@ source.buffer = buffer; source.connect(audioCtx.destination); const now = audioCtx.currentTime; - // Kleine Puffer-Queue (~40ms) damit keine Lücken entstehen if (nextPlayTime < now) nextPlayTime = now + 0.04; source.start(nextPlayTime); nextPlayTime += buffer.duration; }; audioWs.onerror = () => stopAudio(); + audioWs.onclose = () => { + if (audioOn) stopAudio(); + document.getElementById("audio-btn").textContent = "🔇 Ton an"; + }; } function stopAudio() {