我正在使用套接字作为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的示例数据量:
在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();
在音频之前写入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();
尝试使用just()和ajacian81的推荐方法,但无济于事。
我应该补充说,最近有一位谷歌员工回答了我的问题,并确认ICS中的缓冲区大小是有意增加的(对于高清内容)。已经要求API开发人员添加在MediaPlayer上设置缓冲区大小的功能。
虽然我认为这个API更改请求在我出现之前已经存在,所以我不建议任何人屏住呼吸。
答案 0 :(得分:2)
是否可以看到您开始使用MediaPlayer的代码?
您使用的是STREAM_MUSIC
音频流类型吗?
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
你是否也在player.prepareAsync()之间进行过实验;和player.prepare();?
去年我记得有一个类似的问题,解决方案是:开始,暂停然后开始准备开始():
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();
}
});
在这种情况下不太可能是修复,但是当你转动轮子时,这可能值得一试。
答案 1 :(得分:0)
对我来说,解决方案是将MediaCodec与AudioTrack一起使用,我发现我需要知道的所有内容:
这可能是一个解决方案:http://www.piterwilson.com/blog/2014/03/15/mediacodec-mediaextractor-and-audiotrack-to-the-rescue/