androidx / androidx/media

MediaController generates wrong onMediaItemTransition() callback on seek inside same media item

Open
#3,248 4 comments 0 reactions 1 assignee View on GitHub

@marcbaechinger is already working on this.

Since May 29, 2026.

bug
Dominant language
Java
Stars
3k
Forks
955
Avg merge
12d 14h
Merged PRs (30d)
2

Description

Version

Media3 1.10.1

More version details

No response

Devices that reproduce the issue

API 33 emulator

Devices that do not reproduce the issue

N/A

Reproducible in the demo app?

Yes

Reproduction steps
  1. Apply attached patch to session-demo app
  2. Play any song from an artist with more than one song, choose a song that is not the first in the list
  3. Seek inside this same song to some other position using seekbar
  4. onMediaItemTransition() is called on controller at this point

Note: to reproduce this, controller must be attached before setMediaItems happens, which is why I added a new controller in the patch. Also, index of song passed to setMediaItems must be >0.


diff --git a/demos/session_service/src/main/java/androidx/media3/demo/session/DemoPlaybackService.kt b/demos/session_service/src/main/java/androidx/media3/demo/session/DemoPlaybackService.kt
index 81502f5ee8..f49cc17e60 100644
--- a/demos/session_service/src/main/java/androidx/media3/demo/session/DemoPlaybackService.kt
+++ b/demos/session_service/src/main/java/androidx/media3/demo/session/DemoPlaybackService.kt
@@ -23,6 +23,7 @@ import android.content.Context
 import android.content.pm.PackageManager
 import android.graphics.Bitmap
 import android.os.Build
+import android.util.Log
 import androidx.annotation.OptIn
 import androidx.core.app.NotificationCompat
 import androidx.core.app.NotificationManagerCompat
@@ -32,6 +33,7 @@ import androidx.datastore.dataStore
 import androidx.lifecycle.lifecycleScope
 import androidx.media3.cast.CastPlayer
 import androidx.media3.common.AudioAttributes
+import androidx.media3.common.MediaItem
 import androidx.media3.common.Player
 import androidx.media3.common.listenTo
 import androidx.media3.common.util.UnstableApi
@@ -39,6 +41,7 @@ import androidx.media3.demo.session.service.R
 import androidx.media3.exoplayer.ExoPlayer
 import androidx.media3.exoplayer.util.EventLogger
 import androidx.media3.session.CommandButton
+import androidx.media3.session.MediaController
 import androidx.media3.session.MediaLibraryService
 import androidx.media3.session.MediaSession
 import androidx.media3.session.MediaSession.ControllerInfo
@@ -54,6 +57,7 @@ import kotlinx.coroutines.launch
 open class DemoPlaybackService : MediaLibraryService() {
 
   private lateinit var mediaLibrarySession: MediaLibrarySession
+  private lateinit var controller: MediaController
 
   private val turnShuffleOnButton by
     lazy @OptIn(UnstableApi::class) {
@@ -146,6 +150,7 @@ open class DemoPlaybackService : MediaLibraryService() {
   @OptIn(UnstableApi::class)
   override fun onDestroy() {
     getBackStackedActivity()?.let { mediaLibrarySession.setSessionActivity(it) }
+    controller.release()
     mediaLibrarySession.release()
     mediaLibrarySession.player.release()
     clearListener()
@@ -165,6 +170,17 @@ open class DemoPlaybackService : MediaLibraryService() {
       MediaLibrarySession.Builder(this, player, createLibrarySessionCallback())
         .also { builder -> getSingleTopActivity()?.let { builder.setSessionActivity(it) } }
         .build()
+    controller = MediaController.Builder(this, mediaLibrarySession.token)
+      .buildAsync().get()
+    controller.addListener(object : Player.Listener {
+
+          override fun onMediaItemTransition(
+            mediaItem: MediaItem?,
+            reason: @Player.MediaItemTransitionReason Int
+          ) {
+            androidx.media3.common.util.Log.e("hi","[CONTROLLER] media item changed due to $reason")
+          }
+      })
 
     mediaLibrarySession.setCustomShuffleModeButton()
     lifecycleScope.launch {
@@ -181,6 +197,14 @@ open class DemoPlaybackService : MediaLibraryService() {
         .setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true)
         .build()
     exoPlayer.addAnalyticsListener(EventLogger())
+    exoPlayer.addListener(object : Player.Listener {
+      override fun onMediaItemTransition(
+        mediaItem: MediaItem?,
+        reason: @Player.MediaItemTransitionReason Int
+      ) {
+        Log.e("hi", "[PLAYER] media item transition due to $reason")
+      }
+    })
     return CastPlayer.Builder(/* context= */ this).setLocalPlayer(exoPlayer).build()
   }
 
diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
index f1361dedec..7ad9006381 100644
--- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
+++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java
@@ -2530,6 +2530,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
     }
     MediaItem currentMediaItem = newPlayerInfo.getCurrentMediaItem();
     if (mediaItemTransitionReason != null) {
+      Log.i("hi","dispatch mit");
       listeners.queueEvent(
           /* eventFlag= */ Player.EVENT_MEDIA_ITEM_TRANSITION,
           listener -> listener.onMediaItemTransition(currentMediaItem, mediaItemTransitionReason));
@@ -2991,6 +2992,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
             || positionDiscontinuityReason == DISCONTINUITY_REASON_SEEK)) {
       if (oldPlayerInfo.newPositionInfo.mediaItemIndex
           != finalPlayerInfo.newPositionInfo.mediaItemIndex) {
+        Log.e("hi", "move from "+oldPlayerInfo.newPositionInfo.mediaItemIndex+ " to "+finalPlayerInfo.newPositionInfo.mediaItemIndex);
         mediaItemTransitionReason =
             positionDiscontinuityReason == DISCONTINUITY_REASON_AUTO_TRANSITION
                 ? MEDIA_ITEM_TRANSITION_REASON_AUTO
Expected result

No onMediaItemTransition() callback

Actual result
2026-05-29 18:54:24.382 12519-12519 hi                      androidx.media3.demo.session         E  move from 0 to 1
2026-05-29 18:54:24.382 12519-12519 hi                      androidx.media3.demo.session         I  dispatch mit
2026-05-29 18:54:24.382 12519-12519 hi                      androidx.media3.demo.session         E  [CONTROLLER] media item changed due to 2
Media

Anything works

Bug Report
  • You will email the zip file produced by adb bugreport to android-media-github@google.com after filing this issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.