Sonos queue resync + cold-start prefetcher gate #83
Reference in New Issue
Block a user
Delete Branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Three commits on dev since the v2026.06.04 hotfix re-cut. All caught on-device.
80179343— Sonos queue resync on playlist switch (full reload)Tapping a different playlist while Sonos was the active route updated the player view but Sonos kept playing the OLD queue.
PlayerController.setQueuereplaced the local ExoPlayer queue and calledplay(), which forwarded SOAP Play to Sonos — but Sonos's native queue (loaded once at route selection viaremoveAllTracks + AddURIToQueue + SetAVTransportURI) was never refreshed.MinstrelForwardingPlayer.setMediaItems(all 3 overloads) clearsholder.active+ sets target synchronously so the immediately-followingplay()drops viaisLoadingUpnp().OutputPickerControllerobservesuiState.queueidentity changes and runs aloadQueueOnSonosreload when the joined-ids key shifts.e7d7cb24— Incremental Sonos diff for playNext + radio-appendThe first commit re-loaded Sonos's full queue on every uiState.queue identity change. Correct for playlist-switch but disruptive for in-queue mutations —
playNextand radio-append would restart the currently-playing track on Sonos becauseremoveAllTracks + AddURIToQueue x N + SetAVTransportURIre-anchors the transport.Now the resync runs a longest-common-prefix / suffix diff first. When the current Sonos track lies in the preserved prefix, applies the minimum-incremental SOAP operations:
RemoveTrackRangeFromQueueon the removed middle +AddURIToQueueat the same insertion point. Sonos keeps playing the current track and the new entries land in place. Falls back to the full reload only when the diff would orphan playback (the playlist-switch case from the prior commit).Adds
AVTransportClient.removeTrackRangeFromQueue(Sonos-specific,UpdateID=0skips the queue-version check).Cases covered:
playNextinsert → 1AddURIToQueueat slotcurrentIdx+2RemoveTrackRangeFromQueuefor old tail + NAddURIToQueuefor new tracks9a31955f— Gate AudioPrefetcher on isPlayingOn-device logcat showed cold-start playback taking ~25s on fresh install.
AudioPrefetcherwas kicking off N concurrentCacheWriterjobs the instantsetQueueupdateduiState— each a full upcoming-track download over the same OkHttp client as the playbackDataSource. Five-way bandwidth split plus parallel Coil cover fetches starved the current track until its full body had streamed (~12 MB at ~1 MB/s under contention).Now
reconcile()observesuiState.isPlayingand starts upcoming-track prefetches only when the current track is actually playing. Cancellation of out-of-window jobs still always runs so a queue switch or skip frees the pipe immediately, even while paused.Expected cold-start time-to-play: ~25s → ~5-7s on the user's network (single-stream throughput plus one-time TLS/DNS tax).
Test plan
The previous fix re-loaded Sonos's full queue on every uiState.queue identity change -- correct for playlist-switch (full replacement) but disruptive for in-queue mutations: playNext and radio-append would restart the currently-playing track on Sonos because removeAllTracks + AddURIToQueue x N + SetAVTransportURI re-anchors the transport. Now the resync runs a longest-common-prefix / common-suffix diff first. When the current Sonos track lies in the preserved prefix, applies the minimum-incremental SOAP operations -- RemoveTrackRangeFromQueue on the removed middle, AddURIToQueue at the same insertion point -- so Sonos keeps playing the current track and the new entries land in place without interrupting playback. Falls back to the full removeAllTracks reload when the current track is in the removed slice (playlist switch). Adds AVTransportClient.removeTrackRangeFromQueue (Sonos-specific, UpdateID=0 skips the queue-version check). Cases now covered: - Playlist switch -> full reload (current track replaced, prefix=0) - playNext insert -> 1 AddURIToQueue at the right slot - Radio-append -> RemoveTrackRangeFromQueue for old tail + N AddURIToQueue for new tracks at the end