Building a video player app in Android (Part 2 / 5)
With ExoPlayer, Playlists, MediaSession, Audio Focus, PIP
The goal of this series of articles is to get you started with using ExoPlayer to build a simple, but feature rich, video player app (that supports playlists, MediaSession, Audio Focus, and Picture in Picture).
This is the second part of a 5 part series that includes:
- ExoPlayer introduction
- ExoPlayer playlists, UI customization, and events(this article)
- MediaSession Connector extension for ExoPlayer
- Supporting Audio Focus
- Supporting PIP
The first article in the series covered the steps needed to create an ExoPlayer instance and attach it to the UI of your app to allow video playback. It also covered connecting the ExoPlayer to your Activity
lifecycle. This article gets into the details of creating playlists by concatenating MediaSource
s, along with showing you how to customize the ExoPlayer’s playback control UI.
Creating playlists
Instead of providing the player with a single ExtractorMediaSource
(as shown in the buildMediaSource(Uri)
method above), you can simply create a DynamicConcatenatingMediaSource
which can have any number of MediaSource
objects contained in it. Here’s an example.
DynamicConcatenatingMediaSource
creates a dynamic playlist. If you want a static playlist then you can use ContactenatingMediaSource
. Both of them will combine media sources seamlessly and handle buffering for the entire playlist. To learn more about the details of MediaSource
composition, please read this medium article.
Customizing the UI
In order to view the contents of the video that your app loads using ExoPlayer, you have to add a PlayerView
to the activity that creates the ExoPlayer instance and loads the media. You can attach this View to the ExoPlayer instance by assigning your ExoPlayer instance to the player property of the PlayerView
.
Here’s an example of a layout XML for an Activity that shows the PlayerView
. The attributes with the “app:
” namespace allow you to pass configuration parameters to the view so that you can customize its behavior to your liking. You can control the increment (in ms) for video fast forward or rewind, and many other things. You can find a list of all these attributes and what they do in the ExoPlayer javadocs.
Unless you disable the controller with app:use_controller=”false”
, PlayerView
automatically shows a media controller UI, which allows the user to play, pause, skip to next, etc. You can customize how long this controller is displayed before it hides itself automatically by setting a timeout value in the show_timeout
attribute.
In order to customize the controller UI itself, there’s an attribute “controller_layout_id
” that allows us to select a layout file that contains any customizations to the controller UI itself. Here’s an example of this.
This produces a media controller UI that looks similar to the image below. The UI controller is overlaid in front of the PlayerView
itself. You can add or remove buttons for play, pause, rewind, skip, etc. And the way ExoPlayer knows that you want to use your components instead of the defaults is due to the fact that you use the IDs that are supplied by ExoPlayer itself for things like the play button, or pause button, or skip to next button, etc. In order to learn more about customizing the PlayerView
and the UI controller, please read this medium article.
Listening to player events for UX
ExoPlayer provides lots of valuable information about its internal state via the ExoPlayer.EventListener
interface. You can implement this interface or subclass Player.DefaultEventListener
in your code to get notified when player state changes. Additionally, you can implement VideoRendererEventListener
and AudioRendererEventListener
to get more details about audio and video rendering. Together you can use these signals to get an idea of how the quality of experience (QoE) is being affected for the user of your app.
Here are just a few examples:
- When
ExoPlayer.EventListener.OnPlaybackStateChanged()
is called withSTATE_BUFFERING
that is not during the start of playback or when the user has requested to seek to a position that’s not yet available, then this is considered harmful for the QoE. - The time it takes for the
ExoPlayer.VideListener.onFirstFrameRendered
to execute (relative to when playback was initiated by the user in the app) is a signal of initial latency of playback. For a good QoE, this should be as low as possible. VideoRendererEventListener.onDroppedFrames
provides information about dropped frames. Too many of these and you could have a negative impact of QoE.
These articles won’t cover event listening in ExoPlayer in any more detail. To dive more deeply into ExoPlayer’s event listeners, along with QoE signals, be sure to go thru the Measure QoE section of the ExoPlayer codelab. For a deeper understanding of how to detect when the player is buffering, paused, or actually playing media, please refer to this stackoverflow post.
Adaptive streaming
ExoPlayer not only supports loading media files from the APK and network, but it has extensive support for adaptive streaming. Adaptive streaming cuts video and audio files into small chunks of a given duration. ExoPlayer then stitches them back together for playback. Each of these chunks may be available in different qualities (size or bitrate). The player can choose the quality of each chunk according to the device capabilities and available network bandwidth. The player starts with a lower quality chunk and then switches to a better one if more bandwidth becomes available (e.g. switching to a fast WiFi network from a slow mobile one).
You can learn more about both HLS (HTTP Live Streaming), MPEG-DASH (Dynamic Adaptive Streaming over HTTP), and SmoothStreaming in this MDN article. To learn more about the differences between DASH and HLS checkout this article on the ExoPlayer blog. These articles won’t go farther into using ExoPlayer for adaptive streaming, but if you want to look into this more deeply, please go thru the Adaptive Streaming section of the ExoPlayer codelab.
Source code on GitHub
By following these 5 articles, you should be able to create a video player app that is similar to this sample we have created (which you can get from Android Studio as well).
Resources for further learning
ExoPlayer
- IO17 ExoPlayer codelab
- IO14 ExoPlayer Introduction Video
- IO17 ExoPlayer Session Video
- Why ExoPlayer?
- Latest changes for ExoPlayer v2.6.1
MediaSession, Audio Focus
DASH, HLS
Picture in Picture