AndroidMediaPlayer Queue Playback Fix
Fixed queue playback issue where only the first track was playing. Updated track index tracking and added proper callbacks for onTrackStarted during media item transitions to ensure all tracks in a queue play sequentially.
Problem
When passing 3 tracks to playQueue(), only the first track was playing. After the first track completed, the queue wasn’t continuing to play tracks 2 and 3, and onQueueCompleted() was being called immediately.
Root Cause
The original implementation had several issues with track index tracking:
Initial index was 0: Starting with
currentTrackIndex = 0meant the first track would match immediately on STATE_READY, but this index wasn’t being properly managed for subsequent tracks.onMediaItemTransitionwasn’t callingonTrackStarted: When ExoPlayer transitioned to the next track, we were incrementing the index but not notifying the listener that a new track started. This meant tracks 2 and 3 never got their start callbacks.Race condition in state tracking: The logic in
onPlaybackStateChangedandonMediaItemTransitionwasn’t coordinated, leading to missed callbacks.
Solution
The fix involves:
Start with index -1: This ensures we can detect the first track properly when it becomes ready.
Add
hasNotifiedTrackStartflag: This prevents duplicate notifications and helps track whether we’ve notified about the current track.- Call
onTrackStartedin both places:- In
onPlaybackStateChangedwhen STATE_READY is reached (for the first track) - In
onMediaItemTransitionwhen transitioning between tracks (for subsequent tracks)
- In
Use
player.currentMediaItemIndex: Instead of manually incrementing, we rely on ExoPlayer’s own index tracking to know which track is currently playing.- Better logging: Added detailed logging to track state changes and transitions.
Key Changes
Before
1
2
3
4
5
6
7
8
9
10
11
private var currentTrackIndex = 0
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_AUTO) {
// Only notified completion, not start of new track
if (currentTrackIndex > 0) {
currentListener?.onTrackCompleted(currentTrackIndex - 1)
}
currentTrackIndex++ // Just increment, no start callback
}
}
After
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private var currentTrackIndex = -1
private var hasNotifiedTrackStart = false
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
if (mediaItem != null && reason == Player.MEDIA_ITEM_TRANSITION_REASON_AUTO) {
// Notify completion of previous track
if (currentTrackIndex >= 0 && hasNotifiedTrackStart) {
currentListener?.onTrackCompleted(currentTrackIndex)
}
// Start new track
val newIndex = player.currentMediaItemIndex
if (newIndex >= 0 && newIndex < trackInfoList.size) {
currentTrackIndex = newIndex
val trackInfo = trackInfoList[currentTrackIndex]
currentListener?.onTrackStarted(currentTrackIndex, trackInfo) // NOW CALLED!
hasNotifiedTrackStart = true
}
}
}
Expected Behavior Now
With 3 tracks queued, you should see:
- Track 0 starts →
onTrackStarted(0, trackInfo0) - Track 0 completes →
onTrackCompleted(0) - Track 1 starts →
onTrackStarted(1, trackInfo1) - Track 1 completes →
onTrackCompleted(1) - Track 2 starts →
onTrackStarted(2, trackInfo2) - Track 2 completes →
onTrackCompleted(2) - Queue completes →
onQueueCompleted()
Testing
Build and run the app again. The logs should now show:
- “Playback state changed” messages with proper state tracking
- “Media item transition” messages when moving between tracks
- All
onTrackStartedandonTrackCompletedcallbacks for each of the 3 tracks onQueueCompletedonly after all tracks have played