Fix audio on Android Chrome / Mi Browser
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
28eb07bcab
commit
6ff2c329b0
|
|
@ -206,21 +206,35 @@
|
||||||
btn.textContent = "🔇 Ton an";
|
btn.textContent = "🔇 Ton an";
|
||||||
audioOn = false;
|
audioOn = false;
|
||||||
} else {
|
} else {
|
||||||
|
btn.textContent = "⏳ Verbinde…";
|
||||||
startAudio();
|
startAudio();
|
||||||
btn.textContent = "🔊 Ton aus";
|
|
||||||
audioOn = true;
|
audioOn = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function startAudio() {
|
function startAudio() {
|
||||||
audioCtx = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: SAMPLE_RATE });
|
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 = new WebSocket(wsUrl);
|
||||||
audioWs.binaryType = "arraybuffer";
|
audioWs.binaryType = "arraybuffer";
|
||||||
|
|
||||||
|
audioWs.onopen = () => {
|
||||||
|
document.getElementById("audio-btn").textContent = "🔊 Ton aus";
|
||||||
|
};
|
||||||
|
|
||||||
audioWs.onmessage = (event) => {
|
audioWs.onmessage = (event) => {
|
||||||
|
if (!audioCtx) return;
|
||||||
const pcm16 = new Int16Array(event.data);
|
const pcm16 = new Int16Array(event.data);
|
||||||
const buffer = audioCtx.createBuffer(1, pcm16.length, SAMPLE_RATE);
|
const buffer = audioCtx.createBuffer(1, pcm16.length, SAMPLE_RATE);
|
||||||
const data = buffer.getChannelData(0);
|
const data = buffer.getChannelData(0);
|
||||||
|
|
@ -231,13 +245,16 @@
|
||||||
source.buffer = buffer;
|
source.buffer = buffer;
|
||||||
source.connect(audioCtx.destination);
|
source.connect(audioCtx.destination);
|
||||||
const now = audioCtx.currentTime;
|
const now = audioCtx.currentTime;
|
||||||
// Kleine Puffer-Queue (~40ms) damit keine Lücken entstehen
|
|
||||||
if (nextPlayTime < now) nextPlayTime = now + 0.04;
|
if (nextPlayTime < now) nextPlayTime = now + 0.04;
|
||||||
source.start(nextPlayTime);
|
source.start(nextPlayTime);
|
||||||
nextPlayTime += buffer.duration;
|
nextPlayTime += buffer.duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
audioWs.onerror = () => stopAudio();
|
audioWs.onerror = () => stopAudio();
|
||||||
|
audioWs.onclose = () => {
|
||||||
|
if (audioOn) stopAudio();
|
||||||
|
document.getElementById("audio-btn").textContent = "🔇 Ton an";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopAudio() {
|
function stopAudio() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue