v1.5.9 — group L/R sync fix
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 dispatcherpackage.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.