安卓MediaPlayer准备时间过长

5

嘿,我正在使用MediaPlayer播放普通的ShoutCast流。代码很简单,使用prepareAsync()和处理程序开始播放。虽然对于一些流如DI.FM或ETN.FM(http://u10.di.fm:80/di_progressive)它可以无缝工作,但对于其他流(http://mp3.wpsu.org:8000/)它却无法超过准备状态。也没有调用其他监听器。

//Uri streamUri = Uri.parse("http://u10.di.fm:80/di_progressive"); /* works */
Uri streamUri = Uri.parse("http://mp3.wpsu.org:8000/"); /* stuck on prepare state */
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
    public void onPrepared(MediaPlayer mp) {
        mp.start();
    }
});
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(this.getBaseContext(), streamUri);
mediaPlayer.prepareAsync();

感谢您的反馈!


1
使用adb logcat、DDMS或Eclipse中的DDMS视图来检查LogCat并查找可能引发的任何警告。 - CommonsWare
我正在使用Eclipse调试,但MediaPlayer没有发布任何日志消息:( - Sergei
我不知道这是否仍然有效,但是我的建议是:
  1. 您可以使用Log将消息打印到logcat。请参阅http://developer.android.com/reference/android/util/Log.html
  2. create()是实例化MediaPlayer类对象的更好方法。有关详细信息,请参见:http://developer.android.com/reference/android/media/MediaPlayer.html#create(android.content.Context,%20android.net.Uri,%20android.view.SurfaceHolder)
- Sriram
我对此没有确切的答案,但这将有助于您的应用程序减少用户的挫败感。 (https://dev59.com/emw15IYBdhLWcg3weLwF#42042218) - LiTTle
2个回答

2

当我的MP处于准备状态太长时间(流媒体)并尝试使用reset()停止时,我遇到了问题。这会导致MP挂起,从而导致整个应用程序冻结。似乎没有办法在准备状态下停止MP。我考虑使用线程包装的prepare()而不是prepareAsync()。然后我就能杀死那个线程了。到目前为止,我是这样做的:

private void actionCancel(){
            try {
                mp.setDataSource(new String());
            } catch (Exception e) {
                e.printStackTrace();
                android.util.Log.d(TAG,"actionCancel(): mp.setDataSource() exception");
                mp.reset();
            }
}

它对我很有效。
此外,我有一个如下的计数器:

    @Override
    public void onBufferingUpdate(final MediaPlayer mp, final int percent) {

        if (!mp.isPlaying()){
//          android.util.Log.d(TAG,"onBufferingUpdate(): onBufferingUpdateCount = "+onBufferingUpdateCount);
            if (onBufferingUpdateCount>MAX_BUFFERING_UPDATES_AT_PREPARING_STATE)
                restartMP();
            onBufferingUpdateCount++;
            return;
        }
      }

我发现这个监听器总是在准备状态下触发。所以如果它触发了超过10次,而MP仍然没有播放,我就会重新启动它:

private void restartMP(){
        if (mp!=null)
            if (mpState==MediaPlayerState.Preparing)
                actionCancel();
            else
                mp.reset();
    else
        mp = new MediaPlayer();
        mpState = MediaPlayerState.Idle;
        onBufferingUpdateCount=0;
        //isRequestCancelled=false;
        requestTrackInfoStartedAt=0;
        requestPlay();
}

注意,MediaPlayerState是我的自定义枚举类型,其中包含“Preparing”值。 mpState是一个类属性/字段,它保存当前的MediaPlayerState状态。在开始prepareAsync()之前,我将mpState设置为MediaPlayerState.Preparing,在完成后,我将其设置为MediaPlayerState.Started或其他相应的值。


这个方法执行mediaPlayer.prepareAsync()mediaPlayer.start()需要更少的时间吗? - Naz141
实际上,这个方法只是关于“如何在没有ANR的情况下停止MP”。你可以自己决定应用程序等待MP通过准备状态的时间有多长。如果5秒钟过去了,而MP仍在准备中,你可以使用我的方法杀死MP实例。 - Stan

2

我认为服务器端存在一些兼容性问题。

这很奇怪,因为模拟器在我的情况下处理得很好 - 只是在我的Froyo Galaxy S上无法处理,尽管它是相同的API版本。

可能是编解码器问题、http流问题,我不知道。

但所有失败的服务器都是旧的,底部标有“版权所有1998-2004”...你会认为它们并不是最近或最新的。

一个潜在的解决方法(我还没有尝试过)是使用StreamProxy,这也将使您的代码与2.1和可能更早版本兼容。代价是额外的工作、额外的代码,而且无疑会有额外的错误...

如果您不知道,还有另一个2.2播放器错误报告可能也相关:Basic streaming audio works in 2.1 but not in 2.2


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接