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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1965784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:57:51  来源:igfitidea点击:

Streaming Audio from A URL in Android using MediaPlayer?

androidmp3android-mediaplayeraudio-streaming

提问by Pandalover

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 :

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

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.

但是,我反复收到以下信息。我也尝试过不同的 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)

Any help much appreciated, thanks S

非常感谢任何帮助,谢谢

回答by PiyushMishra

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.

带有流媒体示例的简单媒体播放器。对于 xml 部分,您需要一个带有 id button1 的按钮和两个名称为 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;
    }
}

回答by jwadsack

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.

Android MediaPlayer 直到 2.2 才原生支持 MP3 流式传输。在旧版本的操作系统中,它似乎只在本地传输 3GP。您可以尝试口袋旅行代码,尽管它很旧(这里有一个新版本)而且我很难让它变得粘稠——每当它重新填充缓冲区时它就会断断续续。

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

适用于 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

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

这是 StreamProxy 类: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.

NPR 应用程序有时在流式传输时仍会收到“错误 (-38, 0)”。这可能是线程问题或网络更改问题。检查问题跟踪器以获取更新

回答by Pabluez

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

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

try this out:

试试这个:

1: the code

1:代码

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

2: the .pls file

2:.pls 文件

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

此 URL 来自 BBC,仅作为示例。这是我在 linux 上下载的 .pls 文件

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.

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

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.

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

good luck!

祝你好运!

回答by Shshank Bhong

Use

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

回答by doep

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.

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

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

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

回答by Fred Grott

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

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

回答by Master

Looking my projects:

查看我的项目:

  1. https://github.com/master255/ImmortalPlayerhttp/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/VideoViewCacheSimple Videoview with cache. Two threads for play and save data. Bad logic, but if you need then use this.
  1. https://github.com/master255/ImmortalPlayerhttp/FTP 支持,一个线程读取、发送和保存到缓存数据。最简单的方法和最快的工作。复杂的逻辑 - 最好的方法!
  2. https://github.com/master255/VideoViewCache带缓存的简单视频视图。两个线程用于播放和保存数据。糟糕的逻辑,但如果您需要,请使用它。