app - Android-Tamaño del búfer de MediaPlayer en ICS 4.0
music player android apk (2)
¿Sería posible ver el código donde está comenzando () el MediaPlayer?
¿Estás usando el tipo de flujo de audio STREAM_MUSIC
?
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
¿Has experimentado también entre player.prepareAsync (); y player.prepare () ;?
Hubo un problema similar el año pasado que recuerdo, donde la solución era: iniciar, pausar y luego encender Preparado para comenzar ():
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();
}
});
Es poco probable que sea la solución en este caso, pero mientras gira sus ruedas, podría valer la pena intentarlo.
Estoy usando un socket como proxy para MediaPlayer para poder descargar y descifrar el audio mp3 antes de escribirlo en el socket. Esto es similar al ejemplo que se muestra en la aplicación de noticias NPR, sin embargo, estoy usando esto para todas las versiones de Android 2.1 - 4 atm.
Código de NPR StreamProxy - http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java
Mi problema es que la reproducción es rápida para 2.1 - 2.3, pero en Android 4.0 ICS el MediaPlayer almacena demasiados datos antes de disparar el oyente OnPrepared.
Una cantidad de ejemplo de datos escritos en el socket OutputStream antes de onPrepared ():
En SGS2 con 2.3.4 - onPrepared () después de ~ 133920 bytes
En Nexus S con 4.0.4 - onPrepared () después de ~ 961930 bytes
Esto también ocurre en el Galaxy Nexus.
Curiosamente, el emulador 4.0 no almacena tantos datos como los 4.0 dispositivos. ¿Alguien tiene un problema similar con MediaPlayer en ICS?
EDITAR
Así es como el proxy está escribiendo en el socket. En este ejemplo, proviene de un CipherInputStream cargado desde un archivo, pero lo mismo ocurre cuando se carga desde 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();
Los encabezados HTTP que se escriben en MediaPlayer antes del audio ...
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();
}
He buscado implementaciones alternativas, pero como tengo audio cifrado y el MediaPlayer no admite InputStreams como fuente de datos, mi única opción (creo ...) es usar un proxy como este.
Una vez más, esto está funcionando bastante bien Android 2.1 - 2.3, pero en ICS el MediaPlayer está almacenando una gran cantidad de estos datos antes de reproducirlos.
EDICION 2:
Pruebas adicionales muestran que esto también es un problema en el SGS2 una vez que se actualizó a Android 4.0.3. Parece que la implementación del buffering de MediaPlayer ha cambiado significativamente en 4.0. Esto es frustrante ya que la API no proporciona ninguna forma de alterar el comportamiento.
EDIT 3:
Error de Android creado. Agregue comentarios y protagonice también http://code.google.com/p/android/issues/detail?id=29870
EDIT 4:
Mi código de reproducción es bastante estándar. Tengo la llamada de inicio () en el MediaPlayer en mi método onPrepared ().
mCurrentPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mCurrentPlayer.setDataSource(url);
mCurrentPlayer.prepareAsync();
Lo he intentado usando solo prepare () y también la manera recomendada de ajacian81 pero fue en vano.
Debo añadir que recientemente, un empleado de Google volvió a hablarme sobre mi pregunta y me confirmó que el tamaño del buffer se aumentó intencionalmente en ICS (para contenido HD). Se ha solicitado a los desarrolladores de API que agreguen la capacidad de establecer un tamaño de búfer en MediaPlayer.
Aunque creo que esta solicitud de cambio de API había existido antes de que yo llegara, entonces no aconsejaría a nadie que contuviera la respiración.
Para mí, la solución fue utilizar MediaCodec con AudioTrack, encontré todo lo que necesitaba saber aquí:
Esta podría ser una solución: http://www.piterwilson.com/blog/2014/03/15/mediacodec-mediaextractor-and-audiotrack-to-the-rescue/