Skip to content

Releases: Kepners/pcnestspeaker-releases

v2.1.1

Choose a tag to compare

@Kepners Kepners released this 12 Jun 16:39

PC Nest Speaker 2.1.1

Same-version maintenance release on top of 2.1.0.

Fixed

  • HTTP PCM drop recovery. Backpressure recovery now tolerates short Cast/Wi-Fi stalls before closing the receiver stream, waits longer for PCM receiver relaunch, and falls back to a full stream reconnect if direct relaunch fails. This targets the Backpressure recovery failed: Execution of start app 4B876246 timed out after 10.0 s failure seen on July 9, 2026.
  • Play while PC is locked. Settings now includes Play while PC is locked, enabled by default. When enabled, locking Windows leaves the active stream running; when disabled, the app stops on lock and reconnects on unlock.
  • Startup and unlock reconnect. Successful speaker, group, and stereo starts are remembered for automatic reconnect on app startup/autoboot; streams stopped by PC lock can reconnect on unlock.
  • App version display. The in-app footer no longer shows stale v2.0.0; it now uses the packaged app version, with v2.1.1 as the fallback.
  • Speakers tab layout corruption. The Low Latency button added in 2.1.0 was crammed into the Wall of Sound row's left control group, widening it and pushing the audio-output pills off the right edge. The button is removed from the Speakers tab; latency is controlled by Settings > Audio > Speed. The Wall of Sound row is no longer clipped.

Unchanged from 2.1.0

  • Fast plain-audio custom receiver path for the lowest-latency Nest route.
  • Google Home stereo pair = true stereo on two Minis via firmware-locked L/R.
  • EQ presets and Speed profiles in Settings > Audio.
  • L/R volume pairing, instant cached speaker list, reconnect-after-unlock, stale-FFmpeg init-segment fix.

Release State

  • Public release page: https://github.com/Kepners/pcnestspeaker-releases/releases/tag/v2.1.1.
  • Website installer route: https://www.pcnestspeaker.app/download/windows/setup redirects to the GitHub latest/download/PC-Nest-Speaker-Setup.exe asset, so it serves the current release.
  • Setup EXE: 218924773 bytes, SHA256 715B783CD8B8B1D47EE0083F7F1ED59C86167EF30E4258AB5F45EF1C49901F19.
  • Portable EXE: 215743444 bytes, SHA256 B96008D9CF461C5119E096DDE169EDF9DC8CD106F6C699106E8BE539E98CBA9E.
  • Build commit: 950c0da.
  • Local build verification 2026-07-09: packaged app.asar contains the dynamic get-app-version path, v2.1.1 footer fallback, and no stale v2.0.0 - A product footer string.
  • Verified live 2026-07-09: website route download-back returned 218924773 bytes with SHA256 715B783CD8B8B1D47EE0083F7F1ED59C86167EF30E4258AB5F45EF1C49901F19.
  • Caveat: this same-version reissue has not had a clean-machine fresh-install test.

v2.1.0

Choose a tag to compare

@Kepners Kepners released this 12 Jun 16:23

PC Nest Speaker 2.1.0

Low-latency fast-receiver path restored and hardened, true stereo guidance, and new audio controls.

Highlights

  • Fast receiver restored. The custom audio receiver (4B876246) was re-broken by an MSE-first regression; it now uses the proven plain-<audio> path again — ~0.5 s startup on Nest Mini, the fastest reliable path.
  • True stereo on two Minis = Google Home stereo pair. Pair the two speakers in the Google Home app; the pair shows as one device and Google's firmware sample-locks Left/Right. Cast to the pair with the fast receiver for phase-perfect stereo at low latency. (Driving two separate speakers with the same stream causes audible comb-filter "phasing" and is not a stereo solution — see BRAIN.md principle 12.)
  • ⚡ Low Latency button on the Speakers tab — one tap for the snappiest pause/play (best for video / YouTube).
  • Speed setting (Fastest / Fast / Balanced / Stable) and EQ presets (Flat / Bass Boost / Loud & Clear / Voice / Warm) tuned for small speakers — now in Settings → Audio.
  • L/R volume pairing — the volume slider sets both fast-pair speakers to the same level.
  • Faster startup — the speaker list now appears instantly from a cache while a fresh scan refreshes in the background (was a 7–11 s wait).
  • Reliability fixes: a stale-FFmpeg race that corrupted the stream header (and caused silent re-pairs) is fixed; the disruptive auto re-sync that chimed and stopped music is removed; reconnect-after-unlock restores the fast pair.

