StackOverflower
StackOverflower

Reputation: 5761

Issue with MediaPlayer buffering time when streaming audio

I'm using MediaPlayer to stream a radio over HTTP. On Lollipop my stream takes about a minute to start which is unacceptable. It takes about 20 seconds on Kitkat, which is already a pain but now became unusable.

There is a well known problem with this component related to buffering: the amount of bytes to buffer is harcoded and can't be changed.

My code is really standard

player.reset();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource(streamUrl);
player.prepareAsync();

And on prepared I do

player.start();

I've heard about alternatives as GStreamer but I couldn't make it work on Windows.

I wonder if anyone has a working solution to stream radio over HTTP with a decent start delay.

EDIT

I tested ExoPlayer but the lower start time I get is 15 seconds. The player is stuck on "preparing" state (not buffering, that's later so far I see).

EDIT

The format of the stream is AAC

EDIT

I tested https://code.google.com/p/aacdecoder-android/ but the only problem this library has is the lack of support to stream pause. It's a requirement of my application to support pause on online stream.

Upvotes: 10

Views: 17015

Answers (7)

irfan Hussain
irfan Hussain

Reputation: 9

This is for mp3 media player only we can use this code

 mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
            public void onBufferingUpdate(MediaPlayer mp, int percent)
            {
                double ratio = percent / 100.0;
                int bufferingLevel = (int)(mp.getDuration() * ratio);
                seekBar.setSecondaryProgress(bufferingLevel);
            }
        });

Upvotes: 0

Kai
Kai

Reputation: 15476

If your use case is compatible with GPL/LGPL licenses, then VLC should be exactly what you need. VLC is able to stream from your URL on a 3G network with only ~1 sec delay.

Step 1: Download VLC source code and compile per the instruction

Step 2: The most important class is org.videolan.vlc.audio.AudioServiceController, which was called from org.videolan.vlc.gui.MRLPanelFragement.processUri() --> org.videolan.vlc.util.Util.openStream(Context, String) --> AudioServiceController.load(String, boolean). You can remove all the unnecessary code other than AudioServiceController and its support classes to slim down the size

Upvotes: 10

IndieTech Solutions
IndieTech Solutions

Reputation: 2541

If you are willing to spend some $ on a library , I recommend Bass It has a full set of API calls that you can integrate and also a solid documentation. There is a shareware version that you can test.

If you are not willing to spend $. I highly recommend VLC @Kai mentioned, also in the future you can expand your application to stream video with it. I worked with the API before to perform a live stream for my aquarium. @Kai provided you with the necessary links.

Check out this link for more info.

Upvotes: 0

CptEric
CptEric

Reputation: 907

i'll post how i do it and hoe it gives a difference. it's not a realtime sound item ( it's a mp3 from an online api, but it's about 4-6mb) so it could vary, but takes less than 3-5 seconds to load on my genimotion VM.

i know it's almost the same as your code. maybe if you could share the url or a similar one giving the same problems i could test it in my app.

runThread(url);//ran on the oncreate.


 private void runThread(final String url) {
    new Thread() {
        public void run() {
            mediaPlayer  = new MediaPlayer();//mediaplayer is a global variable.
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

                try{
                    mediaPlayer.setDataSource(url);

                    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                        @Override
                        public void onCompletion(MediaPlayer mediaPlayer) {
                            //audio did finish.

                        }
                    });
                    mediaPlayer.prepare(); // might take long! (for buffering, etc)
                    duration = mediaPlayer.getDuration();
                    mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {

                                    //here you should start playing it.
                                }
                            });
                        }
                    });
                }
                catch(Exception e)
                {

                }


            }
    }.start();
}

tested on a nexus 4 with jelly bean, similar time responses.

Upvotes: 0

shri
shri

Reputation: 874

There are 2 kinds of delay in streaming a. is the Buffering delay which is the startup delay and b. is the broadcast delay.

In the case of media player, the stream is taking 1 minute to buffer. So we first need to see how the time taken to fill the buffer can be reduced. I am not sure if that is possible in the Media player code of Android to configure the buffer size.

However if we try to use AAC decoder library for android (https://code.google.com/p/aacdecoder-android/downloads/detail?name=aacdecoder- android-0.8.zip) then we have the provision to fill the input buffer.

Pl. refer to the code snippet below, you can fill your input buffer capacity, based on your requirement and then you can start the playback. Since we have control on the input buffer capacity we can try to reduce time delay to start the playback. Pl. check if this can help you.

 /**
 * Sets the audio buffer (AudioTrack) capacity.
 * The capacity can be expressed in time of audio playing of such buffer.
 * For example 1 second buffer capacity is 88100 samples for 44kHz stereo.
 * By setting this the audio will start playing after the audio buffer 
   is    first filled.
 *
 * NOTE: this should be set BEFORE any of the play methods are called.
 *
 * @param audioBufferCapacityMs the capacity of the buffer in milliseconds
 */
  public void setAudioBufferCapacityMs( int audioBufferCapacityMs ) {
    this.audioBufferCapacityMs = audioBufferCapacityMs;
  }

Upvotes: 0

Bojan Kseneman
Bojan Kseneman

Reputation: 15668

You should avoid media player for live radio streams.

I have used the following library and it works great: https://code.google.com/p/aacdecoder-android/

Upvotes: 1

Dekra
Dekra

Reputation: 572

I can suggest to switch from MediaPlayer to ExoPlayer. With ExoPlayer is feasible to setup buffering params as following:

public static ExoPlayer newInstance(int rendererCount, int minBufferMs, int minRebufferMs) {
  return new ExoPlayerImpl(rendererCount, minBufferMs, minRebufferMs);
}

minBufferMS means a minimum duration of data that must be buffered for playback to start or resume following a user action such as a seek.

minRebufferMs means a minimum duration of data that must be buffered for playback to resume after a player invoked rebuffer (i.e. a rebuffer that occurs due to buffer depletion, and not due to a user action such as starting playback or seeking).

Default values are 500 and 5000, respectively.

Upvotes: 3

Related Questions