Android playing Audio & Video using ExoPlayer

Android Exoplayer allows you to play or stream audio and video files efficiently. Unlike Android’s built-in MediaPlayer, ExoPlayer offers more control and customization over playback, buffering strategies and playlist management. It support various multimedia formats like MP4, MP3, DASH, HLS, SmoothStreaming. It started as standalone project by Google and later migrated into Jetpack Media3 APIs.


In this article we'll see a basic example on how the player can be integrated in your app.
Android exoplayer

1. Getting started

To get started, add the exoplayer dependencies to your project. Find the latest version of exoplayer from here
build.gradle

dependencies {
    ....

    // exoplayer
    implementation("androidx.media3:media3-exoplayer:1.4.1")
    implementation("androidx.media3:media3-ui:1.4.1")
    implementation("androidx.media3:media3-exoplayer-dash:1.4.1")
}
  
Once the dependencies are added, the player components are ready to be used in the app. Below are the keypointers on how the player can be used.
  1. Add the player to your xml layout using PlayerView component.
  2. In your activity create the player instance using ExoPlayer.Builder() and the attach the player to the PlayerView component that is added in xml
  3. Prepare the media(s) that needs to be played using MediaItem.Builder() method.
  4. Add the media items to the player and call prepare() to play the media.

2. Sample URLs

Below are the few sample URLs that you can use to experiment with ExoPlayer.

val dashUrl = "https://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0"

val mp4Url =
        "https://firebasestorage.googleapis.com/v0/b/project-8525323942962534560.appspot.com/o/samples%2Fsample2.mp4?alt=media&token=2f09078b-6c87-4159-9054-73c9b88d665b"

val mp3Url = "https://firebasestorage.googleapis.com/v0/b/project-8525323942962534560.appspot.com/o/samples%2Fnightfall-future-bass-music-228100.mp3?alt=media&token=32821471-654b-4a9e-9790-1e9c7d1cc584"

val mediaUrl1 =
        "https://firebasestorage.googleapis.com/v0/b/project-8525323942962534560.appspot.com/o/samples%2Fnightfall-future-bass-music-228100.mp3?alt=media&token=32821471-654b-4a9e-9790-1e9c7d1cc584"

val mediaUrl2 =
        "https://firebasestorage.googleapis.com/v0/b/project-8525323942962534560.appspot.com/o/samples%2Fsample2.mp4?alt=media&token=2f09078b-6c87-4159-9054-73c9b88d665b"

val mediaUrl3 =
        "https://firebasestorage.googleapis.com/v0/b/project-8525323942962534560.appspot.com/o/samples%2Fin-slow-motion-inspiring-ambient-lounge-219592.mp3?alt=media&token=8c4e73cb-97c6-4163-9cfe-0728dbecf076"

val mediaUrl4 =
        "https://firebasestorage.googleapis.com/v0/b/project-8525323942962534560.appspot.com/o/samples%2Fnight-detective-226857.mp3?alt=media&token=4f6ade23-0aaf-4afc-acb9-645540f2fe87"
    

3. Basic example - Playing Mp3, Mp4, Dash & Playlist

