Android – ICS 4.0中的MediaPlayer缓冲区大小

我使用套接字作为MediaPlayer的代理,因此我可以在将它写入套接字之前下载和解密mp3audio。 这与NPR新闻应用程序中显示的例子类似,但是我将其用于所有Android版本2.1 – 4 atm。

NPR StreamProxy代码 – http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java

我的问题是2.1 – 2.3的回放速度很快,但在Android 4.0 ICS中,MediaPlayer会在触发onPrepared侦听器之前缓冲太多的数据。

在onPrepared()之前写入Socket OutputStream的示例数据量:

在SGS2 2.3.4 – onPrepared()〜133920字节之后

在Nexus S 4.0.4 – onPrepared()〜961930字节之后

这也发生在Galaxy Nexus上。

奇怪的是,4.0仿真器不会像4.0设备那样缓冲数据。 任何人在ICS上遇到与MediaPlayer类似的问题?

编辑

这是代理如何写入套接字。 在这个例子中,它是从一个文件加载的CipherInputStream,但是从HttpResponse加载时也是一样的。

final Socket client = (setup above) // encrypted file input stream final CipherInputStream inputStream = getInputStream(file); // setup the socket output stream final OutputStream output = client.getOutputStream(); // Writing the header final String httpHeader = buildHttpHeader(file.length()); final byte[] buffer = httpHeader.getBytes("UTF-8"); output.write(buffer, 0, buffer.length); int writtenBytes = 0; int readBytes; final byte[] buff = new byte[1024 * 12]; // 12 KB while (mIsRunning && (readBytes = inputStream.read(buff)) != -1) { output.write(buff, 0, readBytes); writtenBytes += readBytes; } output.flush(); output.close(); 

audio前写入MediaPlayer的HTTP标题

 private String buildHttpHeader(final int contentLength) { final StringBuilder sb = new StringBuilder(); sb.append("HTTP/1.1 200 OK\r\n"); sb.append("Content-Length: ").append(contentLength).append("\r\n"); sb.append("Accept-Ranges: bytes\r\n" ); sb.append("Content-Type: audio/mpeg\r\n"); sb.append("Connection: close\r\n" ); sb.append("\r\n"); return sb.toString(); } 

我已经四处寻找替代实现,但由于我已经encryptionaudio和MediaPlayer不支持InputStreams作为数据源我唯一的select(我想..)是使用这样的代理。

再次,这是相当不错的Android 2.1 – 2.3,但在ICS的MediaPlayer缓冲大量的这些数据之前玩。

编辑2:

进一步testing显示,这也是SGS2升级到Android 4.0.3后的一个问题。 所以看起来MediaPlayer的缓冲实现在4.0中已经发生了很大的变化。 这是令人沮丧的,因为API没有办法改变行为。

编辑3:

Android的错误创build。 请添加评论和明星以及http://code.google.com/p/android/issues/detail?id=29870

编辑4:

我的回放代码是相当标准的..我在我的onPrepared()方法的MediaPlayer上的start()调用。

 mCurrentPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mCurrentPlayer.setDataSource(url); mCurrentPlayer.prepareAsync(); 

已经尝试过使用prepare()和ajacian81的推荐方式,但无济于事。

我应该补充一点,Google员工最近回答了我的问题,并确认缓冲区大小在ICS(高清内容)中有意增加。 已向API开发人员要求添加在MediaPlayer上设置缓冲区大小的function。

虽然我认为在我出现之前,API改变的要求已经出现了,所以我不会build议任何人屏住呼吸。

是否有可能看到你开始()的MediaPlayer的代码?

你使用STREAM_MUSICaudiostreamtypes吗?

 player.setAudioStreamType(AudioManager.STREAM_MUSIC); 

你有没有尝试过player.prepareAsync(); 和player.prepare();?

我记得去年有一个类似的问题,解决的办法是:开始,暂停,然后onPrepared开始():

 player.setAudioStreamType(AudioManager.STREAM_MUSIC); player.setDataSource(src); player.prepare(); player.start(); player.pause(); player.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { player.start(); } }); 

在这种情况下不太可能成为解决问题的办法,但是当你旋转你的轮子时,这可能是值得的。

对我来说,解决scheme是使用AudioTrack MediaCodec,我发现我需要知道的一切:

这可能是一个解决scheme: http : //www.piterwilson.com/blog/2014/03/15/mediacodec-mediaextractor-and-audiotrack-to-the-rescue/