studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones android audio streaming android-mediaplayer audio-streaming

para - manual de programacion android pdf



¿Por qué le toma tanto tiempo a MediaPlayer de Android preparar algunas transmisiones en vivo para su reproducción? (6)

Cambiar MediaPlayer por FFmpegMediaPlayer funciona mucho mejor que MediaPlayer si quieres probar tus streams puedes hacerlo a través de la demo que tienen.

Estoy encontrando grandes diferencias en el tiempo que tarda el MediaPlayer de Android en prepararse para la reproducción de transmisión en vivo con diferentes transmisiones.

Los datos duros

Agregué el registro entre prepareAsync () y la devolución de llamada onPrepared (MediaPlayer mp) y probé varias transmisiones varias veces cada una. Los tiempos para cada flujo fueron muy consistentes (+/- un segundo), y aquí están los resultados:

  1. Corriente de noticias MPR: 27 segundos (http://newsstream1.publicradio.org:80/)
  2. Corriente de música clásica MPR: 15 segundos (http://classicalstream1.publicradio.org:80/)
  3. MPR La corriente actual: 7 segundos (http://currentstream1.publicradio.org:80/)
  4. Flujo de PRI: 52 segundos (http://pri-ice.streamguys.biz/pri1)

Las pruebas se realizaron en un Nexus S con Android 2.3.4 en una conexión 3G (~ 1100 Kbps).

Reproducir archivos de audio MP3 que no se reproducen no es un problema.

Aquí hay fragmentos de cómo estoy reproduciendo las transmisiones:

Preparar MediaPlayer:

... mediaPlayer.setDataSource(playUrl); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.prepareAsync(); ...

Luego, en onPrepared (MediaPlayer mp):

mediaPlayer.start();

¿Por qué toma tanto tiempo preparar algunas transmisiones pero no otras? Los datos anteriores parecen sugerir que podría basarse en la cantidad de datos almacenados en búfer y no en la duración del contenido de audio almacenado. ¿Podría ser esto realmente?

Actualización: He probado la transmisión en vivo en dispositivos físicos con Android 1.6, 2.2 y 2.3.4 y emuladores con 1.6, 2.1, 2.2, 2.3.1 y 2.3.3. Solo veo la larga demora en 2.3.3 y 2.3.4. Las versiones anteriores comienzan a reproducirse en 5 segundos.


Cuando tuve este problema, decidí probar si hay transmisión disponible antes de abrir el reproductor. Si hace que el usuario espere mucho tiempo y la música se iniciará bien (no lo es, pero digamos que está bien). El peor de los casos es hacer que espere mucho tiempo y ¡la música nunca comenzará! Entonces, tenemos 2 situaciones:

  • El escenario de transmisión en vivo, como una estación de radio.
  • El archivo mp3 grabado que está disponible en línea.

En el escenario de la radio podríamos verificar si el puerto acepta conexiones (estado de abrir / cerrar). Si está abierto, prepara al jugador para la música, de lo contrario no lo prepares.

public static boolean isLiveStreamingAvailable() { SocketAddress sockaddr = new InetSocketAddress(STREAMING_HOST, STREAMING_PORT); // Create your socket Socket socket = new Socket(); boolean online = true; // Connect with 10 s timeout try { socket.connect(sockaddr, 10000); } catch (SocketTimeoutException stex) { // treating timeout errors separately from other io exceptions // may make sense return false; } catch (IOException iOException) { return false; } finally { // As the close() operation can also throw an IOException // it must caught here try { socket.close(); } catch (IOException ex) { // feel free to do something moderately useful here, eg log the event } } return true; }

En el escenario del archivo mp3, las cosas son un poco diferentes. Debe verificar el código de respuesta que sigue después de la solicitud http.

public static boolean isRecordedStreamingAvailable() { try { HttpURLConnection.setFollowRedirects(false); // note : you may also need // HttpURLConnection.setInstanceFollowRedirects(false) HttpURLConnection con = (HttpURLConnection) new URL(RECORDED_URL).openConnection(); con.setRequestMethod("HEAD"); return (con.getResponseCode() == HttpURLConnection.HTTP_OK); } catch (Exception e) { e.printStackTrace(); return false; } }


Intenté esto con 10 puntos de datos, tres rápidos, 7 lentos. Es consistente, es decir, una transmisión rápida es rápida y una lenta siempre lenta.

Creo que está relacionado con el servidor entregado ''contenido-longitud'', Android no sabe cuánto almacenar en búfer si el contenido-longitud no está especificado correctamente.

Podría estar equivocado, no fue tan lejos como el cableado.


Parece que está almacenando una cantidad fija de datos en vez de una cantidad fija de tiempo. Para cualquiera que no sepa las velocidades de bit de varios tipos de secuencias de NPR fuera de su cabeza, los datos se ven así:

  1. Flujo de noticias de MPR: 27 segundos ( http://newsstream1.publicradio.org:80/ ), 64 kbps
  2. Corriente de música clásica de MPR: 15 segundos ( http://classicalstream1.publicradio.org:80/ ), 128 kbps
  3. MPR La corriente actual: 7 segundos ( http://currentstream1.publicradio.org:80/ ), 128 kbps
  4. Intercambio de PRI: 52 segundos ( http://pri-ice.streamguys.biz/pri1 ), 32 kbps

Además de la discrepancia entre los dos flujos de 128 kbps, existe una muy buena correlación entre la tasa de bits y la duración del almacenamiento en búfer.

En cualquier caso, Android es de código abierto, por lo que siempre puedes ver lo que está haciendo . Desafortunadamente, prepareAsync() y prepare() son métodos nativos, y parece que los eventos relacionados con el búfer también se envían desde un proceso nativo.

¿Has intentado adjuntar un OnBufferingUpdateListener al MediaPlayer para obtener actualizaciones más detalladas sobre el estado del buffer? Puede ser interesante comparar la velocidad a la que se entregan los eventos y el porcentaje que el búfer llena en cada evento en las diferentes secuencias. Puede hacer una referencia cruzada con los bitrates del flujo, y si 4 segundos de almacenamiento en búfer a 32 kbps llenan el búfer el mismo porcentaje que 1 segundo de búfer a 128 kbps, entonces creo que habrá encontrado su respuesta.


Recientemente he depurado este mismo problema con un proveedor de audio de transmisión. El problema se relaciona con el nivel de escena y las fuentes de transmisión de 32 kbps o menos. Pasamos por la misma transmisión midiendo el tiempo de respuesta a 24, 32, 48, 64 y 128 kbps.

  • 24 -> 46 segundos para comenzar a transmitir
  • 32 -> 24 segundos para comenzar a transmitir
  • 48 -> 2 segundos para comenzar a transmitir
  • 64 -> 2 segundos para comenzar a transmitir
  • 128 -> 2 segundos para comenzar a transmitir

Esto es a partir de una conexión inalámbrica constante promediada en 10 intentos en cada tasa de bits. La clave, como señaló Travis, era que el fanático de la escena no podía descifrar cuánto tiempo debía almacenar el audio. A veces veía un mensaje ''error: 1, -21492389'' más o menos, que parecía colgar silenciosamente al jugador de stagefright. Traté de rastrear esto y eventualmente llegué a la conclusión de que las secuencias muy lentas (sub 24 kbps) parecían causar un desbordamiento del búfer porque amortiguarían hasta que el dispositivo se quedara sin espacio para la transmisión de audio.

Quería agregar que OnBufferingUpdateListener no se OnBufferingUpdateListener en absoluto durante esta prueba. No sé para qué sirve. Creo que la única manera en que puedes saber cómo se está cargando es usar proxy de la carga, de manera similar a la aplicación NPR mencionada anteriormente.


Si está transmitiendo desde Icecast, eche un vistazo a la configuración del burst-size :

El tamaño de ráfaga es la cantidad de datos (en bytes) para reventar a un cliente en el momento de la conexión. Al igual que la ráfaga de conexión, esto es para llenar rápidamente el pre-buffer utilizado por los reproductores de medios. El valor predeterminado es 64 kbytes, que es un tamaño típico utilizado por la mayoría de los clientes, por lo que no suele ser necesario cambiarlo. Esta configuración se aplica a todos los puntos de montaje a menos que se anule en las configuraciones de montaje. Asegúrese de que este valor sea más pequeño que el tamaño de la cola; de ser necesario, aumente el tamaño de la cola para que sea más grande que el tamaño de la ráfaga deseada. De lo contrario, podrían producirse intentos fallidos de conexión del cliente de escucha debido a una ráfaga inicial que conduzca a la conexión que ya excede el límite del tamaño de la cola.

Aumenté el burst-size la burst-size a 131072 en mi servidor, y ahora mi aplicación de Android basada en MediaPlayer reproduce transmisiones sin mucha demora.