Repeat modes in ExoPlayer
Starting with version 2.5, ExoPlayer will have a repeat mode feature allowing you to seamlessly switch between regular playback, Repeat One, and Repeat All modes.
The new repeat modes work pretty much as you would expect:
- Regular playback is what you get by default. It plays everything you have set up from start to end and then transitions to the
Player.STATE_ENDED
state. If you ever want to go back to this mode you can useplayer.setRepeatMode(Player.REPEAT_MODE_OFF);
. - Repeat One indefinitely loops the current window (for more information about windows, have a look at our excellent Timeline documentation). You can enable this mode with
player.setRepeatMode(Player.REPEAT_MODE_ONE);
. - Repeat All loops the entire timeline (all windows) indefinitely. It is conceptually equivalent to using a
LoopingMediaSource
with an infinite loop count but is more flexible as it can be turned off and on during playback. This mode can be enabled withplayer.setRepeatMode(Player.REPEAT_MODE_ALL);
.
Whenever the repeat mode changes, the player will notify any registered Player.EventListener
by calling onRepeatModeChanged(newRepeatMode)
. This comes in quite handy if you need to update your UI for example.
We also added this feature to our customizable UI package. The repeat mode control buttons are not shown by default, but you can easily enable them by calling SimpleExoPlayerView.setRepeatToggleModes(...)
with one of the following options:
REPEAT_TOGGLE_MODE_NONE
hides the button completely.REPEAT_TOGGLE_MODE_ONE
enables the Repeat One option only.REPEAT_TOGGLE_MODE_ALL
enables the Repeat All option only.REPEAT_TOGGLE_MODE_ONE | REPEAT_TOGGLE_MODE_ALL
enables both options, Repeat One and Repeat All.
Alternatively, set your preferred repeat mode options with the attribute repeat_toggle_modes
to PlaybackControlView
in the layout XML file. Valid attribute values are none
, one
, all
, or one|all
.
So, how does it work? Does the Timeline change every time you toggle the repeat mode (No)? Do you still get gapless playback between videos (Yes)?
The implementation is surprisingly simple and it keeps all of ExoPlayer’s existing playback mechanisms in place like pre-buffering for gapless playback. It also doesn’t update the Timeline as we don’t consider repeat modes as changes to the inherent structure of the media. It all relies on one nifty trick of adding a method to the Timeline interface for querying the next and previous window index given a certain repeat mode. So, for regular playback this method just points to the next or previous window:
For Repeat One all windows point to themselves:
And for Repeat All, the first and last window close the loop by pointing to the other end:
Now, whenever the player needs to determine what to buffer next, instead of buffering the window at windowIndex + 1
, it queries the Timeline for the next window index. The same method can also be used by the UI controller to skip to the next or previous window.
One final caveat is that we need to inspect the buffered data whenever the repeat mode changes to see if it still matches the new order. If it doesn’t, we throw away all pre-buffered data from the point where it doesn’t match and continue buffering from there.
For those of you interested in more advanced playback possibilities, we also added a flag to the ConcatenatingMediaSource
constructor to allow you to treat the whole concatenation as repeat-one-atomic. This means that whenever you turn on Repeat One within this media source it gets repeated in its entirety even if it consists of multiple windows. For example, setting up a media source as such:
results in the following behavior for Repeat One:
This blog post described how we added support for repeat modes (Repeat One, Repeat All) including new matching UI components. We also went into some more depth on how it is implemented inside ExoPlayer. If you are interested in this feature, please try it out with our dev-v2 branch or in the upcoming ExoPlayer 2.5! For questions, feedback and bug reports, feel free to use our issue tracker on GitHub.