Now let's see this in action by creating simple player that can play few media types like mp3, mp4, dash or a playlist.
  1. Create a new activity named PlayerActivity and add the PlayerView component to its xml layout
    activity_player.xml
    
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/black">
    
        <androidx.media3.ui.PlayerView
            android:id="@+id/player_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
        
  2. Open the activity file and do the below changes.
    1. First the player instance is built using ExoPlayer.Builder() and attached to xml player component
    2. The media item is perpared using MediaItem.Builder() and set to player using setMediaItems().
    3. By calling prepare(), player will load the media and ready to play. Here by setting playWhenReady=true, the player will autoplay the media once it's ready
    4. And most importantly the player holds the video decoders and other resources that are limited on the device. These should be released when no longer needed by the app to be able to used by other apps. This can be done by calling release() method. Usually we do this in onPause(), onStop() methods.
    PlayerActivity.kt
    
    package info.androidhive.exoplayer
    
    import android.os.Bundle
    import android.widget.Toast
    import androidx.activity.enableEdgeToEdge
    import androidx.appcompat.app.AppCompatActivity
    import androidx.media3.common.MediaItem
    import androidx.media3.common.MimeTypes
    import androidx.media3.common.Player
    import androidx.media3.exoplayer.ExoPlayer
    import info.androidhive.exoplayer.databinding.ActivityPlayerBinding
    
    class PlayerActivity : AppCompatActivity() {
        private val binding by lazy(LazyThreadSafetyMode.NONE) {
            ActivityPlayerBinding.inflate(layoutInflater)
        }
        private var player: Player? = null
        private var playWhenReady = true
        private var mediaItemIndex = 0
        private var playbackPosition = 0L
        private val mp4Url =
            "https://firebasestorage.googleapis.com/v0/b/project-8525323942962534560.appspot.com/o/samples%2Fsample2.mp4?alt=media&token=2f09078b-6c87-4159-9054-73c9b88d665b"
    
        private val playbackStateListener: Player.Listener = object : Player.Listener {
            override fun onPlaybackStateChanged(playbackState: Int) {
                super.onPlaybackStateChanged(playbackState)
                when (playbackState) {
                    ExoPlayer.STATE_IDLE -> {}
                    ExoPlayer.STATE_BUFFERING -> {}
                    ExoPlayer.STATE_READY -> {}
                    ExoPlayer.STATE_ENDED -> {}
                }
            }
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            enableEdgeToEdge()
            setContentView(binding.root)
        }
    
        private fun initializePlayer() {
            player = ExoPlayer.Builder(this).build().also { exoPlayer ->
                binding.playerView.player = exoPlayer
                exoPlayer.trackSelectionParameters =
                    exoPlayer.trackSelectionParameters.buildUpon().setMaxVideoSizeSd().build()
                
                val mediaItem = MediaItem.Builder().setUri(mp4Url).build()
                
                exoPlayer.setMediaItems(listOf(mediaItem), mediaItemIndex, playbackPosition)
                exoPlayer.playWhenReady = playWhenReady
                exoPlayer.addListener(playbackStateListener)
                exoPlayer.prepare()
            }
        }
    
        private fun releasePlayer() {
            player?.let { player ->
                playbackPosition = player.currentPosition
                mediaItemIndex = player.currentMediaItemIndex
                playWhenReady = player.playWhenReady
                player.removeListener(playbackStateListener)
                player.release()
            }
            player = null
        }
    
        public override fun onStart() {
            super.onStart()
            initializePlayer()
        }
    
        public override fun onResume() {
            super.onResume()
            if (player == null) {
                initializePlayer()
            }
        }
    
        public override fun onPause() {
            super.onPause()
            releasePlayer()
        }
    
        public override fun onStop() {
            super.onStop()
            releasePlayer()
        }
    }   
        
  3. Open AndroidManifest.xml and add INTERNET permission as we are playing the media from a remote URL. Add configChanges flags to avoid activity restarts when the device orientation changes.
    AndroidManifest.xml
    
      <uses-permission android:name="android.permission.INTERNET" />
      
      <activity
                android:name=".PlaylistActivity"
                android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
    
Now if you run the app, you should see the Mp4 video playing.
Android exoplayer playing videos

4. Playing HLS, DASH videos

Usually player can play these videos if url ends with the extension like .mp4 or .m3u8. If not, we need to manually set the MIME type as shown below.

// Dash video
MediaItem.Builder().setUri(mediaUrl).setMimeType(MimeTypes.APPLICATION_MPD)

// HLS video
MediaItem.Builder().setUri(mediaUrl).setMimeType(MimeTypes.APPLICATION_M3U8)
You can also further customize the media item by using MediaSource.Factory(). Below a dash media source is created using DashMediaSource

val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
        
// Prepare dash media source
val mediaSource: MediaSource =
            DashMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(mediaUrl))
            
exoPlayer.setMediaSource(mediaSource)
exoPlayer.prepare()

You can do the same for HLS videos using HlsMediaSource. For this you need to add exoplyer's hls module first.

implementation("androidx.media3:media3-exoplayer-hls:1.4.1")


val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
        
// Prepare dash media source
val mediaSource: MediaSource =
            HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(mediaUrl))
            
exoPlayer.setMediaSource(mediaSource)
exoPlayer.prepare()

5. Playing a playlist

The player is capable of playing a playlist as well. You can pass the list of media URLs to player and the player plays the next item once the current item ends. Tapping the next and previous controls on the player, plays the next or previous media item.

Here is an example of preparing a playlist. I hope we have covered the fundamentals of Exoplayer. The complete code can be found here. Let me know your queries in the comments section below.

Cheers!
Happy Coding 🤗

2 Comments

  1. Great article! The step-by-step guide on using ExoPlayer was easy to follow and super helpful. I loved the examples for different media formats and how to set up playlists. Thanks for making media playback so simple!

    ReplyDelete
Previous Post Next Post

نموذج الاتصال