From 49740c47cf9478fd6d330951cc8065516b837a1f Mon Sep 17 00:00:00 2001 From: Ray <154766448+damontecres@users.noreply.github.com> Date: Wed, 7 Jan 2026 12:49:43 -0500 Subject: [PATCH] Create media session during playback allowing for external control (#640) ## Description Creates a `MediaSession` during playback which allows for external control such as via smart speakers, Google Home app, etc Note: one limitation is that seeking previous/next items in the playlist isn't supported. This is because Wholphin manages that independent of the `Player`, so additional dev work is needed for this. ### Related issues Closes #622 Might help with #415 --- app/build.gradle.kts | 1 + .../damontecres/wholphin/ui/playback/PlaybackViewModel.kt | 8 ++++++++ gradle/libs.versions.toml | 1 + 3 files changed, 10 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 51d2590f..c83d76a6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -196,6 +196,7 @@ dependencies { implementation(libs.androidx.hilt.work) implementation(libs.androidx.media3.exoplayer) + implementation(libs.androidx.media3.session) implementation(libs.androidx.media3.datasource.okhttp) implementation(libs.androidx.media3.exoplayer.hls) implementation(libs.androidx.media3.ui) 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 064434c4..fa71dc7f 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 @@ -21,6 +21,7 @@ import androidx.media3.exoplayer.DecoderCounters import androidx.media3.exoplayer.DecoderReuseEvaluation import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.analytics.AnalyticsListener +import androidx.media3.session.MediaSession import coil3.imageLoader import coil3.request.ImageRequest import coil3.size.Size @@ -134,6 +135,7 @@ class PlaybackViewModel val player by lazy { playerFactory.createVideoPlayer() } + private val mediaSession: MediaSession internal val mutex = Mutex() val controllerViewState = @@ -177,10 +179,15 @@ class PlaybackViewModel } jobs.forEach { it.cancel() } player.release() + mediaSession.release() } viewModelScope.launch(ExceptionHandler()) { controllerViewState.observe() } player.addListener(this) (player as? ExoPlayer)?.addAnalyticsListener(this) + mediaSession = + MediaSession + .Builder(context, player) + .build() jobs.add(subscribe()) jobs.add(listenForTranscodeReason()) } @@ -1031,6 +1038,7 @@ class PlaybackViewModel Timber.v("release") activityListener?.release() player.release() + mediaSession.release() activityListener = null } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 964fab0d..57b03009 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -84,6 +84,7 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa androidx-media3-datasource-okhttp = { module = "androidx.media3:media3-datasource-okhttp", version.ref = "androidx-media3" } androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "androidx-media3" } +androidx-media3-session = { module = "androidx.media3:media3-session", version.ref = "androidx-media3" } androidx-media3-exoplayer-hls = { module = "androidx.media3:media3-exoplayer-hls", version.ref = "androidx-media3" } androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "androidx-media3" } androidx-media3-ui-compose = { module = "androidx.media3:media3-ui-compose", version.ref = "androidx-media3" }