音频-Android-ICS 4.0中的MediaPlayer缓冲区大小
我使用套接字作为MediaPlayer的代理,因此可以在将mp3音频写入套接字之前下载并解密。 这类似于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的数据量示例:
在具有2.3.4的SGS2上-约133920字节后的onPrepared()
在使用4.0.4的Nexus S上-约961930字节后的onPrepared()
这也发生在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();
在音频之前写入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();
}
我四处寻找替代实现,但是由于我已经加密了音频并且MediaPlayer不支持InputStreams作为数据源,所以我唯一的选择(我认为..)是使用诸如此类的代理。
同样,这在Android 2.1-2.3上运行良好,但在ICS中,MediaPlayer在播放之前会缓冲大量此类数据。
编辑2:
进一步的测试表明,一旦升级到Android 4.0.3,这在SGS2上也是一个问题。 因此,似乎MediaPlayer的缓冲实现在4.0中已发生了显着变化。 由于API无法提供任何更改行为的方式,因此令人沮丧。
编辑3:
已创建Android错误。 请添加评论并在其中加注星标[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(用于HD内容)的缓冲区大小是有意增加的。 已要求API开发人员添加在MediaPlayer上设置缓冲区大小的功能。
尽管我认为这个API更改请求在我来之前就已经存在了,所以我不建议任何人屏住呼吸。
是否可以在启动MediaPlayer的地方看到代码?
您是否正在使用STREAM_MUSIC
音频流类型?
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
您是否还在player.prepareAsync()之间进行了实验? 和player.prepare();?
我记得去年有一个类似的问题,解决方案是:开始,暂停然后onPrepared to start():
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();
}
});
在这种情况下可能无法解决,但是在旋转车轮时,这可能值得一试。
对我来说,解决方案是将MediaCodec与AudioTrack一起使用,我在这里找到了所有需要了解的信息:
这可能是一个解决方案:[http://www.piterwilson.com/blog/2014/03/15/mediacodec-mediaextractor-and-audiotrack-to-the-rescue/]