A top-level playlist API for ExoPlayer

Marc Bächinger
AndroidX Media3
Published in
5 min readSep 17, 2020

--

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.

--

--