Notes

  • Env-gated latency diagnostics remain off by default.
  • The experimental per-member group fast path stays fenced behind PCNEST_GROUP_FAST_CUSTOM=1; the recommended dual-Mini stereo path is a Google Home stereo pair.

Release State

  • Public release page: https://github.com/Kepners/pcnestspeaker-releases/releases/tag/v2.1.0.
  • Website installer route: https://www.pcnestspeaker.app/download/windows/setup (302-redirects to the GitHub latest/download/PC-Nest-Speaker-Setup.exe asset, so it always serves the current release).

v2.0.0

Choose a tag to compare

@Kepners Kepners released this 18 May 18:09

PC Nest Speaker 2.0.0 - group audio baseline

Version 2.0.0 makes the proven Cast Audio Group path the default and ships the warm PC Nest Speaker colour system.

Highlights

  • Cast Audio Groups now use the Default Media Receiver on the group itself, so the group leader opens one WebM/Opus HTTP stream and Google Cast handles native member sync.
  • WebM/Opus HTTP audio defaults to 320k at 48 kHz stereo.
  • Reissued build includes Stream Monitor wiring for the v2 HTTP WebM/Opus path: bitrate, data sent, connection state, and visualizer activity now come from actual bytes written to connected Cast clients.
  • A subtle 1.05 signal lift is applied by default for a brighter perceived sound without changing the Windows volume model.
  • The experimental per-speaker group receiver path is disabled by default and remains behind PCNEST_GROUP_FAST_CUSTOM=1.
  • The app UI keeps the existing PC Nest Speaker logo treatment and applies the warm cream, pink, green, and ink palette.
  • Footer and package metadata now use v2.0.0 and Kepnersen on X.com.

Trial and licensing

  • The 1-hour streaming trial remains in place.
  • Trial state is still stored in encrypted, signed local usage data.
  • Licence keys remain XXXX-XXXX-XXXX-XXXX uppercase hex keys.
  • Licence activation still validates against https://www.pcnestspeaker.app/api/validate-license.
  • A valid licence still bypasses trial expiry.

Customer build contents

The Windows release build is expected to include:

  • FFmpeg
  • MediaMTX
  • cast-helper.exe
  • cast-daemon.exe
  • audioctl.exe
  • SoundVolumeView
  • VB-Cable driver files
  • Equalizer APO installer
  • installer diagnostic helpers

Verification performed

  • Renderer JavaScript syntax check passed.
  • Main-process JavaScript syntax check passed.
  • Usage tracker syntax check passed.
  • Preload JavaScript syntax check passed.
  • Static release-gate checks passed for 3600-second trial duration, packaged trial blocking, licence activation, production licence API URL, preload licence IPC, and renderer licence UI.
  • Full Windows build completed for installer and portable artifacts.
  • Packaged app.asar was checked for the colour-only UI, v2 footer, one-hour trial constants, and licence API wiring.
  • Reissued packaged app.asar was checked for the HTTP Stream Monitor stats wiring.
  • Unpacked build resources were checked for FFmpeg, MediaMTX, Python cast helpers, audioctl, SoundVolumeView, VB-Cable files, Equalizer APO, and installer tools.
  • User clean-install test result accepted as release gate: loud, fast, and reporting 2.0.

Published release

  • Published on 2026-05-18 as v2.0.0.
  • Public release page: https://github.com/Kepners/pcnestspeaker-releases/releases/tag/v2.0.0.
  • Website installer route: https://www.pcnestspeaker.app/download/windows/setup.
  • Browser download filename: PC-Nest-Speaker-Setup-2.0.0.exe.
  • Setup EXE: 218924631 bytes, SHA256 57E077551916639D3E9C02100E5C0303C76364915FCA6FFDE5B7BA8967138E28.
  • Portable EXE: 215743266 bytes, SHA256 6C7FBCA9A7B5DC281C3119E2B89C6B24ECE89D091ED978AC3E4D2AAB94C98B64.
  • Live route proof after Caddy reload: HTTP 200, Content-Length: 218924631, Content-Disposition: attachment; filename="PC-Nest-Speaker-Setup-2.0.0.exe".
  • Full public-route download hash matched the local setup EXE hash.

