使用MediaPlayer从Android中的URL流式传输音频?

时间:2009-12-27 11:40:33

标签: android mp3 android-mediaplayer audio-streaming

我一直在尝试使用Android内置的MediaPlayer类通过http传输mp3。文档会告诉我,这应该像以下一样简单:

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

然而,我反复得到以下内容。我也尝试过不同的URL。请不要告诉我流式传输不适用于mp3。

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)

非常感谢任何帮助,谢谢 小号

7 个答案:

答案 0 :(得分:71)

带流媒体示例的简单媒体播放器。对于xml部分,您需要一个带有id按钮1的按钮和两个带有名称button_pause和button_play的可绘制文件夹中的图像,请不要忘记在清单中添加互联网权限。

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;
    }
}

答案 1 :(得分:35)

Android MediaPlayer在2.2之前不支持MP3本地流式传输。在旧版本的操作系统中,它似乎只能本地传输3GP。你可以尝试一下pocketjourney代码,虽然它已经过时了(有一个new version here)并且我很难把它变成粘滞的 - 只要它重新填充缓冲区就会口吃。

适用于Android的NPR新闻应用程序是开源的,使用本地代理服务器在2.2之前的操作系统版本中处理MP3流媒体。您可以在此处的第199-216行(r94)中查看相关代码:http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

这是StreamProxy类:http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=e4984187f45c39a54ea6c88f71197762dbe10e72

NPR应用程序在流式传输时有时仍会出现“错误(-38,0)”。这可能是线程问题或网络更改问题。查看issue tracker for updates

答案 2 :(得分:9)

我猜你是想尝试直接播放.pls或类似的东西。

试试这个:

1:代码

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

2:.pls文件

此网址仅以BBC为例。这是一个.pls文件,在我用

下载的linux上
wget http://foo.bar/file.pls

然后我用vim打开(使用你最喜欢的编辑器;),我已经看到了这个文件中的真实URL。不幸的是,不是所有的.pls都是那样的纯文本。

我已经读过1.6不支持通过http流式传输mp3,但是,我刚用android 1.6和2.2测试了obove代码并且没有任何问题。

祝你好运!

答案 3 :(得分:3)

使用

 mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
 mediaplayer.prepareAsync();
 mediaplayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
      @Override
      public void onPrepared(MediaPlayer mp) {
          mediaplayer.start();
      }
 });

答案 4 :(得分:2)

我遇到了同样的错误,结果证明代码没有任何问题。问题是网络服务器发送了错误的Content-Type标题。

尝试使用wireshark或类似内容来查看网络服务器正在发送的内容类型。

答案 5 :(得分:1)

没有使用OnPreparedListener调用mp.start以避免日志中的零状态..

答案 6 :(得分:1)

看我的项目:

  1. https://github.com/master255/ImmortalPlayer http / FTP支持,一个线程可以读取,发送和保存到缓存数据。最简单的方式和最快的工作。复杂的逻辑 - 最好的方法!
  2. https://github.com/master255/VideoViewCache包含缓存的简单视频视图。两个线程用于播放和保存数据。错误的逻辑,但如果你需要,那么使用它。