88

I've been trying to stream mp3's over http using Android's built in MediaPlayer class. The documentation would suggest to me that this should be as easy as :

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(URL_OF_FILE);
mp.prepare();
mp.start();

However I am getting the following repeatedly. I have tried different URLs as well. Please don't tell me that streaming doesn't work on mp3's.

E/PlayerDriver(   31): Command PLAYER_SET_DATA_SOURCE completed with an error or info PVMFErrNotSupported
W/PlayerDriver(   31): PVMFInfoErrorHandlingComplete
E/MediaPlayer(  198): error (1, -4)
E/MediaPlayer(  198): start called in state 0
E/MediaPlayer(  198): error (-38, 0)
E/MediaPlayer(  198): Error (1,-4)
E/MediaPlayer(  198): Error (-38,0)

Any help much appreciated, thanks S

Jonik
  • 80,077
  • 70
  • 264
  • 372
Pandalover
  • 2,388
  • 3
  • 21
  • 19
  • A few questions: (1) which SDK version are you using? (2) Which device(s) are you testing on? This works fine on SDK 2.0.1, testing on a Droid. – Roman Nurik Dec 28 '09 at 21:58
  • Hi Roman, thanks for taking the time. I am trying this against 1.6 and I am using an HTC Hero. I will try it on 2.01 in in light of your comments but it would be a ridiculous outcome if this only worked on 2.x and and above devices out of he box. – Pandalover Dec 28 '09 at 22:54
  • Just tried it on a 2.01 emulator. Doesn't work unfortunately. I am intrigued to try this against a real 1.6 device and a real 2.01 device. I'm in Google testing on the 4th. Maybe I'll have to wait till then. I'd prefer not to have to though. – Pandalover Dec 28 '09 at 23:11
  • I don't suspect 2.0 vs. 2.0.1 will make any difference, but emulator vs. a live device may make a difference. I'm surprised this didn't work on the Hero. I'll look into it and see if I can get a better answer. Oh also, just as a sanity check, you should make sure you've requested the INTERNET permission in the manifest. – Roman Nurik Dec 29 '09 at 03:19
  • Hey just outta discussion I have a question. If I use mp.setDataSource(URL_OF_FILE); We do not need to save any file for the audio streaming. Isn't it? So that way its the best way to stream audio from any location. Any ideas? – Bohemian Dec 29 '09 at 06:34
  • I tried streaming audio using setDataSource(context,uri); It plays fine on the 2.01/emulator. Does 1.6 support this? – Bohemian Dec 29 '09 at 07:35
  • Roman, yes I certainly have the INTERNET permission. – Pandalover Dec 29 '09 at 10:46
  • Bohemian, what kin dof URI di you use? I assume I you know the difference between a URL and a URI? If you did get it to work using a URI can you show me how you constructed your URI, thanks. Note I am trying to hit a remote URL not some kind of local file URI though I absolutely accept that it cuold work with a remote URI. – Pandalover Dec 29 '09 at 10:49

7 Answers7

80

simple Media Player with streaming example.For xml part you need one button with id button1 and two images in your drawable folder with name button_pause and button_play and please don't forget to add the internet permission in your manifest.

public class MainActivity extends Activity {
private Button btn;
/**
 * help to toggle between play and pause.
 */
private boolean playPause;
private MediaPlayer mediaPlayer;
/**
 * remain false till media is not completed, inside OnCompletionListener make it true.
 */
private boolean intialStage = true;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn = (Button) findViewById(R.id.button1);
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    btn.setOnClickListener(pausePlay);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

private OnClickListener pausePlay = new OnClickListener() {

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        // TODO Auto-generated method stub

        if (!playPause) {
            btn.setBackgroundResource(R.drawable.button_pause);
            if (intialStage)
                new Player()
                        .execute("http://www.virginmegastore.me/Library/Music/CD_001214/Tracks/Track1.mp3");
            else {
                if (!mediaPlayer.isPlaying())
                    mediaPlayer.start();
            }
            playPause = true;
        } else {
            btn.setBackgroundResource(R.drawable.button_play);
            if (mediaPlayer.isPlaying())
                mediaPlayer.pause();
            playPause = false;
        }
    }
};
/**
 * preparing mediaplayer will take sometime to buffer the content so prepare it inside the background thread and starting it on UI thread.
 * @author piyush
 *
 */

class Player extends AsyncTask<String, Void, Boolean> {
    private ProgressDialog progress;

    @Override
    protected Boolean doInBackground(String... params) {
        // TODO Auto-generated method stub
        Boolean prepared;
        try {

            mediaPlayer.setDataSource(params[0]);

            mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

                @Override
                public void onCompletion(MediaPlayer mp) {
                    // TODO Auto-generated method stub
                    intialStage = true;
                    playPause=false;
                    btn.setBackgroundResource(R.drawable.button_play);
                    mediaPlayer.stop();
                    mediaPlayer.reset();
                }
            });
            mediaPlayer.prepare();
            prepared = true;
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            Log.d("IllegarArgument", e.getMessage());
            prepared = false;
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        }
        return prepared;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        if (progress.isShowing()) {
            progress.cancel();
        }
        Log.d("Prepared", "//" + result);
        mediaPlayer.start();

        intialStage = false;
    }

    public Player() {
        progress = new ProgressDialog(MainActivity.this);
    }

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        this.progress.setMessage("Buffering...");
        this.progress.show();

    }
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    if (mediaPlayer != null) {
        mediaPlayer.reset();
        mediaPlayer.release();
        mediaPlayer = null;
    }
}
PiyushMishra
  • 5,743
  • 6
  • 37
  • 57
  • There's a slight problem with this, if I lock my phone while the MediaPlayer is playing, my app crashes when I unlock it. – CiaranC94 Jul 21 '16 at 09:32
  • 5
    I've just tried commenting-out the "mediaPlayer.release()" line in onPause(), and _now_ my app doesn't crash upon unlocking. – CiaranC94 Jul 21 '16 at 10:17
  • @PiyushMishra these feature is accepted by developer console? As my app is get rejected b'coz I have used Vitamio 4.x version – Pallavi Dec 22 '16 at 14:31
