v1.5.7 — hotfix: guarantee MSE fallback (1.5.6 silent freeze)
PC Nest Speaker 1.5.7 — hotfix
1.5.6 introduced a regression: on Cast Audio, await fetch() can hang forever without ever resolving headers (the historical Cast Audio Chromium quirk noted in CLAUDE.md as "request opens, headers never resolve to JS"). The MSE path's first-byte watchdog was armed after fetch() returned, so when fetch hung the watchdog never armed, the function awaited indefinitely, the caller's catch never ran, and the <audio> fallback never fired → user got no audio at all.
Server-side log confirmed bytes were flowing on the socket (453 B init segment sent, bitrate climbed to ~228 kbps), but the JS fetch() Promise never resolved with the response object.
What 1.5.7 changes (receiver only)
Two layers of watchdog so the fallback to plain <audio> always fires:
- Inner — race
fetch()against a 2.5 s timeout that callspcmAbort.abort()and rejects. - Outer — master watchdog wraps the whole MSE attempt at 4 s. Even if
reader.read(),appendBuffer(), orsourceopenwere the hanging step instead offetch(), the master watchdog still trips fallback.
Even on a Cast Audio runtime where AbortController.abort() is itself broken, Promise.race rejects on schedule, the caller's catch block runs, disconnectHttpPcm() cleans MSE state, and the plain <audio> path takes over. Audio is restored within ~5 s of pressing Play in the worst case, vs. silence forever in 1.5.6.
What you'll see in the log
If MSE works on this runtime (best case):
mse-fetch-start → mse-fetch-headers → mse-first-byte → mse-canplay → mse-playing
mse-seek-probe { seek_works: true|false }
If MSE hangs (the 1.5.6 silent-failure case, now non-silent):
mse-fetch-start
mse-fallback-to-audio reason=fetch watchdog 2500ms ← NEW
audio-canplay → audio-playing ← same path as 1.5.5, audio plays
The reason= field tells us whether fetch() hangs, the master watchdog tripped, or some other step is the blocker. That's the diagnostic signal that replaces the silent freeze.
Plan B if MSE is fundamentally broken on Cast Audio
Replace fetch().body.getReader() with XMLHttpRequest + progress events. XHR2 has been on Chromium longer and the Cast Audio runtime is more likely to honor it. Will only attempt this if 1.5.7 logs confirm fetch() is the specific blocker (not the master watchdog tripping on something later).
Files changed
pcnestspeaker-receiver/receiver-audio.html— fetch race + master watchdogpackage.json— version bump
Desktop binaries unchanged from 1.5.6 functionally; rebuild for version-string parity.