Android - Tamanho do buffer do MediaPlayer no ICS 4.0
Eu estou usando um soquete como um proxy para o MediaPlayer para que eu possa baixar e descriptografar o áudio mp3 antes de escrevê-lo para o soquete. Isso é semelhante ao exemplo mostrado no aplicativo de notícias NPR, no entanto, estou usando isso para todas as versões do Android 2.1 - 4 atm.
Código NPR StreamProxy -http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java
Meu problema é que a reprodução é rápida para 2.1 - 2.3, mas no Android 4.0 ICS o MediaPlayer armazena em excesso muitos dados antes de disparar o ouvinte onPrepared.
Um exemplo de quantidade de dados gravados no Socket OutputStream antes de onPrepared ():
No SGS2 com 2.3.4 - onPrepared () após ~ 133920 bytes
No Nexus S com 4.0.4 - onPrepared () após ~ 961930 bytes
Isso também ocorre no Galaxy Nexus.
Estranhamente, o emulador 4.0 não armazena tantos dados quanto os dispositivos 4.0. Alguém experimenta um problema semelhante com o MediaPlayer no ICS?
EDITAR
Veja como o proxy está gravando no soquete. Neste exemplo, é de um CipherInputStream carregado de um arquivo, mas o mesmo ocorre quando é carregado a partir do HttpResponse.
<code>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(); </code>
Os cabeçalhos HTTP que são gravados no MediaPlayer antes do áudio.
<code>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(); } </code>
Eu procurei implementações alternativas, mas como eu tenho áudio criptografado e o MediaPlayer não suporta InputStreams como uma fonte de dados, minha única opção (eu acho) é usar um proxy como este.
Mais uma vez, isso está funcionando muito bem Android 2.1 - 2.3, mas no ICS o MediaPlayer está armazenando uma grande quantidade desses dados antes de jogar.
EDIT 2:
Outros testes estão mostrando que este também é um problema no SGS2, uma vez atualizado para o Android 4.0.3. Portanto, parece que a implementação de buffer do MediaPlayer mudou significativamente em 4.0. Isso é frustrante, pois a API não oferece nenhuma maneira de alterar o comportamento.
EDIT 3:
Bug Android criado. Por favor, adicione comentários e estrela lá tambémhttp://code.google.com/p/android/issues/detail?id=29870
EDIT 4:
Meu código de reprodução é bastante padrão .. Eu tenho a chamada start () no MediaPlayer no meu método onPrepared ().
<code>mCurrentPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mCurrentPlayer.setDataSource(url); mCurrentPlayer.prepareAsync(); </code>
Tentei usando apenas prepare () e também a maneira recomendada de ajacian81, mas sem sucesso.
Devo acrescentar que recentemente um funcionário do Google me respondeu sobre a minha pergunta e confirmou que o tamanho do buffer foi aumentado intencionalmente no ICS (para conteúdo em HD). Foi solicitado aos desenvolvedores da API para adicionar a capacidade de definir um tamanho de buffer no MediaPlayer.
Embora eu ache que essa solicitação de mudança da API já existia antes de eu aparecer, não aconselho ninguém a segurar a respiração.