From 85926f4ec04a2d39b4374b548e32fab3447cca9a Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 3 Jun 2026 23:51:54 -0400 Subject: [PATCH] fix(android): keep service alive when UPnP is playing -- override playWhenReady --- .../minstrel/player/MinstrelForwardingPlayer.kt | 8 ++++++++ .../fabledsword/minstrel/player/MinstrelPlayerService.kt | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) 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 cc2e74ae..b4e7a327 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 @@ -218,6 +218,14 @@ class MinstrelForwardingPlayer( override fun getPlaybackState(): Int = if (isRemote()) Player.STATE_READY else super.getPlaybackState() + // Mirror remote state so any consumer that gates on playWhenReady -- + // notably MediaSessionService's foreground-keepalive checks and our own + // onTaskRemoved -- sees the remote renderer as the source of truth. + // Without this, swiping the app away with Sonos playing would stop the + // service, kill the poll loop, and leave Sonos orphaned. + override fun getPlayWhenReady(): Boolean = + if (isRemote()) remoteState.isPlaying else super.getPlayWhenReady() + override fun release() { pollJob?.cancel() scope.cancel() diff --git a/android/app/src/main/java/com/fabledsword/minstrel/player/MinstrelPlayerService.kt b/android/app/src/main/java/com/fabledsword/minstrel/player/MinstrelPlayerService.kt index 8c867142..7458a730 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/player/MinstrelPlayerService.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/player/MinstrelPlayerService.kt @@ -176,7 +176,11 @@ class MinstrelPlayerService : MediaSessionService() { override fun onTaskRemoved(rootIntent: Intent?) { val player = mediaSession?.player ?: return super.onTaskRemoved(rootIntent) - val activelyPlaying = player.playWhenReady && player.playbackState != Player.STATE_ENDED + // player.isPlaying is overridden on MinstrelForwardingPlayer to return + // remoteState.isPlaying while UPnP is active, so a swipe-away with + // Sonos playing keeps the service (and its UPnP poll loop) alive. + val activelyPlaying = player.isPlaying || + (player.playWhenReady && player.playbackState != Player.STATE_ENDED) if (!activelyPlaying) { stopSelf() }