Music/Video player is one of the first essential apps that we download on our phone when we buy a new one. Also, the music/video app has come a long way and now most of the content is streamed over fluctuating mobile network along with the new kind of content shared by people such as 3D video and content.

In this article, We will be learning how to overcome all those challenges and support a new type of content on an Android app using ExoPlayer library.

Photo by Wahid Khene on Unsplash

Article bores me, Show me Code

If you directly want to jump at the code, then check out the following GitHub repository with proper code documentation.

ExoPlayer Overview

ExoPlayer is an open source library separate from Android Framework but built on top on Android MediaCodec API and supports essential features such as Dynamic Adaptive Streaming over HTTP (DASH), Smooth Streaming, Common encryption which is not supported by Android built-in media API.

New Standards and Requirements — DASH, Smooth Streaming & Common Encryption (Optional)

In the past, most video and audio utilized streaming protocols such as RTP (Real Time Protocol) or RTSP (Real Time Streaming Protocol) which means that it relies on the persistent connection between your device and the server sending the video/audio. The problem with that approach is that since its Stateful, it uses more bandwidth and doesn’t have the ability to change the source on runtime and so is lesser suitable for the current mobile computing needs.

The new technologies such as DASH by MPEG and Smooth Streaming by Microsoft tackle these issue by basing their technology over a stateless HTTP connection and having an adaptive bitrate streaming. The major advantage of these technologies is that it is much more flexible such as the video source can be changed at runtime, the video can be streamed from any segment of the video.

Check out the following article series from HowStuffWorks that has described both RTS and DASH in detail.

Let’s get started

Add Dependencies — Build.gradle (Module: app)

dependencies {

//Other dependenices



//Exoplayer

implementation "com.google.android.exoplayer:exoplayer:$exoPlayerVersion"



//Exoplayer IMA(Interactive Media Ads)

implementation ("com.google.android.exoplayer:extension-ima:$exoPlayerVersion"){

exclude module: 'support-v4'

}

}

Adding Layout

<com.google.android.exoplayer2.ui.PlayerView

android:id="@+id/player_view"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

Playing a basic video

For playing a basic video, we need to follow following simple steps:-

Setup Player View

Get a reference to the PlayerView defined in the layout.

@Override

protected void onCreate(Bundle savedInstanceState) {



playerView = findViewById(R.id.player_view);

}

Initialize the Player

Next step is to initialize our video player instance. It requires:-

* Renderer — It deals with setting up the connection (HTTP/local) with the source, video playback even listener and handler.

* Track Selector — As the name suggests, it deals with the track selection and management which is going to be consumed by the renderer.

* Load Control — It controls buffering of the media. Next, we need to set up parameters for the player.

* playWhenReady — A boolean parameter that Sets whether playback should proceed when the PlaybackState is STATE_READY. Also If the player is already in the ready state then this method can be used to pause and resume the playback. Initialize this with True.

* currentWindowIndex — This is an integer value which returns the index of the current window (think of it as buffer bucket) currently being played.

* playbackPosition — This is the frame where the playback is currently positioned. Plugging everything Up. Finally, we will plug everything together so our initializePlayer function will become as —

private void initializePlayer() {

player = ExoPlayerFactory.newSimpleInstance(

new DefaultRenderersFactory(this),

new DefaultTrackSelector(), new DefaultLoadControl());



playerView.setPlayer(player);



player.setPlayWhenReady(playWhenReady);

player.seekTo(currentWindow, playbackPosition);

}

Build Media Source

Next step is to build media source which is the source for our media file to our above-created player. Exoplayer comes with many default MediaSource factories as shown in code below:-

Plug-in Everything and Hit Play

For the final part, all we need to do is add a relevant media source to our player and hit play.

Make it full Screen

@SuppressLint("InlinedApi")

private fun hideSystemUi() {

playerView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE

or View.SYSTEM_UI_FLAG_FULLSCREEN

or View.SYSTEM_UI_FLAG_LAYOUT_STABLE

or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY

or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)

}

Finally, we will write our play function which will take either a single URL or array of URL as a parameter and play them accordingly.

var currUri = null

var currUriList = null //Play single video

fun play(uri: Uri?){

if(uri == null) return

currUri = uri

initPlayer()

preparePlayer(uri!!)

hideSystemUi()

}



//Overloaded function to play the whole playlist

fun play(uriList : Array<Uri>?){

if(uriList == null) return

currUriList = uriList

initPlayer()

preparePlayer(uriList!!)

hideSystemUi()

}

Handling Player’s Lifecycle

Finally, we will handle the player lifecycle appropriately to handle configuration changes and activity pause & resume.

Now just call these lifecycle methods in your activity’s, fragment’s or Lifecycle Observer’s appropriate method.

Key TakeAway

ExoPlayer can support multiple video and audio formats. (Check BuildMediaSource section)

Since Exoplayer supports Adaptive bitrate streaming, you can make use of this technique (By using DASH or HLS media source) to provide a better user experience.

ExoPlayer comes up with many useful features on top on Android built-in MediaCodec library and thus make it easier to develop more powerful and awesome Video Players.

Happy Coding!