为什么Android的MediaPlayer需要这么长时间来准备一些实况stream才能播放?

我发现Android MediaPlayer准备用不同的stream进行实况stream播放的时间差异很大。

硬数据

我在prepareAsync()和onPrepared(MediaPlayer mp)callback之间添加了日志logging,并且每次testing多个stream几次。 每个stream的时间非常一致(+/- 1秒),这里是结果:

  1. MPR新闻stream:27秒(http://newsstream1.publicradio.org:80/)
  2. MPR古典音乐stream:15秒(http://classicalstream1.publicradio.org:80/)
  3. MPR当前stream:7秒(http://currentstream1.publicradio.org:80/)
  4. PRIstream:52秒(http://pri-ice.streamguys.biz/pri1)

testing是在Android 2.3.4上通过3G连接(〜1100 Kbps)在Nexus S上进行的。

播放非stream式MP3audio文件不是问题。

这里是我如何玩这些溪stream的片段:

准备MediaPlayer:

... mediaPlayer.setDataSource(playUrl); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.prepareAsync(); ... 

然后在onPrepared(MediaPlayer mp)上:

 mediaPlayer.start(); 

为什么要准备一些stream而不是其他的stream? 上面的数据似乎表明,它可能是基于缓冲的数据 ,而不是缓冲的audio内容的持续时间 。 这真的可以吗?

更新:我testing了使用Android 1.6,2.2和2.3.4以及1.6,2.1,2.2,2.3.1和2.3.3模拟器的实际stream媒体。 我只看到了2.3.3和2.3.4的长时间延迟。 旧版本在5秒内开始播放。

它似乎是缓冲固定的数据量,而不是固定的时间量。 对于那些不知道各种types的NPRstream的比特率的人来说,数据如下所示:

  1. MPR新闻stream:27秒( 64位
  2. MPR古典音乐stream:15秒( http://classicalstream1.publicradio.org:80/),128kbps
  3. MPR当前stream量:7秒( 128kbps ), http ://currentstream1.publicradio.org: 80/
  4. PRIstream:52秒( http://pri-ice.streamguys.biz/pri1),32kbps

除了两个128kbpsstream之间的差异之外,比特率和缓冲持续时间之间有很好的相关性。

无论如何,Android是开源的,所以你总是可以看看它在做什么 。 不幸的是, prepareAsync()prepare()是本地方法,看起来缓冲区相关的事件也是从本地进程调度的。

您是否尝试过将附加的OnBufferingUpdateListener附加到MediaPlayer以获得有关缓冲区状态的更精细的更新? 比较事件发生的速度和缓冲区填充不同stream的每个事件的百分比可能是有趣的。 你可以交叉引用这个比特stream的比特率,如果以32 kbps的速度缓冲4秒钟填充的缓冲区相同的百分比为1秒的128 kbps的缓冲,那么我想你会find你的答案。

通过FFmpegMediaPlayer切换MediaPlayerMediaPlayer更有效,如果你想testing你的stream,你可以通过他们的演示来完成。

我最近用stream式audio提供程序debugging了这个相同的问题。 这个问题涉及stagekright和stream源32kbps及更低。 我们在24,32,48,64和128 kbps的速度下测量响应时间。

  • 24 – > 46秒开始stream式传输
  • 32 – > 24秒开始stream式传输
  • 48 – > 2秒开始stream式传输
  • 64 – > 2秒开始stream式传输
  • 128 – > 2秒开始stream式传输

这是来自一致的无线连接,平均每个比特率超过10次。 正如特拉维斯指出的那样,关键在于舞台表演无法弄清audio的缓冲时间。 有时我会看到一条消息“错误:1,-21492389”左右,这似乎是在默默地让舞台剧玩家崩溃。 我试图追踪下来,最终得出的结论是,非常慢的stream(低于24kbps)似乎会导致缓冲区溢出,因为它们会缓冲直到设备用完audiostream的空间。

我想补充说,在整个testing过程中, OnBufferingUpdateListener根本不会为我开火。 我不知道那是什么 我认为唯一可以告诉加载如何的方法是代理加载,类似于上面提到的NPR应用程序。

如果您是从Icecaststream式传输,请查看burst-size设置:

突发大小是在连接时间突发到客户端的数据量(以字节为单位)。 就像突发连接一样,这是为了快速填充媒体播放器使用的预缓冲区。 默认值是64千字节,这是大多数客户使用的典型大小,所以通常不需要改变它。 此设置适用于所有安装点,除非在安装设置中被覆盖。 确保此值小于队列大小,必要时将队列大小设置为大于您所需的突发大小。 如果不这样做,可能会导致中止侦听器客户端连接尝试,原因是初始突发导致连接已经超出了队列大小限制。

我在我的服务器上增加了131072的burst-size ,现在基于MediaPlayer Android应用播放stream没有太多的延迟。

我试了10个数据点,三个快,七个慢。 这是一致的,这是一个快速的stream是快速的,慢的一直是缓慢的。

我认为这与服务器交付的内容长度有关,如果内容长度没有正确指定,Android不知道要缓冲多less。

可能是错的,没有丝毫跳动。

当我遇到这个问题时,我决定在打开播放器之前testingstream是否可用。 如果您让用户等待很长时间,音乐就会开始播放(不是的,但是我们可以说没关系)。 最糟糕的情况是让他等待很长时间,音乐永远不会开始! 所以,我们有两种情况:

  • 实时stream式场景,就像一个电台。
  • 录制的mp3文件可以在线获取。

无线电情况下,我们可以检查端口是否接受连接(打开/closures状态)。 如果是开放的准备播放器的音乐,否则不准备它。

 public static boolean isLiveStreamingAvailable() { SocketAddress sockaddr = new InetSocketAddress(STREAMING_HOST, STREAMING_PORT); // Create your socket Socket socket = new Socket(); boolean online = true; // Connect with 10 s timeout try { socket.connect(sockaddr, 10000); } catch (SocketTimeoutException stex) { // treating timeout errors separately from other io exceptions // may make sense return false; } catch (IOException iOException) { return false; } finally { // As the close() operation can also throw an IOException // it must caught here try { socket.close(); } catch (IOException ex) { // feel free to do something moderately useful here, eg log the event } } return true; } 

mp3文件的情况下 ,事情有点不同。 您应该检查http请求后面的响应代码。

 public static boolean isRecordedStreamingAvailable() { try { HttpURLConnection.setFollowRedirects(false); // note : you may also need // HttpURLConnection.setInstanceFollowRedirects(false) HttpURLConnection con = (HttpURLConnection) new URL(RECORDED_URL).openConnection(); con.setRequestMethod("HEAD"); return (con.getResponseCode() == HttpURLConnection.HTTP_OK); } catch (Exception e) { e.printStackTrace(); return false; } }