Working with ExoPlayer — The clean way — and customization
ExoPlayer is a open-source super customizable audio/video player from Google. It is able to play DASH (Dynamic Adaptive Streaming over HTTP), HLS (HTTP Live Streaming) and SmoothStreaming; merge, loop, concatenate, cache medias — while allowing developer to define custom load control, define seamless transition between successive medias and much more. So without further delay, lets get started.
Installation
In your build.gradle
file, include following dependencies and turn on Java 8 support.
repositories {
google()
jcenter()
}
implementation 'com.google.android.exoplayer:exoplayer:2.X.X'
P.S For cleaner code, we will be using Data binding Library and BindingAdapter so do not forget to enable these in gradle.
UI setup
Now lets head to UI setup. Create a layout file called item_video
. This may be inflated in RecyclerView
or a Fragment or a Activity but for now, lets assume this will be inflated in RecyclerView.
Usage
Since we are inflating our layout in RecyclerView
’s adapter, lets create a class that extends RecyclerView.Adapter
and on RecyclerView.Adapter#onBindViewHolder
, we will bind the video stream URL to the variable we have defined in our xml i.e url
. Optionally, if we need to know the current state of PlayerView
, we will have to implement a listener PlayerStateCallback
and pass it to the PlayerView
to get notified of the state change .
P.S- Here’s a helpful gist containing a number of streaming URLs you can use to test your implementation.
Notice how we are setting the stream URL for the video in url
variable available from the data binding library. The app:video_url
and the app:on_state_change
part in the xml file is from BindingAdapter
. The callback
is used to communicate the state of the video player like buffering, paused, playing or idle so that we can handle these change of state in our main code. Now for the fun part — Lets create an extension function with @BindingAdapter
annotation, that we will use to setup our PlayerView
, with the values we have passed in our xml file as the arguments.
You can also pass in the view for ProgressBar
as an argument to above extension function.
Great! Look at how clean the RecyclerView.ViewAdapter
code is! There’s barely anything there. We have successfully started streaming the videos from the test URLs.
Now for the advance part!
Caching
In order to prevent media from buffering again and again, you’ll need to implement a local cache. You can do this by creating a subclass of DataSource.Factory
and building a CacheDataSource
.
Note: I have used a local Context
here, but in singleton dependencies, you should use the application context. It’s better to inject it.
And to use this cache as data source, instead of DefaultHttpDataSoruceFactory
— use the above created LocalCacheDataSourceFactory
.
Seamless transition between medias
Need a seamless buffer-free transition between successive medias? Want to have control over the looping or the playback sequences of the media? Then MediaSource
is what you need! Here’s a nice article about it.
Load Control
Want to have a control on the duration of media buffered for playing or before playing? Then you’ll need to override the DefaultLoadControl. It provides a dummy constructor as well as a builder to allow you to customize the property of the ExoPlayer.