Recently I’ve been working on a media player application in my previous freelancing project. The application includes so much online, offline audio and video streaming. So, I tried to use Android framework classes such as MediaPlayer and AudioPlayer to play media files. As it turned out after so many hours of frustration, MediaPlayer sends out weird exceptions and  I could not see what certain crashes are happening. MediaPlayer has written natively, impossible to debug or figure out exactly what exception is happening. So, after that, I searched again and find out about ExoPlayer.  

What is ExoPlayer

ExoPlayer is an application level Media Player developed and maintained by Google. It is written in Java and it relies on low-level media. It provides so many customization options including HLSMediaSource, DashMediaSource, MP4, and others. It is used by Google apps like YouTube and Google Play Movies. 

Note: ExoPlayer only supports Android version 4.1 and above.

Android App Setup

Open the app level build.grdle file and add the ExoPlayer dependency. The ExoPlayer dependency is split into modules to allow developers to import only required dependency. If you want to learn about modularization see this post.

Below is the complete dependency of ExoPlayer.

implementation 'com.google.android.exoplayer:exoplayer:2.X.X'    // Replace X with current version.

By adding modular approach dependency your application size will be smaller and you won’t need some modules which you don’t use.

Below is the modular dependencies of ExoPlayer.

 
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'

You have to choose which dependency you need according to your application. If you don’t know what modular dependency you required just add a complete dependency.

So, we add ExoPlayer to our app now we can play audio and video in our app seamlessly.

Play Online Audio Song

Let’s see how we can play audio song online. Below is the example of how to setup ExoPlayer for an online audio song.

BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
TrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
DataSource.Factory dateSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, getPackageName()), bandwidthMeter);
MediaSource mediaSource = new ExtractorMediaSource(Uri.parse("www.musicper.com/tere-bin.mp3"), dateSourceFactory, extractorsFactory, new Handler(), Throwable::printStackTrace);    // replace Uri with your song url
exoPlayer = ExoPlayerFactory.newSimpleInstance(this, new DefaultTrackSelector(trackSelectionFactory));
exoPlayer.prepare(mediaSource);

You guys must be thinking what on earth is this, but don’t worry most of it is a default. There is no need to spend much time to understand it. I’m afraid I have to explain this, that if you don’t want you can skip this and continue from here.

Below is the first line of code.

BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();

DefaultBandwidthMeter class implies estimated available network bandwidth based on measured download speed.

Below is the second line of code.

final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

An ExtractorFactory is there for providing an array of the extractor for the media formats. You can see the list of formats providing by ExtractorFactory here. 

Below is the third line of code.

TrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);

AdaptiveTrackSelection.Factory is a bandwidth based adaptive TrackSelectionIt gives the highest quality state of a buffer according to your network condition.

Below is the fourth line of code.

DataSource.Factory dateSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, getPackageName()), defaultBandwidthMeter);

DefaultDataSourceFactory supports almost all non-adaptive audio video formats supported on Android. It will recognize our mp3 file and play it nicely. You can learn more about DefaultDataSourceFactory here.

Below is the fifth line of code.

MediaSource mediaSource = new ExtractorMediaSource(Uri.parse("www.musicper.com/tere-bin.mp3"), dateSourceFactory, extractorsFactory, new Handler(), Throwable::printStackTrace);   // Replace Uri with your song url

ExtractorMediaSource is the main part where all of our previous objects concat in it. It is suitable for regular media files. It is representing the media which we’re going to play.

Below is the sixth line of code.

exoPlayer = ExoPlayerFactory.newSimpleInstance(this, new DefaultTrackSelector(trackSelectionFactory));

In here we’re only creating an instance of ExoPlayer.  A factory for ExoPlayer instance. For to read more about ExoPlayer see this link.

Below is the seventh line of code.

exoPlayer.prepare(mediaSource);

You see in here we’re setting media source to our ExoPlayer instance. So, now we created the SimpleExoPlayer instance as an object to make it accessible to all methods in the class.

Now it’s time to see how we can play some music with the ExoPlayer instance. After preparing the media source we just need to set the boolean value to an ExoPlayer instance.

Below is the example of how to play a song.

exoPlayer.setPlayWhenReady(true);

The setPlayWhenReady method will start the media when it is ready. If the player is already in the ready state then this method can be used to pause and resume playback.

You can also mute or unmute with an ExoPlayer instance.

exoPlayer.setVolume(0f);              // It is used for mute
exoPlayer.setVolume(1f);              // It is usedfor unmute

We have to release our player when no longer in use to save resources. The following shows how to release the player.

if (player!=null) {
        player.release();
        player = null;
    }

Playlist Of Online Audio Song

Sometimes we need to play songs in a list. For this purpose, we can use ConcatenatingMediaSource instead of ExtractorMediaSourceThe following shows how we can make ConcatenatingMediaSource of a list of songs.

BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
TrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
DataSource.Factory dateSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, getPackageName()), bandwidthMeter);
MediaSource[] mediaSources = new MediaSource[songList.size()];
for (int i = 0; i < mediaSources.length; i++) {
    String songUri = songList.get(i).getUri();
    mediaSources[i] = new ExtractorMediaSource(Uri.parse(songUri), dateSourceFactory, extractorsFactory, null, Throwable::printStackTrace);
}
MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]
        : new ConcatenatingMediaSource(mediaSources);
exoPlayer = ExoPlayerFactory.newSimpleInstance(this, new DefaultTrackSelector(trackSelectionFactory));
exoPlayer.prepare(mediaSource);

To have a callback when the new song is going to play, something bad happened during playing, the song is buffering and position discontinuity. If you want to get notified every time when these things happened you need to add a listener to an exoPlayer instance.

The following shows how you can add the listener to an exoPlayer.

exoPlayer.addListener(new Player.EventListener() {
            @Override
            public void onTimelineChanged(Timeline timeline, Object manifest) {
            }

            @Override
            public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
            }

            @Override
            public void onLoadingChanged(boolean isLoading) {
            }

            @Override
            public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            }

            @Override
            public void onRepeatModeChanged(int repeatMode) {
            }

            @Override
            public void onPlayerError(ExoPlaybackException error) {
            }

            @Override
            public void onPositionDiscontinuity() {
            }

            @Override
            public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
            }
        });

Play Offline Audio Streaming

Playing offline audio song pretty much the same playing song online.

Below is the example of how you can play the offline song.

RenderersFactory renderersFactory = new DefaultRenderersFactory(this, null, DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);
TrackSelector trackSelector = new DefaultTrackSelector();
ExtractorFactory extractorFactory = new DefaultExtractorsFactory();
DataSource dataSource = new DefaultDataSourceFactory(this,Util.getUserAgent(this, "ExoPlayerIntro"));
MediaSource mediaSource = new ExtractorMediaSource(uri, dataSource, extractorFactory, new Handler(), Throwable::printStackTrace);
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector);
simpleExoPlayer.prepare(mediaSource);
simpleExoPlayer.setPlayWhenReady(true);

You see, this is the same except for DefaultRenderersFactory instance. For offline streaming, we just need to add EXTENSION_RENDERER_MODE_OFF. 

Playlist Of Offline Audio Streaming

Now, it’s time to see how we can play the playlist of offline songs. I’m pretty sure if you guy’s working on media player app this would have been your requirement.

Below is the example of how to play the playlist of offline songs.

RenderersFactory rederersFactory = new DefaultRenderersFactory(this, null, DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);
TrackSelector trackSelector = new DefaultTrackSelector();
ExtractorFactory extractorFactory = new DefaultExtractorsFactory();
DataSource dataSource = new DefaultDataSourceFactory(this,Util.getUserAgent(this, "ExoPlayerIntro"));
MediaSource[] mediaSources = new MediaSource[songList.size()];
for (int i = 0; i < mediaSources.length; i++) {
       String s = songList.get(i).getSongId();
       mediaSources[i] = new ExtractorMediaSource(Uri.parse(s), dateSourceFactory, extractorsFactory, null, Throwable::printStackTrace);
}
MediaSource mediaSource = mediaSources.length == 1 ? mediaSources[0]: new ConcatenatingMediaSource(mediaSources);
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector);
simpleExoPlayer.prepare(mediaSource);
simpleExoPlayer.setPlayWhenReady(true);

That’s, it guys this is my explanation about playing audio song online and offline with ExoPlayer.

I hope this blog gives you a good understanding of how to play the audio song with ExoPlayer. If you’ve any queries please do comment below.

Thank you for being here and keep reading.

You might be Interested In: QRCode Generator And Reader Android Example

Author

I’m a mobile product devsigner (i.e. I consider myself as both a developer and a designer) and user experience/interface engineer. I’m an expert on the Android platform and have been recognized as it by the community.

7 Comments

  1. what if i want to show notification of current song playing notification bar allow user to control song from notification panel like play, pause, next song,previous song and close the notification using exo player only…

  2. Sunny Saini Reply

    Hey,

    Is there any way to cache the audio file which is streamed online?
    The requirement is to forward and backward the audio which was cache locally on android device.

    TIA

    • Ahsen Saeed Reply

      Hey, you just need to copy the online audio song code and paste in your Fragment onCreateView. The last thing doesn’t forget to add the setPlayWhenReady to true and please add the valid online audio song url.

    • Ahsen Saeed Reply

      I didn’t make the sample app for this. To test the code you just need to copy and paste the Online or Offline Streaming code in onCreate and then the audio song will be played after that.

  3. Many Thanks, very helpful.
    I need function to add or remove playlist items (media sources) without release player or initialize player.
    Can you make this function?

Write A Comment