Android ExoPlayer Title Image
| | |

Online Offline Audio Streaming With ExoPlayer

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

Similar Posts

10 Comments

  1. Hi, if i have the list of url songs in a json into my raw folder, how can i do that with exoplayer? if im using a recyclerview to show the name of the song. thanks for your time

    1. Hey tuski,
      First you need to read the raw folder file.
      InputStream inputStream = resources.openRawResource(R.raw.rawfile);
      Scanner scanner = new Scanner(inputStream);
      StringBuilder stringBuilder = new StringBuilder();
      while (scanner.hasNextLine())
      stringBuilder.append(scanner.nextLine());
      JSONObject jsonObject = new JSONObject(stringBuilder.toString());

      After reading the raw file simply use the above code for online and offline exoplayer streaming.

Comments are closed.