35

Android MediaPlayer doesn't support streaming of MP3 natively until 2.2. In older versions of the OS it appears to only stream 3GP natively. You can try the pocketjourney code, although it's old (there's a new version here) and I had trouble making it sticky — it would stutter whenever it refilled the buffer.

The NPR News app for Android is open source and uses a local proxy server to handle MP3 streaming in versions of the OS before 2.2. You can see the relevant code in lines 199-216 (r94) here: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

And this is the StreamProxy class: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=e4984187f45c39a54ea6c88f71197762dbe10e72

The NPR app is also still getting the "error (-38, 0)" sometimes while streaming. This may be a threading issue or a network change issue. Check the issue tracker for updates.

PCoder
  • 2,165
  • 3
  • 23
  • 32
jwadsack
  • 5,708
  • 2
  • 40
  • 50
  • Are you absolutely sure about this? My understanding is that it was to do with the mime type. Could you check whether t works with the right MIME type pre 2.1? I am working on something else right now and couldn't check for a while. – Pandalover Aug 26 '10 at 09:51
  • 1
    According to the 2.2 release notes (http://developer.android.com/sdk/android-2.2-highlights.html), it includes a "New media framework (Stagefright) that supports local file playback and HTTP progressive streaming". In all my testing I was unable to get a 2.1 device to stream from a shoutcast server directly. I believe that the issue is that shoutcast servers return a protocol of ICY/1.1 rather than HTTP/1.1 and the media player trips up on this as it doesn't know how to respond to that content. – jwadsack Aug 26 '10 at 17:57
  • @jwadsack what if the audio files should be downloaded once and than user can play the files offline too? – Devendra Singh Jul 11 '15 at 05:32
  • @DevendraSingh I don't know if you can save the file while it is streaming with the current media player implementation (this answer is almost five years old and a lot has changed since 2.2). If nothing else, you could build a proxy following this example and write the file to storage while you pass it through the proxy. – jwadsack Jul 11 '15 at 15:55
11

I guess that you are trying to play an .pls directly or something similar.

try this out:

1: the code

mediaPlayer = MediaPlayer.create(this, Uri.parse("http://vprbbc.streamguys.net:80/vprbbc24.mp3"));
mediaPlayer.start();

2: the .pls file

This URL is from BBC just as an example. It was an .pls file that on linux i downloaded with

wget http://foo.bar/file.pls

and then i opened with vim (use your favorite editor ;) and i've seen the real URLs inside this file. Unfortunately not all of the .pls are plain text like that.

I've read that 1.6 would not support streaming mp3 over http, but, i've just tested the obove code with android 1.6 and 2.2 and didn't have any issue.

good luck!

Pabluez
  • 2,653
  • 3
  • 19
  • 29
  • 8
    Remember that if you want to stream music that you have to use mediaplayer.prepareAsync and not mediaplayer.prepare. Therefore you cannot use mediaplayer.create() because any of the .create() functions takes your Media Player object directly into the Prepared state, from which you cannot call prepareAsync, which you have to in order to stream. http://developer.android.com/reference/android/media/MediaPlayer.html – marienke May 22 '13 at 14:04
4

Use

 mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
 mediaplayer.prepareAsync();
 mediaplayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
      @Override
      public void onPrepared(MediaPlayer mp) {
          mediaplayer.start();
      }
 });
Shshank Bhong
  • 257
  • 2
  • 8
2

I've had the same error as you have and it turned out that there was nothing wrong with the code. The problem was that the webserver was sending the wrong Content-Type header.

Try wireshark or something similar to see what content-type the webserver is sending.

doep
  • 113
  • 4
2

Looking my projects:

  1. https://github.com/master255/ImmortalPlayer http/FTP support, One thread to read, send and save to cache data. Most simplest way and most fastest work. Complex logic - best way!
  2. https://github.com/master255/VideoViewCache Simple Videoview with cache. Two threads for play and save data. Bad logic, but if you need then use this.
Master
  • 690
  • 6
  • 18
1

No call mp.start with an OnPreparedListener to avoid the zero state i the log..

Fred Grott
  • 3,505
  • 1
  • 23
  • 18
  • I still get the log line 05-22 20:26:13.625: E/MediaPlayer(23818): stop called in state 0 even though I start my Media Player in the prepared() function. I also have an onError function where I reset the Media Player object. It still takes up to 2 minutes for my stream to start playing. See my question here: http://stackoverflow.com/questions/16672568/mediaplayer-error-1-1004-aka-media-error-io-trying-to-stream-music-on-samsun – marienke May 22 '13 at 14:08