A top-level playlist API for ExoPlayer
In ExoPlayer 2.0, MediaSource composition made it possible to play sequences of media items using ConcatenatingMediaSource
. ExoPlayer 2.5 added the ability to dynamically edit the sequence of media items during playback. ExoPlayer 2.12 goes a step further, directly integrating playlist support into the player’s top-level API. Along with the new playlist API, a new MediaItem
class is introduced to allow media to be defined and passed to the player in a convenient way, without having to build MediaSource
instances in application code. When the player receives a MediaItem
, it will convert it to a MediaSource
internally for playback.
Adding items to the playlist
Creating a playlist of media items and passing it to the player is simple, as shown below:
In this example, media items are created with the MediaItem.fromUri
convenience method. Later in this post, we’ll learn how to build more complex media items with a MediaItem.Builder
, as well as how media items are converted into MediaSource
instances for playback inside the player.
Detecting playback transitions
The currently media item can always be queried by calling getCurrentMediaItem
on the player. Detecting when the player transitions from one media item to another is as simple as implementing the EventListener.onMediaItemTransition
callback. An application will commonly implement this method to update its user interface to reflect the new item being played:
The reason for the transition is indicated by the reason
argument, with possible values defined by @MediaItemTransitionReason
. Common reasons include playback transitioning automatically when the end of an item is reached (MEDIA_ITEM_TRANSITION_REASON_AUTO
) and the user seeking to a different item (MEDIA_ITEM_TRANSITION_REASON_SEEK
). See the @MediaItemTransitionReason Javadoc for other possible reasons.
Modifying the playlist
The playlist can be modified by calling addMediaItem(MediaItem item)
, moveMediaItem(int fromIndex, int toIndex)
and removeMediaItem(int index)
directly on the player. Playlist modifications can be performed when the player is in any state, including before the player is prepared and while media is currently playing. More details, as well as variations of these methods for adding, moving and removing multiple media items, can be found in the developer guide and Player Javadoc respectively.
If you previously used ConcatenatingMediaSource
, you may be familiar with passing an onCompletionAction
runnable to playlist modification methods, to be executed after the modification has taken place:
When using the new top-level playlist API this is unnecessary. The tighter integration of playlists into the player allows modifications to be applied synchronously, meaning such an action can be executed directly after a modification is made:
A modification of the playlist can be detected by implementing the EventListener.onTimelineChanged
callback and looking for calls where the reason
argument is TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED
. An application may implement this callback to update its user interface to reflect the updated playlist. See the developer guide for more details.
Building more complex media items
We’ve already seen how MediaItem.fromUri
can be used to build a simple media item. To build more complex media items, MediaItem.Builder
can be used. The code snippet below demonstrates how to build a media item for an HLS stream, attaching custom application data using setTag
:
Setting a MIME type is not generally required. It’s only needed to create HLS, DASH or SmoothStreaming media items in cases where the media URI has a non-standard file extension, in which case specifying the MIME type as MimeTypes.APPLICATION_M3U8
, MimeTypes.APPLICATION_MPD
or MimeTypes.APPLICATION_SS
respectively acts as an explicit hint to the player.
Attaching custom application data to a media item can be useful when receiving media items back from the playlist API. For example, the data attached in the example above could be retrieved and used to update the application’s user interface when playback transitions to another media item:
MediaItem.Builder
supports building of MediaItem
instances that specify a number of additional properties, including:
- Protected content properties including the DRM type, license server URI and license request headers.
- Side-loaded subtitle files to use during playback.
- Clipping start and end positions.
- An ad tag URI for ad insertion.
See the developer guide for more details.
MediaItem to MediaSource conversion
When a MediaItem
is added to the playlist, the player converts it internally into a playable MediaSource
. By default the library does this using a DefaultMediaSourceFactory
.
In the simple case, DefaultMediaSourceFactory
will convert a MediaItem
into a ProgressiveMediaSource
, DashMediaSource
, HlsMediaSource
or SsMediaSource
, depending on the type of the media. In more complicated cases, DefaultMediaSourceFactory
uses MediaSource composition to build up an appropriate corresponding MediaSource. For example, the media item defined below is for a protected and clipped DASH stream:
In this case DefaultMediaSourceFactory
will build a DrmSessionManager
configured for Widevine and the specified license URI. This is then injected when building a DashMediaSource
. Finally, the clipping properties are applied by wrapping the DashMediaSource
in a ClippingMediaSource
.
DefaultMediaSourceFactory
applies other media item properties similarly. For example, MergingMediaSource
is used to attach side-loaded subtitle files, and wrapping with AdsMediaSource
is used to apply ad tag URIs.
Sounds complicated? The good news is that users of the new top-level playlist API only need to build the media item, and can leave it to the player to take care of building the appropriate corresponding MediaSource
.
Customizing the conversion
DefaultMediaSourceFactory
covers a wide range of use cases. However, some developers may want to implement their own MediaSource
or instantiate an existing implementation in a way that cannot be specified using MediaItem
. For these use cases developers can implement a custom MediaSourceFactory
, which can be set when building a player with SimpleExoPlayer.Builder
or ExoPlayer.Builder
.
Using MediaSources directly
In addition to the top-level playlist API based on MediaItem
, the ExoPlayer
interface offers methods for setting and adding to the playlist the take MediaSource
instances directly (e.g., setMediaSources(List<MediaSource>)
). This provides another alternative to specifying a custom MediaSourceFactory
for advanced use cases.
We think the new top-level playlist API makes it easier and more convenient to use ExoPlayer for a wide range of use cases. The new MediaItem
class makes it possible to define media items in a declarative way, including items that are clipped, that have side-loaded subtitles, and that have ad tag URIs. DefaultMediaSourceFactory
takes care of converting these media items into playable MediaSource instances internally. Advanced use cases are supported by passing a custom MediaSourceFactory
, or by passing MediaSource
instances directly to the player.
As always, we are keen to hear your opinion of our new API. Please let us know you questions or general feedback on GitHub.