v1.5.9 — group L/R sync fix

Choose a tag to compare

@Kepners Kepners released this 11 May 13:38

PC Nest Speaker 1.5.9

Fixes the long-standing L/R sync drift on Cast Audio Groups ("right speaker is faster than left" by ~2 s).

What was wrong

Pre-1.5.9 group flow: launch our custom Audio Receiver 4B876246 on each group member individually, send each the same WebM/Opus URL, and let each <audio> element pull the stream independently. Each Mini's <audio> element pre-rolled at its own pace → the playheads drifted apart over seconds.

The architectural reason was correct in the source comment: "Cast Groups can't run custom receivers — only individual devices can." So we routed around groups entirely and treated members as two independent sinks. Functionally it played audio on both, but the platform's sync mechanism never engaged.

What 1.5.9 changes

For Cast Audio Groups, route through the Default Media Receiver (CC1AD845) which can run on a group, and let the group's leader Mini handle native L/R fan-out:

  • Start the WebM/Opus HTTP audio server on :8766/audio.webm (unchanged)
  • Cast that URL to the group itself, not its members, via pychromecast.media_controller.play_media(url, "audio/webm; codecs=\"opus\"", stream_type=LIVE)
  • The group's leader Mini fetches the URL once and broadcasts decoded audio to all members through Cast Audio's internal sync protocol — phase-aligned playout

