Issue with MediaPlayer buffering time when streaming audio
Asked Answered
R

7

10

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.

Rickyrico answered 3/4, 2015 at 13:6 Comment(6)
What bitrate does your stream use? e.g. 32 kbps 64 kbps etc.Brookite
@Simas: it uses 32 kbps. I know this would improve with a bigger bitrate, but doesn't seem like a real solutionRickyrico
What format of audio are you playing, AAC?Earlap
@BojanKseneman: yes, AAC.Rickyrico
Is a web api an option?Salvo
@Alundra the dreamwalker: not if there is any suitable option client side :) Let's say that's a last option.Rickyrico
O
10

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

Ope answered 11/4, 2015 at 14:22 Comment(14)
I've never heard about this, I'll be testing this solution. ThanksRickyrico
kai in VLC player we have the option to perform pause on live streaming. can you pl. clarifyCassilda
@Kai: do you know if there is a working example using android studio? I'm not sure if I have time to test this solution before the bounty forces me to pick a winner. As shri said, it is mandatory to have a solution supporting pause.Rickyrico
@Rickyrico can you clarify what kind of behavior do you wish from pausing a live stream? Do you mean that I can pause a live stream for x seconds, and the player should buffer it and play it back when I hit play again?Ope
@Rickyrico Just tested it and it does support pause as described up, kinda surprised. I don't know if the length of this buffer can be adjusted or not though.Ope
Kai, that's correct. While the requirement is to pick up where you left off, that's a little crazy and I probably can convince them to abandon the idea. When you play initialy the server sends an ad before the stream. It's enough with avoid this ad being sent on every play. If I use stop, the ad will be sent when play is hit, that's the main reason behind the pause requirement: avoid the adRickyrico
It would be great to see a working example as I don't have very much time today to test it. I'd like to award you the bounty in case this works but I'm not sure If I'll make it on time. I wish you posted this earlier :)Rickyrico
I'll package the version I have working for you to download, but it only works in Linux and probably need all the necessary tools installed for it to be able to function correctly.Ope
@Kai: that sounds complicated. Here I have something that could be a working demo for android studio. I'll be checking about it at some point today. ThanksRickyrico
Let us continue this discussion in chat.Ope
Do you have native libraries for different platforms? That project only have arm. ThanksRickyrico
@Rickyrico Let us continue this discussion in chat.Ope
Thank kai for verifying and confirming the support for pauseCassilda
You can now find libvlc in Maven: search.maven.org/artifact/org.videolan.android/libvlc-all. The class names have changed a bit since this answer. Use org.videolan.libvlc.LibVLC, org.videolan.libvlc.MediaPlayer, and org.videolan.libvlc.Media. The API is fairly intuitive!Stacystadholder
M
3

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.

Megaera answered 6/4, 2015 at 6:23 Comment(8)
Do you have a complete sample showing buffering setting? I remember I tested ExoPlayer some months ago and I couldn't find a way to make any progress on this topic. I could have failed to see it though.Rickyrico
Here is a demo app of ExoPlayer where you can easily test buffering status github.com/google/ExoPlayer/tree/master/demoMegaera
Thanks, I'll be testing that. In any case I wish you have any authorative source stating that ExoPlayer fixes this problem. I was following this issue on google play and no one ever mentioned ExoPlayer. I'll find it out though :)Rickyrico
By "I was following this issue on google play" I meant to say "I was following this issue on google CODE" (the one I pasted a link above)Rickyrico
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). I'd say that's why I didn't advance with this player when I tested it some months ago: by that time it wasn't any improvement in comparison to what I hadRickyrico
Can you share the link you are testing against?Megaera
It seems that your sample code is for Exoplayer 1. I could not find ExoPlayerImpl in Exoplayer 2.Chairwoman
With ExoPlayer 2 (r2.1.3) on Android 6.0.1, testing with mp3, 96kbps streams from radio.abc.net.au/help/streams I see minimal delays (<2sec) where as with mediaPlayer on same streams I get ~15-30sec delays.Deering
E
1

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/

Earlap answered 12/4, 2015 at 20:9 Comment(6)
"You should avoid media player for live radio streams". - just out of curiosity: why? Are there any docs/articles/whatever about this?Vinculum
We have noticed problems with media player on quite a few devices. Tough the issues may be codec related, but using the above library seemed to work on those devices.Earlap
Bojan Is there a way to configure the input buffer size in the acc decoderCassilda
Of course. There are two methods aacPlayer.setAudioBufferCapacityMs(343); aacPlayer.setDecodeBufferCapacityMs(3242); Note I just entered some dumb valuesEarlap
Thanks for your answer. I tested this library some months ago and is perfect except for one thing: it does't allow pausing the stream, only allows stop. Unfortunately this makes a difference on my appRickyrico
Yes that is true, we were using stop for resume and playAsync for resumeEarlap
C
0

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;
  }
Cassilda answered 13/4, 2015 at 11:9 Comment(3)
Thanks for your answer. I tested this library some months ago and is perfect except for one thing: it does't allow pausing the stream, only allows stop. Unfortunately this makes a difference on my appRickyrico
Ok , my understanding is on real time streaming, we normally do not perform pause. When we do a playback from a recorded content then pausing the content is required.Cassilda
I kind of agree, but my requirement is different. I need to allow pause over a live stream. Thanks!Rickyrico
V
0

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.

Vidette answered 13/4, 2015 at 14:56 Comment(0)
S
0

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.

Salvo answered 13/4, 2015 at 15:4 Comment(0)
S
0

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);
            }
        });
Supersensible answered 21/10, 2022 at 6:12 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.