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

den*_*eli 42 audio streaming android audio-player android-music-player

我正在使用套接字作为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();
Run Code Online (Sandbox Code Playgroud)

在音频之前写入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();
}
Run Code Online (Sandbox Code Playgroud)

我已经四处寻找替代实现,但由于我已经加密了音频并且MediaPlayer不支持InputStreams作为数据源,我唯一的选择(我认为..)就是使用这样的代理.

再次,这在Android 2.1 - 2.3上工作得相当好,但在ICS中,MediaPlayer在播放之前缓冲了大量此类数据.

编辑2:

进一步测试显示,一旦升级到Android 4.0.3,这也是SGS2上的一个问题.因此,似乎MediaPlayer的缓冲实现在4.0中发生了重大变化.这令人沮丧,因为API无法改变行为.

编辑3:

安装了Android bug.请添加评论并在那里加注星标 http://code.google.com/p/android/issues/detail?id=29870

编辑4:

我的播放代码是相当标准的..我在onPrepared()方法中对MediaPlayer进行了start()调用.

mCurrentPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mCurrentPlayer.setDataSource(url);
mCurrentPlayer.prepareAsync();
Run Code Online (Sandbox Code Playgroud)

尝试使用just()和ajacian81的推荐方法,但无济于事.

我应该补充说,最近有一位谷歌员工回答了我的问题,并确认ICS中的缓冲区大小是有意增加的(对于高清内容).已经要求API开发人员添加在MediaPlayer上设置缓冲区大小的功能.

虽然我认为这个API更改请求在我出现之前已经存在,所以我不建议任何人屏住呼吸.

aja*_*n81 2

是否可以看到启动 MediaPlayer 的代码?

您使用的是STREAM_MUSIC音频流类型吗?

player.setAudioStreamType(AudioManager.STREAM_MUSIC);
Run Code Online (Sandbox Code Playgroud)

您是否也尝试过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();                
                }
          });
Run Code Online (Sandbox Code Playgroud)

在这种情况下不太可能解决这个问题,但是当你正在旋转的时候,这可能值得一试。