From 659554df0e8a028700d79f9d220818c1c940a1e6 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 15 Jul 2026 19:11:40 -0400 Subject: [PATCH] =?UTF-8?q?fix(player):=20route=20notification=20next/prev?= =?UTF-8?q?=20to=20Sonos=20while=20casting=20=E2=80=94=20#171?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device verification of v2026.07.15 found the notification/lock-screen next+prev buttons dead during a UPnP cast (play/pause worked). Root cause: the system media controls issue COMMAND_SEEK_TO_NEXT / COMMAND_SEEK_TO_PREVIOUS -> Player.seekToNext()/seekToPrevious(), which are DISTINCT from the seekToNextMediaItem()/seekToPreviousMediaItem() the in-app buttons call and which MinstrelForwardingPlayer already routes to Sonos. seekToNext/Previous were un-overridden, so ForwardingPlayer forwarded them to the paused local delegate — nudging its cursor, which the identity poll then re-synced back to Sonos, so the buttons read as dead. Override seekToNext()/seekToPrevious() to delegate to the media-item variants (the full Sonos path: optimistic local advance + AVTransport Next/Previous + pending-transport gate) when a UPnP route is engaged; plain local playback keeps the default behaviour. Fixes notification/lock-screen/Auto/Wear skip during a cast. Completes milestone #171 Step 3 (#1606 / #606). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../minstrel/player/MinstrelForwardingPlayer.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/android/app/src/main/java/com/fabledsword/minstrel/player/MinstrelForwardingPlayer.kt b/android/app/src/main/java/com/fabledsword/minstrel/player/MinstrelForwardingPlayer.kt index eb8c52bd..be14cc46 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/player/MinstrelForwardingPlayer.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/player/MinstrelForwardingPlayer.kt @@ -342,6 +342,23 @@ class MinstrelForwardingPlayer( } } + // The system media notification / lock-screen / Android Auto / Wear 'next' + // and 'previous' buttons issue COMMAND_SEEK_TO_NEXT / COMMAND_SEEK_TO_PREVIOUS + // -> Player.seekToNext() / seekToPrevious(), which are DISTINCT from the + // *MediaItem variants the in-app transport buttons call. Un-overridden, the + // base ForwardingPlayer forwards these to the paused local delegate -- so + // the notification next/prev only nudged the local cursor (which the poll + // then re-synced back to Sonos), reading as dead buttons while casting. + // Route them through the same Sonos path as the media-item variants when a + // UPnP route is engaged; plain local playback keeps the default behaviour. + override fun seekToNext() { + if (isRemote() || isLoadingUpnp()) seekToNextMediaItem() else super.seekToNext() + } + + override fun seekToPrevious() { + if (isRemote() || isLoadingUpnp()) seekToPreviousMediaItem() else super.seekToPrevious() + } + override fun getCurrentPosition(): Long = if (isRemote()) remoteState.positionMs else super.getCurrentPosition()