为什么Android的MediaPlayer需要这么长时间来准备一些实况stream才能播放?
我发现Android MediaPlayer准备用不同的stream进行实况stream播放的时间差异很大。
硬数据
我在prepareAsync()和onPrepared(MediaPlayer mp)callback之间添加了日志logging,并且每次testing多个stream几次。 每个stream的时间非常一致(+/- 1秒),这里是结果:
- MPR新闻stream:27秒(http://newsstream1.publicradio.org:80/)
- MPR古典音乐stream:15秒(http://classicalstream1.publicradio.org:80/)
- MPR当前stream:7秒(http://currentstream1.publicradio.org:80/)
- 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的比特率的人来说,数据如下所示:
- MPR新闻stream:27秒( 64位 )
- MPR古典音乐stream:15秒( http://classicalstream1.publicradio.org:80/),128kbps
- MPR当前stream量:7秒( 128kbps ), http ://currentstream1.publicradio.org: 80/
- 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切换MediaPlayer
比MediaPlayer
更有效,如果你想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; } }
- 在SVN的Android项目中,我应该忽略哪些文件
- 如何使用DrawerLayout来显示在ActionBar /工具栏和状态栏下?
- 适用于KitKat的Android 5.0材质devise风格导航抽屉
- QualcommCameraHardware来源的想法native_get_picture:MSM_CAM_IOCTL_GET_PICTURE连接超时错误?
- 奥托vs LocalBroadcast:
- 适用于Android的Scala编程
- proguard地狱 – 找不到引用类
- 如何在小部件右侧没有向下三angular形的情况下创buildandroid微调器
- 如何在Android应用程序中设置全息黑暗主题?