Single Minis (non-group) continue to use the custom 4B876246 Audio Receiver path (it's working and gives us pcm-status diagnostics we still want for individual devices).

Trade-offs

Single Mini path (unchanged) Group path (new in 1.5.9)
Receiver Custom Audio Receiver 4B876246 Default Media Receiver CC1AD845
Latency ~1 s ~1–1.5 s (DMR has its own jitter buffer; we'll measure)
L/R sync N/A Native, phase-aligned
Force-relaunch on cast yes no (DMR cycles naturally)
pcm-status diagnostics back to PC yes no
Pause/resume custom IPC standard Cast media controls

If group-mode latency turns out worse than the per-member approach, we'll need a different fix — but that's a real measurement we can't make until the L/R drift is gone.

Files changed

  • src/main/electron-main.js — group path in the streaming dispatcher
  • package.json — version bump

What you'll see in the log

[Group] "Study group" → DMR cast (native L/R sync via group leader)
[Group] Capture device: CABLE Output (...)
[AudioHttp] HTTP audio server listening on http://0.0.0.0:8766/audio.webm
[Group] HTTP server: http://192.168.50.49:8766/audio.webm
[Group] Casting URL to "Study group" via DMR…
[Group] ✓ "Study group" playing — leader handles L/R sync natively

Compared to 1.5.8 which showed [PCM] Launching second group member "Right speaker" and two separate receiver-status streams.

Confirmed unchanged from 1.5.8

  • Plain <audio src=> path on individual Minis
  • WebM/Opus 192k VBR encoding, 20 ms cluster size (1.5.3 tuning)
  • Volume sync to all targets at fire-time (1.5.2 fix)
  • Receiver page cache-bust meta tags (1.5.8)
  • TV/Shield WebRTC + HLS paths

Known follow-ups

  • v1.5.10: Pause/resume snappier — keep <audio> element alive on pause instead of tearing down the HTTP connection (saves ~1 s on resume on individual Minis). DMR group path already has standard pause/resume primitives.
  • v1.5.11: Discovery 7.6 s → ~3 s — parallelise group-member resolution.

v1.5.8 — audio-restore hotfix (disable MSE, cache-bust receiver)

Choose a tag to compare

@Kepners Kepners released this 11 May 15:16

PC Nest Speaker 1.5.8 — audio-restore hotfix

Receiver-only change. MSE attempt is disabled. The dispatcher routes straight to the plain <audio src=> path that has worked since 1.5.0.

Why

Real-device testing of 1.5.6 and 1.5.7 on Nest Mini showed the receiver hanging forever at mse-fetch-start with no fallback ever firing — even after the 1.5.7 watchdogs were added. Most likely cause is the Cast Audio Chromium runtime caching the old (no-watchdog) receiver HTML despite force_relaunch, or the runtime not honoring setTimeout/AbortController.abort() during a hung fetch(). Either way, the user got no audio.

1.5.8 is purely about restoring playback. No latency improvement claims. Latency on 1.5.8 ≈ 1.5.5.

What's still in the code

connectHttpPcmMse() stays in receiver-audio.html for now. The dispatcher no longer calls it — it's unreachable. Will revisit once the research agent reports back on:

  1. Whether XMLHttpRequest + responseType="arraybuffer" + onprogress works for incremental chunk delivery on Cast Audio (where fetch().body.getReader() doesn't), or
  2. Whether to pivot to the owntone-server pattern — Google's built-in mirroring receiver 85CDB22F + Cast RTP / Opus / targetDelay=400. That's the only open-source path proven to hit ~400 ms total latency on Cast Audio, but it's a 1–2 week transport rewrite.

If audio is still dead after upgrading

The Cast Audio runtime caches receiver HTML (HTTP Cache-Control: max-age=600 from GitHub Pages). To force a fresh fetch:

  1. Open the Google Home app, find the Nest Mini, hold the icon → "Restart". Or unplug it for 10 seconds.
  2. Cast again from PC Nest Speaker.
  3. The fresh receiver load will pick up the 1.5.8 receiver code.

Files changed

  • pcnestspeaker-receiver/receiver-audio.html — dispatcher routes straight to <audio> path
  • package.json — version bump

v1.5.7 — hotfix: guarantee MSE fallback (1.5.6 silent freeze)

Choose a tag to compare

@Kepners Kepners released this 11 May 15:15

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:

  1. Inner — race fetch() against a 2.5 s timeout that calls pcmAbort.abort() and rejects.
  2. Outer — master watchdog wraps the whole MSE attempt at 4 s. Even if reader.read(), appendBuffer(), or sourceopen were the hanging step instead of fetch(), 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 watchdog
  • package.json — version bump

Desktop binaries unchanged from 1.5.6 functionally; rebuild for version-string parity.

v1.5.6 — receiver MSE+SourceBuffer (live-edge seek)

Choose a tag to compare

@Kepners Kepners released this 11 May 15:14

PC Nest Speaker 1.5.6

The receiver is the change. Desktop bytes are unchanged from 1.5.5 except the version string — the work all lives in receiver-audio.html on GitHub Pages, which the Cast SDK reloads on every cast (force-relaunch from 1.5.0 onwards).

What changed — receiver-side

MSE + SourceBuffer path (preferred, with <audio> fallback)

Problem. Plain <audio src=stream> on Cast Audio runs an opaque internal jitter buffer we can't read or write. Steady-state latency floored at ~1–1.5 s and currentTime writes against a live HTTP-chunked source are likely silent no-ops (per MDN, and confirmed by absence of a seek-probe in v1.5.4/1.5.5 logs because we never had a chance to fire one).

Fix. New connectHttpPcmMse() is now the preferred path:

  • MediaSource + addSourceBuffer('audio/webm; codecs="opus"') with mode='sequence'.
  • fetch().body.getReader() pumps WebM clusters into the SourceBuffer.
  • A 250 ms drift loop calls sb.remove(0, currentTime - 0.5s) to trim history and audio.fastSeek(buffered.end - 0.2s) to push the playhead toward the live edge when we lag.
  • One-shot mse-seek-probe reports back whether the seek inside the MSE buffer actually moves the playhead.

Watchdog + automatic fallback

Cast Audio Chromium has historically had fetch().body.getReader() stalls (the existing CLAUDE.md notes this). 1.5.6's MSE path arms a 3.5 s first-byte watchdog. If no bytes arrive — or any of MediaSource.isTypeSupported, sourceopen, addSourceBuffer, fetch, or appendBuffer fail — the receiver tears down MSE and falls through to the plain <audio src> path that's been working since 1.5.0. So this is strictly additive: best case we cut 300–700 ms off latency, worst case we land on the same path as 1.5.5.

Why this approach (research summary)

Inspired by:

  • shaka-player #9872 — production live SourceBuffer.remove() + seek-to-live pattern
  • w3c/media-source #291 — documents the seekable window after remove()
  • owntone-server cast.c — the only open-source path proven to hit ~400 ms total latency on Cast Audio. They use Google's built-in mirroring receiver 85CDB22F with Cast RTP / Opus / targetDelay=400. If MSE doesn't crack it, that's where 1.5.7 goes — but RTP is a 1–2 week rewrite, so we test cheaper options first.

What you'll see in the desktop log

Where 1.5.5 only emitted audio-src-set / audio-loadedmetadata / audio-canplay / audio-playing, 1.5.6 will additionally emit (when MSE works):

mse-attempt
mse-src-set
mse-sourceopen
mse-sb-added
mse-fetch-headers
mse-first-byte
mse-canplay
mse-playing
mse-seek-probe { seek_works: true|false, ... }   ← the answer we've been waiting for
mse-drift-resync / mse-drift-catchup              ← drift management firing

If MSE fails for any reason you'll see mse-fallback-to-audio reason=... followed by the same audio-* events as 1.5.5.

Files changed

  • pcnestspeaker-receiver/receiver-audio.htmlconnectHttpPcmMse() + dispatcher + capabilities probe extended with mse_isTypeSupported_webm_opus
  • package.json — version bump

Desktop binaries are unchanged from 1.5.5 functionally; rebuilding only so the version string and "About" dialog match the receiver.

v1.5.5 — discovery dispatch hotfix (1.5.4 was a no-op)

Choose a tag to compare

@Kepners Kepners released this 11 May 15:14

PC Nest Speaker 1.5.5

Hotfix for 1.5.4 — the discovery speedup didn't actually take effect.

What was wrong in 1.5.4

1.5.4 changed discover_speakers(timeout=) from 5s default to 3s default, but the CLI entry point at the bottom of cast-helper.py had its own hardcoded fallback:

timeout = int(sys.argv[2]) if len(sys.argv) > 2 else 5

electron-main.js calls runPython(['discover']) with no timeout argument, so the CLI dispatcher always fell through to 5, never reaching the function default. Net effect: the documented 5s→3s change in 1.5.4 was a no-op. Logs in 1.5.4 still printed Scanning network (timeout: 5s).

What 1.5.5 does

  • CLI dispatcher default 53 (matches function default).
  • That's it. No other changes.

Confirming the fix

The discovery log line should now read Scanning network (timeout: 3s) and "Slow discovery" warnings should drop from ~7.6s into the ~5s range.

Everything else from 1.5.4 (receiver seek-probe + fastSeek(), group_cc.wait 5→3s) is unchanged and was already correct in the live receiver — the v1.5.4 release just didn't pull the cold-start savings the desktop side promised.

Files changed

  • src/main/cast-helper.py — CLI dispatch default
  • package.json — version bump

v1.5.4 — pairing speed + seek-probe diagnostic

Choose a tag to compare

@Kepners Kepners released this 11 May 15:13

PC Nest Speaker 1.5.4

Pairing-speed pass + a receiver-side diagnostic to confirm whether Chromium on Cast Audio actually honors live-stream seeks.

What changed

Desktop — cast-helper.py (pairing speed)

Knob 1.5.3 1.5.4 Effect
discover_speakers(timeout=) 5 s 3 s mDNS responses arrive in 1–2 s on a healthy LAN; the extra 2 s of "be safe" was a flat tax on every cold cast
group_cc.wait(timeout=) 5 s 3 s Group control sockets open in well under 1 s; reduces group-resolve stage

Net: ~2–4 s shaved off pairing in the common case. If a slow device (Shield, distant Mini) misses the window, Refresh is one click.

Receiver — receiver-audio.html (seek-probe + fastSeek)

Why this is here: prior to 1.5.4 the drift management (TARGET_LAG / SOFT_LAG / HARD_LAG, see 1.5.3 notes) writes to audio.currentTime and audio.playbackRate to keep the receiver close to the live edge. Per MDN, Chromium-family browsers may treat live HTTP streams as non-seekable, in which case those writes are silent no-ops and the entire drift envelope is fiction.

1.5.4 adds:

  • A one-shot seek-probe the first time lag exceeds 0.5 s. It records seekable.start/end, buffered.end, the seek target, the seek method (fastSeek or currentTime), and currentTime 100 ms later. The result is reported back to the desktop over the Cast custom namespace as pcm-status: seek-probe { … } so we can read the actual behavior on real Nest hardware, not assume.
  • audio.fastSeek() is now used in the drift hard-correction path when available — it's the documented fast path for non-seekable / live media in WHATWG, where regular currentTime writes can be ignored.

If the probe shows seek_works: false, the latency floor is structural — bury the drift code or replace it with a network-level catch-up. If seek_works: true, current code is correct and the floor is buffer-related (cluster size, decoder lookahead).

Files changed

  • src/main/cast-helper.py — discovery + group_cc timeout reductions
  • pcnestspeaker-receiver/receiver-audio.html — seek-probe + fastSeek (already live on GitHub Pages)
  • package.json — version bump

Confirmed unchanged from 1.5.3

  • 192 kbps VBR Opus with -application audio
  • 10 ms frame_duration, 20 ms cluster_time_limit
  • Volume fan-out to all group members
  • WebM init segment captured + prepended for late-joining clients
  • Force-relaunch of receiver page on every cast

Sources used

PC Nest Speaker 1.5.3 — responsive mode (4-knob latency tighten)

Choose a tag to compare

@Kepners Kepners released this 11 May 15:12

PC Nest Speaker 1.5.3

"Responsive mode" — coordinated 4-knob latency tighten across server and receiver.

What changed

Server (http-pcm-server.js)

Knob 1.5.2 1.5.3 Effect
-frame_duration 20 ms 10 ms Halves Opus encoder lookahead (~10 ms latency). Per-frame overhead grows slightly; encoding efficiency at 192 k VBR drops ~3-5% — not perceptually audible
-cluster_time_limit 40 ms 20 ms WebM clusters now carry 2 × 10 ms frames instead of 2 × 20 ms. Receiver sees fresh data twice as often

Receiver (receiver-audio.html)

Knob 1.5.2 1.5.3 Effect
TARGET_LAG 0.30 s 0.18 s Direct subtract from steady-state pause/resume latency
SOFT_LAG 0.80 s 0.50 s playbackRate = 1.05 engages earlier — drift corrected before audible
HARD_LAG 1.50 s 0.90 s Hard-seek to live edge fires sooner

Estimated total impact

~150–700 ms reduction on a typical pause/resume cycle, depending on how much drift had accumulated.

Trade-off — when 1.5.3 might NOT be the right choice

1.5.3 is tuned for clean home LAN. On a noisy Wi-Fi (interference, contention, distant access point) the smaller TARGET_LAG (180 ms) leaves less headroom for jitter — you'll hear more micro-glitches as drift management hard-seeks more often.

If 1.5.3 sounds glitchy where 1.5.2 was clean, it's a network problem, not a build regression. Tightening the envelope made us notice it. Two options if that happens:

  • Stay on v1.5.2 for noisy networks
  • Future: expose TARGET_LAG / HARD_LAG as a setting so users can pick "responsive" vs "stable" themselves

Confirmed unchanged from 1.5.1/1.5.2

  • Audio quality bitrate: 192 kbps VBR with -application audio (music-tuned)
  • Volume sync fan-out across all group members (1.5.2 fix)
  • Force-relaunch of receiver page on every cast (so new receiver code lands)
  • WebM init segment captured + prepended to each new client (the fix without which MSE/<audio> silently parks data)

Files changed

  • src/main/http-pcm-server.js — FFmpeg args (frame_duration, cluster_time_limit)
  • pcnestspeaker-receiver/receiver-audio.html — drift management constants
  • package.json — version bump

Sources used in tuning