Replacing the old Android MediaPlayer API, ExoPlayer offers features not currently supported by the old API such as DASH, SmoothStreaming, Playlists, and better customisation options. Add all that and more on top of a much more robust package that works more consistently across different devices.
[/vc_column_text][/vc_column][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” bg_color=”#bbdefb” scene_position=”center” text_color=”light” text_align=”left” top_padding=”0″ bottom_padding=”0″ overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none” shape_type=””][vc_column centered_text=”true” column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” top_margin=”12″ bottom_margin=”12″ width=”1/6″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][nectar_icon icon_family=”fontawesome” icon_style=”default” icon_color=”Extra-Color-1″ icon_padding=”20px” icon_fontawesome=”fa fa-youtube-play”][/vc_column][vc_column column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” top_margin=”0″ bottom_margin=”16″ width=”5/6″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][vc_column_text]Do note that if you choose to play from the web, you will need the direct download uri of the video. This means you can’t use ExoPlayer for YouTube, not at least without the YouTube Player API.[/vc_column_text][/vc_column][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” scene_position=”center” text_color=”dark” text_align=”left” overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none”][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” scene_position=”center” text_color=”dark” text_align=”left” overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none”][vc_column column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” width=”1/1″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][vc_column_text]
ExoPlayer Features
ExoPlayer was esentially built to be a better Android Media Player API, and thus offers many features that the old API just doesn’t have.
- More supported media formats including DASH, SmoothStreaming, HLS, Progressive Container formats, and HDR video playback
- Features such as Playlists, Gapless Audio Playback, Seeking in Live Streams, and Multi-Period DASH
- Subtitle support, support for Widevine common encryption, and Google Cast SDK support
- A very nicely customisable UI, both in its controls and in its look and feel
And that’s just scraping the surface of it. Find the full list of pros and cons here.
Do note that ExoPlayer doesn’t work on Android versions below 4.1 (API level 16). If you’re considering using ExoPlayer, make sure your minimum supported version meets the requirements for all the features you intend to use by checking the supported devices page here.[/vc_column_text][/vc_column][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” scene_position=”center” text_color=”dark” text_align=”left” overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none”][vc_column column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” width=”1/1″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][vc_column_text]
ExoPlayer Alternatives and Competitors
Although ExoPlayer is very widely adopted in Android apps all over, it does have some successful competition (that can play media from various sources, particularly these libraries:
- Vitamio
- LibVLC
How do these libraries compare to ExoPlayer?
Vitamio
It’s arguable which media player is more robust between Vitamio and ExoPlayer, but other devs have conducted tests that proved ExoPlayer has better performance when it comes to loading videos. Vitamio is also a paid service which may put off many developers.
LibVLC
LibVLC is somewhat limited in its functionality as it requires the Android NDK to make use of.
With ExoPlayer being very rich in its features whilst being easy to use, it’s no wonder so many developers choose to use ExoPlayer in their apps.[/vc_column_text][/vc_column][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” scene_position=”center” text_color=”dark” text_align=”left” overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none”][vc_column column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” width=”1/1″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][vc_column_text]
Getting Started
Start by making sure you have the Google and JCenter repositories in your root build.gradle
file.
repositories { google() jcenter() }
Then add the ExoPlayer dependency to your app/build.gradle
file.
implementation 'com.google.android.exoplayer:exoplayer:2.X.X'
Do find the latest version on the ExoPlayer Github page.
The above dependency includes the full ExoPlayer library, but if you want to optimise even further, you can reduce the size taken by the library by importing only the modules you need.
implementation 'com.google.android.exoplayer:exoplayer-core:2.X.X' implementation 'com.google.android.exoplayer:exoplayer-dash:2.X.X' implementation 'com.google.android.exoplayer:exoplayer-ui:2.X.X'
Check out the ExoPlayer Github page for more details on individual modules.
Finally, if not already enabled, make sure you have Java 8 support in all files depending on ExoPlayer by adding this code to the android
section.
compileOptions { targetCompatibility JavaVersion.VERSION_1_8 }[/vc_column_text][/vc_column][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” scene_position=”center” text_color=”dark” text_align=”left” overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none”][vc_column column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” width=”1/1″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][vc_column_text]
Initialise the Player
In your activity’s XML layout file, add the PlayerView object
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/player_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
In your activity, declare your player as a global variable and initialise it like so
private var player: ExoPlayer? = null private fun initialisePlayer() { player = SimpleExoPlayer.Builder(this).build() player_view.player = player }
SimpleExoPlayer
is an implementation of ExoPlayer
that uses default renderer components.[/vc_column_text][/vc_column][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” scene_position=”center” text_color=”dark” text_align=”left” overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none”][vc_column column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” width=”1/1″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][vc_column_text]
Playing Music/Video
To play audio or video, you need to build a data source. DefaultDataSourceFactory
will suit our needs for now, but there are a number of different data source factories we can choose from which include ProgressiveMediaSource
, CacheDataSourceFactory
, and DashMediaSource
among others.
I won’t go into detail about any of them now as that could well be its own article.
private fun buildMediaSource(uri: Uri): MediaSource { val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(this, "user-agent") return ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(uri) }
The user-agent is the user-agent that will be used when making the HTTP request for the media file.
After that, update your initialisePlayer
with the following code
private fun initialisePlayer() { player = SimpleExoPlayer.Builder(this).build() player_view.player = player val uri = Uri.parse(getString(R.string.media_url_mp3)) val mediaSource = buildMediaSource(uri) }
uri
here should be the url of your media file on the web.
If you need a quick one to test with right here, try this:
https://storage.googleapis.com/exoplayer-test-media-0/Jazz_In_Paris.mp3
Or for video:
https://storage.googleapis.com/exoplayer-test-media-0/BigBuckBunny_320x180.mp4
(The above link points to the Big Buck Bunny video provided by the Blender Foundation)[/vc_column_text][/vc_column][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” scene_position=”center” text_color=”dark” text_align=”left” overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none”][vc_column column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” width=”1/1″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][vc_column_text]
Dealing with the Activity Lifecycle
Audio/Video streaming can be quite memory intensive. ExoPlayer is no different. We need to make sure the app isn’t hogging any resources when they’re not in use.
Override onStart
, onResume
, onPause
, and onStop
methods of your activity.
private var playWhenReady = true private var currentWindow = 0 private var playbackPosition: Long = 0 override fun onStart() { super.onStart() if (Util.SDK_INT > 23) { initializePlayer() } } override fun onResume() { super.onResume() hideSystemUi() if (Util.SDK_INT <= 23 || player == null) { initializePlayer() } } override fun onPause() { super.onPause() if (Util.SDK_INT <= 23) { releasePlayer() } } override fun onStop() { super.onStop() if (Util.SDK_INT > 23) { releasePlayer() } } private fun hideSystemUi() { player_view.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) } private fun releasePlayer() { if (player != null) { playbackPosition = player.currentPosition currentWindow = player.currentWindowIndex playWhenReady = player.playWhenReady player.removeListener(playbackStateListener) player.release() player = null } }
Android API 24 and higher support multiple windows. Your app can be visible but not active whilst in split window mode so you need to initialise the player in onStart
.
Below API 24 however, the system requires you to wait as long as possible until you grab resources so you wait until onResume
to initialise the player.
hideSystemUi
is a helper method that allows you to have a full-screen experience.
releasePlayer
is a method that frees up resources, put in either onPause
or onStop
, based on the same multiwindow-related reasons as initialising the player above.
In case your activity doesn’t get destroyed before the user goes back to it, you save the playWhenReady
, currentWindow
, and playbackPosition
to allow the user to play the audio/video from where they left off.[/vc_column_text][/vc_column][/vc_row][vc_row type=”in_container” full_screen_row_position=”middle” scene_position=”center” text_color=”dark” text_align=”left” overlay_strength=”0.3″ shape_divider_position=”bottom” bg_image_animation=”none”][vc_column column_padding=”no-extra-padding” column_padding_position=”all” background_color_opacity=”1″ background_hover_color_opacity=”1″ column_link_target=”_self” column_shadow=”none” column_border_radius=”none” width=”1/1″ tablet_width_inherit=”default” tablet_text_alignment=”default” phone_text_alignment=”default” column_border_width=”none” column_border_style=”solid” bg_image_animation=”none”][vc_column_text]
Final Preparation
All you need to do now is supply the information from the global variables you defined earlier when you initialise your player like so.
private fun initialisePlayer() { player = SimpleExoPlayer.Builder(this).build() player_view.player = player val uri = Uri.parse(getString(R.string.media_url_mp3)) val mediaSource = buildMediaSource(uri) player.setPlayWhenReady(playWhenReady); player.seekTo(currentWindow, playbackPosition); player.prepare(mediaSource, false, false); }
setPlayWhenReady
tells the player to start playing as soon as the resources for playback have been acquired. We set this to initially be true
so playback starts as soon as the activity is launched
seekTo
tells the player to seek to a specific position within a specific window. Having both currentWindow
and playbackPosition
initialised at zero means that playback starts from the start of the video when the activity is launched
prepare
tells the player to acquire all the resources for the given mediaSource
. The other parameters here are resetPosition
and resetState
which we set to false because we already handled those in the preceding lines
Now because of the way the player has been set up, once you call prepare
, the player will start acquiring resources from the data source and then automatically play your audio / video.
More Coming Up
We only scratched the basics of ExoPlayer. There is so much to cover with this one library with regards to data sources, customising the player UI, adaptive streaming and such.
Expect more ExoPlayer content in the following weeks. If you especially like ExoPlayer, or if you think there are contenders that can tell ExoPlayer to sit down, leave it down in the comments. And as always, happy coding ༼ つ ◕_◕ ༽つ[/vc_column_text][/vc_column][/vc_row]