xref: /aosp_15_r20/external/exoplayer/tree_15dc86382f17a24a3e881e52e31a810c1ea44b49/docs/playlists.md (revision 30877f796caf59d855b10b687a5d6b3918d765cb)
1---
2title: Playlists
3---
4
5The playlist API is defined by the `Player` interface, which is implemented by
6all `ExoPlayer` implementations. It enables sequential playback of multiple
7media items. The following example shows how to start playback of a playlist
8containing two videos:
9
10~~~
11// Build the media items.
12MediaItem firstItem = MediaItem.fromUri(firstVideoUri);
13MediaItem secondItem = MediaItem.fromUri(secondVideoUri);
14// Add the media items to be played.
15player.addMediaItem(firstItem);
16player.addMediaItem(secondItem);
17// Prepare the player.
18player.prepare();
19// Start the playback.
20player.play();
21~~~
22{: .language-java}
23
24Transitions between items in a playlist are seamless. There's no requirement
25that they're of the same format (e.g., it’s fine for a playlist to contain both
26H264 and VP9 videos). They may even be of different types (e.g., it’s fine for a
27playlist to contain both videos and audio only streams). It's allowed to use the
28same `MediaItem` multiple times within a playlist.
29
30## Modifying the playlist
31
32It's possible to dynamically modify a playlist by adding, moving and removing
33media items. This can be done both before and during playback by calling the
34corresponding playlist API methods:
35
36~~~
37// Adds a media item at position 1 in the playlist.
38player.addMediaItem(/* index= */ 1, MediaItem.fromUri(thirdUri));
39// Moves the third media item from position 2 to the start of the playlist.
40player.moveMediaItem(/* currentIndex= */ 2, /* newIndex= */ 0);
41// Removes the first item from the playlist.
42player.removeMediaItem(/* index= */ 0);
43~~~
44{: .language-java}
45
46Replacing and clearing the entire playlist are also supported:
47
48~~~
49// Replaces the playlist with a new one.
50List<MediaItem> newItems = ImmutableList.of(
51    MediaItem.fromUri(fourthUri),
52    MediaItem.fromUri(fifthUri));
53player.setMediaItems(newItems, /* resetPosition= */ true);
54// Clears the playlist. If prepared, the player transitions to the ended state.
55player.clearMediaItems();
56~~~
57{: .language-java}
58
59The player automatically handles modifications during playback in the correct
60way. For example if the currently playing media item is moved, playback is not
61interrupted and its new successor will be played upon completion. If the
62currently playing `MediaItem` is removed, the player will automatically move to
63playing the first remaining successor, or transition to the ended state if no
64such successor exists.
65
66## Querying the playlist
67
68The playlist can be queried using `Player.getMediaItemCount` and
69`Player.getMediaItemAt`. The currently playing media item can be queried
70by calling `Player.getCurrentMediaItem`. There are also other convenience
71methods like `Player.hasNextMediaItem` or `Player.getNextMediaItemIndex` to
72simplify navigation in the playlist.
73
74## Repeat modes
75
76The player supports 3 repeat modes that can be set at any time with
77`Player.setRepeatMode`:
78
79* `Player.REPEAT_MODE_OFF`: The playlist isn't repeated and the player will
80   transition to `Player.STATE_ENDED` once the last item in the playlist has
81   been played.
82* `Player.REPEAT_MODE_ONE`: The current item is repeated in an endless loop.
83   Methods like `Player.seekToNextMediaItem` will ignore this and seek to the
84   next item in the list, which will then be repeated in an endless loop.
85* `Player.REPEAT_MODE_ALL`: The entire playlist is repeated in an endless loop.
86
87## Shuffle mode
88
89Shuffle mode can be enabled or disabled at any time with
90`Player.setShuffleModeEnabled`. When in shuffle mode, the player will play the
91playlist in a precomputed, randomized order. All items will be played once and
92the shuffle mode can also be combined with `Player.REPEAT_MODE_ALL` to repeat
93the same randomized order in an endless loop. When shuffle mode is turned off,
94playback continues from the current item at its original position in the
95playlist.
96
97Note that the indices as returned by methods like
98`Player.getCurrentMediaItemIndex` always refer to the original, unshuffled
99order. Similarly, `Player.seekToNextMediaItem` will not play the item at
100`player.getCurrentMediaItemIndex() + 1`, but the next item according to the
101shuffle order. Inserting new items in the playlist or removing items will keep
102the existing shuffled order unchanged as far as possible.
103
104### Setting a custom shuffle order
105
106By default the player supports shuffling by using the `DefaultShuffleOrder`.
107This can be customized by providing a custom shuffle order implementation, or by
108setting a custom order in the `DefaultShuffleOrder` constructor:
109
110~~~
111// Set a custom shuffle order for the 5 items currently in the playlist:
112exoPlayer.setShuffleOrder(
113    new DefaultShuffleOrder(new int[] {3, 1, 0, 4, 2}, randomSeed));
114// Enable shuffle mode.
115exoPlayer.setShuffleModeEnabled(/* shuffleModeEnabled= */ true);
116~~~
117{: .language-java}
118
119## Identifying playlist items
120
121To identify playlist items, `MediaItem.mediaId` can be set when building the
122item:
123
124~~~
125// Build a media item with a media ID.
126MediaItem mediaItem =
127    new MediaItem.Builder().setUri(uri).setMediaId(mediaId).build();
128~~~
129{: .language-java}
130
131If an app does not explicitly define a media ID for a media item, the string
132representation of the URI is used.
133
134## Associating app data with playlist items
135
136In addition to an ID, each media item can also be configured with a custom tag,
137which can be any app provided object. One use of custom tags is to attach
138metadata to each media item:
139
140~~~
141// Build a media item with a custom tag.
142MediaItem mediaItem =
143    new MediaItem.Builder().setUri(uri).setTag(metadata).build();
144~~~
145{: .language-java}
146
147
148## Detecting when playback transitions to another media item
149
150When playback transitions to another media item, or starts repeating the same
151media item, `Listener.onMediaItemTransition(MediaItem,
152@MediaItemTransitionReason)` is called. This callback receives the new media
153item, along with a `@MediaItemTransitionReason` indicating why the transition
154occurred. A common use case for `onMediaItemTransition` is to update the
155application's UI for the new media item:
156
157~~~
158@Override
159public void onMediaItemTransition(
160    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
161  updateUiForPlayingMediaItem(mediaItem);
162}
163~~~
164{: .language-java}
165
166If the metadata required to update the UI is attached to each media item using
167custom tags, then an implementation might look like:
168
169~~~
170@Override
171public void onMediaItemTransition(
172    @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
173  @Nullable CustomMetadata metadata = null;
174  if (mediaItem != null && mediaItem.localConfiguration != null) {
175    metadata = (CustomMetadata) mediaItem.localConfiguration.tag;
176  }
177  updateUiForPlayingMediaItem(metadata);
178}
179~~~
180{: .language-java}
181
182## Detecting when the playlist changes
183
184When a media item is added, removed or moved,
185`Listener.onTimelineChanged(Timeline, @TimelineChangeReason)` is called
186immediately with `TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED`. This callback is
187called even when the player has not yet been prepared.
188
189~~~
190@Override
191public void onTimelineChanged(
192    Timeline timeline, @TimelineChangeReason int reason) {
193  if (reason == TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
194    // Update the UI according to the modified playlist (add, move or remove).
195    updateUiForPlaylist(timeline);
196  }
197}
198~~~
199{: .language-java}
200
201When information such as the duration of a media item in the playlist becomes
202available, the `Timeline` will be updated and `onTimelineChanged` will be called
203with `TIMELINE_CHANGE_REASON_SOURCE_UPDATE`. Other reasons that can cause a
204timeline update include:
205
206* A manifest becoming available after preparing an adaptive media item.
207* A manifest being updated periodically during playback of a live stream.
208