Categories
android blog kotlin

Building a podcast app series: 3. Exoplayer

What is a podcast app if not a wrapper around a media player? And, if we talk Android, there is the only one media player worth considering, ExoPlayer, made by Google engineers. Let’s look at how can we connect all the pieces we have built so far and actually connect the ExoPlayer with the view within the app.

ExoPlayer

Exoplayer is very powerful and modular, we are going to use just a fraction of what ExoPlayer really offers. ExoPlayer has a couple of core components that have to work together for it to play anything, in no particular order:

  1. ExoPlayer instance
  2. MediaSource

We need to create an ExoPlayer instance and hold it in memory since it is pretty expensive to create. We will reuse a single instance throughout the app. For it to play anything, we need to create a MediaSource. These sources are basically different types of streams that ExoPlayer has to read in order to fetch the audio data and play it. There are other important parts to the ExoPlayer ecosystem but for starters, we need those two basic things.

ExoPlayer instance

This is the heart of ExoPlayer and the object itself. We can simply create a single instance and pass or not pass a bunch of configuration options. Let’s keep it simple and create a basic instance:

val player = SimpleExoPlayer.Builder(context).build()

MediaSource

So the name of this class is pretty self-explanatory, we have to be aware of the fact that there are a couple of different media sources, depending on the actual source that serves the content:

  • DashMediaSource for DASH.
  • SsMediaSource for SmoothStreaming.
  • HlsMediaSource for HLS.
  • ProgressiveMediaSource for regular media files.

Let’s create a simple media source:

val mediaSource =
   ProgressiveMediaSource.Factory(dataSourceFactory).
        createMediaSource(Uri.parse(it.mp3Url))        
  exoPlayer.prepare(mediaSources)

And that’s it. We can now play an episode!

Since we are building a podcast player, it is safe to assume we will never play one episode at a time, so we need a way to tell ExoPlayer to play the next item when one item is finished playing. To handle that, ExoPlayer has a concept of the concatenated media source. We can bundle together a bunch of media sources, they don’t have to be of the same type, and attach that source to the ExoPlayer instance.

val mediaSources = (listOf(currentEpisode) + _playlist).map {
   ProgressiveMediaSource.Factory(dataSourceFactory).
        createMediaSource(Uri.parse(it.mp3Url))        
   }.toTypedArray()
exoPlayer.prepare(ConcatenatingMediaSource(*mediaSources)

So instead of passing just one media source, we can pass in a concatenating media source and the ExoPlayer will automatically play all episodes from that playlist.

Browse the full code on this link and in the next article, we will talk about a foreground service that needs to run our ExoPlayer and keep our app in the background so Android does not shut down our app to claim more resources :).

Leave a Reply

Your email address will not be published. Required fields are marked *