为什么Android需要这么长时间';让MediaPlayer准备一些实时流以便播放?
我发现Android MediaPlayer为不同流的实时流播放做准备所需的时间有很大差异 硬数据 我在prepareAsync()和onPrepared(MediaPlayer mp)回调之间添加了日志记录,并对每个流进行了几次测试。每个流的时间非常一致(+/-1秒),结果如下:为什么Android需要这么长时间';让MediaPlayer准备一些实时流以便播放?,android,audio,streaming,android-mediaplayer,audio-streaming,Android,Audio,Streaming,Android Mediaplayer,Audio Streaming,我发现Android MediaPlayer为不同流的实时流播放做准备所需的时间有很大差异 硬数据 我在prepareAsync()和onPrepared(MediaPlayer mp)回调之间添加了日志记录,并对每个流进行了几次测试。每个流的时间非常一致(+/-1秒),结果如下: MPR新闻流:27秒(http://newsstream1.publicradio.org:80/) 经典音乐流:15秒(http://classicalstream1.publicradio.org:80/) MP
...
mediaPlayer.setDataSource(playUrl);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepareAsync();
...
然后在onPrepared(MediaPlayer mp)中:
为什么要花这么长的时间来准备一些溪流而不是其他溪流?上述数据似乎表明,这可能是基于已缓冲的数据量,而不是缓冲音频内容的持续时间。真的会这样吗
更新:我已经在使用Android 1.6、2.2和2.3.4的物理设备以及使用1.6、2.1、2.2、2.3.1和2.3.3的模拟器上测试了流媒体直播。我只看到2.3.3和2.3.4的长时间延迟。较旧的版本在5秒内开始播放。它似乎是在缓冲固定数量的数据,而不是固定时间。对于那些不知道各种类型的NPR流的比特率的人来说,数据如下所示:
prepareAsync()
和prepare()
是本机方法,与缓冲区相关的事件似乎也是从本机进程调度的
您是否尝试将
OnBufferingUpdateListener
附加到MediaPlayer以获得关于缓冲区状态的更细粒度更新?比较事件的传递速率以及不同流中每个事件的缓冲区填充百分比可能会很有趣。您可以将其与流比特率进行交叉引用,如果32kbps的4秒缓冲与128kbps的1秒缓冲所占的百分比相同,那么我想您已经找到了答案。我尝试了10个数据点,3个快,7个慢。
这是一致的,快的流是快的,慢的流总是慢的
我认为这与服务器提供的“内容长度”有关,如果没有正确指定内容长度,Android不知道要缓冲多少
可能是错误的,没有达到有线共享的程度。我最近与流媒体音频提供商调试了相同的问题。该问题与stagefright和32kbps及以下的流媒体源有关。我们以24、32、48、64和128 kbps的速率测量响应时间
- 24->46秒开始播放流媒体
- 32->24秒开始播放流媒体
- 48->2秒开始播放流媒体
- 64->2秒开始播放流媒体
- 128->2秒开始播放流媒体
我想补充一点,在整个测试过程中,
OnBufferingUpdateListener
根本没有为我触发。我不知道它是干什么用的。我认为你能知道加载方式的唯一方法是代理加载,就像上面提到的NPR应用程序一样。切换MediaPlayer
比MediaPlayer
效果好得多。如果你想测试你的流,你可以通过他们拥有的应用程序来完成。如果你是从Icecast流媒体,查看突发大小设置:
突发大小是要突发到客户端的数据量(以字节为单位)
在连接时间。就像突发连接一样,这是为了快速填充
媒体播放器使用的预缓冲区。默认值为64 KB,这是一个
大多数客户使用的典型尺寸,因此通常不需要更改
必修的。此设置适用于所有装入点,除非在中被重写
安装设置。确保此值小于队列大小,
如有必要,增加队列大小,使其大于所需大小
突发大小。否则可能导致侦听器客户端中止
连接尝试,由于导致连接的初始突发
已超过队列大小限制
我将服务器上的突发大小增加到131072,现在基于MediaPlayer
的Android应用程序可以毫不延迟地播放流。当我遇到这个问题时,我决定在打开播放器之前测试流是否可用。如果你让用户等待很长时间,音乐就会开始播放
mediaPlayer.start();
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;
}
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;
}
}