The relevant code is in MediaSessionConnector.java:
private int mapPlaybackState(int exoPlayerPlaybackState, boolean playWhenReady) {
switch (exoPlayerPlaybackState) {
case Player.STATE_BUFFERING:
return PlaybackStateCompat.STATE_BUFFERING;
case Player.STATE_READY:
return playWhenReady ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED;
case Player.STATE_ENDED:
return PlaybackStateCompat.STATE_PAUSED;
default:
return PlaybackStateCompat.STATE_NONE;
}
}
It's unclear to me why Player.STATE_ENDED is mapped to PlaybackStateCompat.STATE_PAUSED instead of PlaybackStateCompat.STATE_STOPPED. I'd like to alter that mapping behavior in my own app, but unfortunately, this is a private method and the class itself is final, so I'm doubly prevented from making my own customizations.
The reasoning behind this mapping is that with the MediaSession API, MediaControllerCompat.TransportControls.stop() in contrast to MediaControllerCompat.TransportControls.pause() implies that resources like codecs or the player itself can/should be freed. This is not the case for Player.STATE_ENDED. If ExoPlayer is in the Player.STATE_ENDED seeking to a position somewhere before the end of the media makes the player transition to STATE_READY again. So no resources are freed.
Documentation of STATE_PAUSED and STATE_STOPPED is unclear around this though:
https://developer.android.com/reference/android/support/v4/media/session/PlaybackStateCompat.html#STATE_STOPPED
It might be implied here: https://developer.android.com/reference/android/support/v4/media/session/MediaControllerCompat.TransportControls.html#stop()
While the actual mapping of STATE_ENDED is compatible with that, I acknowledge that this hides the Player.STATE_ENDED which is not visible through the media session state with that mapping. So you can't detect when all media is played to the end.
I think we should reconsider this and map Player.STATE_ENDED to PlaybackStateCompat.STOP which then would reflect that the media has been played to the end.
Am I correct you need to detect the STATE_END for your use case?
Ah, thanks for the explanation. You are correct, I need to detect the end of playback from a media controller (through a MediaControllerCompat.Callback listener).
We'll make a change to map Player.STATE_ENDED onto PlaybackStateCompat.STATE_STOPPED.
Hi @ojw28,
I was wondering why this change didn't make it to release yet? I could really use this functionality of knowing when the track has ended. Just like @dougkeen, I need it through the MediaControllerCompat.Callback listener.
Most helpful comment
We'll make a change to map
Player.STATE_ENDEDontoPlaybackStateCompat.STATE_STOPPED.