From 609f618642340c2ac3f845d28724ee0e58ded9bd Mon Sep 17 00:00:00 2001 From: Damontecres Date: Mon, 2 Mar 2026 18:52:06 -0500 Subject: [PATCH] Add media session --- .../wholphin/services/MusicService.kt | 36 +++++++++++++++++-- .../wholphin/ui/playback/PlaybackViewModel.kt | 3 ++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/MusicService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/MusicService.kt index 983d296e..64efe810 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/MusicService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/MusicService.kt @@ -12,6 +12,7 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.datasource.okhttp.OkHttpDataSource import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.source.DefaultMediaSourceFactory +import androidx.media3.session.MediaSession import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.AudioItem import com.github.damontecres.wholphin.data.model.BaseItem @@ -28,6 +29,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import org.jellyfin.sdk.api.client.ApiClient @@ -69,6 +72,34 @@ class MusicService } } + private val mutex = Mutex() + var mediaSession: MediaSession? = null + private set + + suspend fun start() { + if (mediaSession == null) { + mutex.withLock { + if (mediaSession == null) { + Timber.i("Starting music MediaSession") + mediaSession = MediaSession.Builder(context, player).build() + } + } + } + onMain { player.play() } + } + + suspend fun stop() { + mutex.withLock { + Timber.i("Stopping music") + if (mediaSession == null) { + Timber.w("Stopping but no MediaSession") + } + mediaSession?.release() + mediaSession = null + onMain { player.stop() } + } + } + /** * Fetches instant mix items, replaces the queue, and begins playback */ @@ -100,8 +131,8 @@ class MusicService withContext(Dispatchers.Main) { player.setMediaItems(emptyList()) player.shuffleModeEnabled = shuffled - player.play() } + start() addAllToQueue(items, startIndex) } @@ -110,6 +141,7 @@ class MusicService shuffled: Boolean, ) { Timber.d("setQueue: %s items, shuffled=%s", items.size, shuffled) + start() val mediaItems = items .filter { it.type == BaseItemKind.AUDIO } @@ -118,7 +150,6 @@ class MusicService updateQueueSize() player.setMediaItems(mediaItems) player.shuffleModeEnabled = shuffled - player.play() } } @@ -202,6 +233,7 @@ class MusicService it.copy(queueSize = player.mediaItemCount) } } + start() } suspend fun moveQueue( diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt index 0d23f4bf..505f44ac 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt @@ -42,6 +42,7 @@ import com.github.damontecres.wholphin.preferences.UserPreferences import com.github.damontecres.wholphin.services.DatePlayedService import com.github.damontecres.wholphin.services.DeviceProfileService import com.github.damontecres.wholphin.services.ImageUrlService +import com.github.damontecres.wholphin.services.MusicService import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.PlayerFactory import com.github.damontecres.wholphin.services.PlaylistCreationResult @@ -142,6 +143,7 @@ class PlaybackViewModel private val userPreferencesService: UserPreferencesService, private val imageUrlService: ImageUrlService, private val screensaverService: ScreensaverService, + private val musicService: MusicService, @Assisted private val destination: Destination, ) : ViewModel(), Player.Listener, @@ -270,6 +272,7 @@ class PlaybackViewModel * Initialize from the UI to start playback */ private suspend fun init() { + musicService.stop() nextUp.setValueOnMain(null) this.preferences = userPreferencesService.getCurrent() if (preferences.appPreferences.playbackPreferences.refreshRateSwitching) {