programacion - manual de android en pdf
BĂșfer de flujo de audio (5)
Acabo de probar la siguiente solución, y funciona. Este problema es causado por el "/ n" utilizado en los encabezados en el método StreamProxy
processRequest()
de StreamProxy
. Cambiar esto a "/ r / n" debería hacer que el error desaparezca.
En cuanto a la implementación de transmisiones personalizadas, lo he usado en el pasado, aunque parece ser principalmente para transmisiones de radio infinitas. http://blog.pocketjourney.com/2009/12/27/android-streaming-mediaplayer-tutorial-updated-to-v1-5-cupcake/
Necesito reproducir la transmisión de audio en vivo, en realidad es la radio. El problema es que también necesito administrar un búfer de 20 minutos para la transmisión. Según tengo entendido, no es fácil de implementar con Android.
En primer lugar, comprobé MediaPlayer, pero no proporciona ningún método para la administración de búfer. De hecho, incluso no se puede establecer el tamaño del búfer directamente.
En segundo lugar, intenté administrar el búfer utilizando archivos locales: descargue progresivamente la secuencia a archivos temporales y cámbielos. Pero cuando desea cambiar al siguiente archivo (cambiar la fuente de datos en MediaPlayer), el audio no se reproduce continuamente. Se pueden escuchar breves interrupciones.
La última idea es usar el proxy de la corriente. Por lo general, se usa para reproducir transmisiones en versiones de Android inferiores a 8. En el proxy de transmisión, crea ServerSocket, lee la transmisión de audio y escribe en el reproductor. Así que en realidad puedo gestionar el almacenamiento en búfer allí. Puedo almacenar en caché y escribir en MediaPlayer lo que quiera. Pero. No funciona con Android 8.
Tengo una excepción: restablecimiento de la conexión por el par java.net.SocketException: restablecimiento de la conexión por el par. MediaPlayer 8 no quiere leer datos de socket.
Por lo tanto, tengo dos preguntas: 1) ¿Qué otra forma de implementar el almacenamiento en búfer de flujo? 2) ¿Cómo adaptar StreamProxy para Android 8?
Cualquier idea es apreciada.
Gracias
Cuando busca u omite o se pierde la conexión y MediaPlayer continúa reconectándose al servidor proxy, debe enviar esta respuesta con el Estado 206 después de recibir la solicitud y el rango (int) del cliente.
String headers += "HTTP/1.1 206 Partial Content/r/n";
headers += "Content-Type: audio/mpeg/r/n";
headers += "Accept-Ranges: bytes/r/n";
headers += "Content-Length: " + (fileSize-range) + "/r/n";
headers += "Content-Range: bytes "+range + "-" + fileSize + "/*/r/n";
headers += "/r/n";
Y cuando recibe una solicitud de MediaPlayer que no contiene Rango en el encabezado HTTP, entonces está solicitando un nuevo archivo de flujo, en este caso, el encabezado de respuesta debería tener este aspecto:
String headers = "HTTP/1.1 200 OK/r/n";
headers += "Content-Type: audio/mpeg/r/n";
headers += "Accept-Ranges: bytes/r/n";
headers += "Content-Length: " + fileSize + "/r/n";
headers += "/r/n";
¡Disfrutar!
El Mediaplayer del SDK 8 no podría leer una URL de proxy. Pero según mi trabajo actual, esto difiere de un dispositivo a otro. En mi Samsung ACE (SDK 8) la conexión de proxy funciona bien, pero en mi HTC Incredible S, la conexión de proxy daría el mismo problema que tiene. Una conexión directa a la transmisión de audio funciona bien, pero esto causa bips y boops en algunos dispositivos como EVO en el sprint.
¿Conseguiste una resolución para este problema? ¿Como manejaste esto?
-Hari
Me doy cuenta de que esta pregunta tiene como 5 años, pero en caso de que alguien más esté vagando: ExoPlayer es una biblioteca de Google que le da mucho más control sobre opciones como el tamaño del búfer.
//DefaultUriDataSource – For playing media that can be either local or loaded over the network.
DefaultUriDataSource dataSource = new DefaultUriDataSource(WgtechApplication.getAppContext(),
Util.getUserAgent(WgtechApplication.getAppContext(), WgtechApplication.class.getSimpleName()));
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
//ExtractorSampleSource – For formats such as MP3, M4A, MP4, WebM, MPEG-TS and AAC.
ExtractorSampleSource sampleSource = new ExtractorSampleSource(Uri.parse(RADIO_STREAMING_URL),
dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
player.prepare(new MediaCodecAudioTrackRenderer(sampleSource));
Aquí hay un pequeño proyecto que creé para aprender a usarlo. https://github.com/feresr/MyMediaPlayer
http://developer.android.com/guide/topics/media/exoplayer.html https://github.com/google/ExoPlayer
Uso el mismo StreamProxy que los chicos usaron para el proyecto NPR: https://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java
Así se pone el flujo de audio original:
String url = request.getRequestLine().getUri();
HttpResponse realResponse = download(url);
...
InputStream data = realResponse.getEntity().getContent();
Y escribe desde este flujo al socket del cliente:
byte[] buff = new byte[1024 * 50];
while (isRunning && (readBytes = data.read(buff, 0, buff.length)) != -1) {
client.getOutputStream().write(buff, 0, readBytes);
}
(Puedes obtener el código completo en el enlace de arriba).
Y finalmente, cómo inicializan el reproductor (PlaybackService):
if (stream && sdkVersion < 8) {
if (proxy == null) {
proxy = new StreamProxy();
proxy.init();
proxy.start();
}
String proxyUrl = String.format("http://127.0.0.1:%d/%s", proxy.getPort(), url);
playUrl = proxyUrl;
}
...
mediaPlayer.setDataSource(playUrl);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepareAsync();
Así que comprueban la versión SDK. Pero si omito esta comprobación y uso el proxy para el SDK 8, también obtengo una excepción. Es extraño que MediaPlayer ni siquiera intente leer la transmisión:
12-30 15:09:41.576: DEBUG/StreamProxy(266): downloading...
12-30 15:09:41.597: DEBUG/StreamProxy(266): reading headers
12-30 15:09:41.597: DEBUG/StreamProxy(266): headers done
12-30 15:09:41.647: DEBUG/StreamProxy(266): writing to client
12-30 15:09:41.857: INFO/AwesomePlayer(34): mConnectingDataSource->connect() returned - 1007
12-30 15:09:41.857: ERROR/MediaPlayer(266): error (1, -1007)
12-30 15:09:41.867: ERROR/MediaPlayer(266): Error (1,-1007)
12-30 15:09:41.867: WARN/AudioService(266): onError(1, -1007)
12-30 15:09:41.867: WARN/AudioService(266): MediaPlayer refused to play current item. Bailing on prepare.
12-30 15:09:41.867: WARN/AudioService(266): onComplete()
12-30 15:09:42.097: ERROR/StreamProxy(266): Connection reset by peer
java.net.SocketException: Connection reset by peer
at org.apache.harmony.luni.platform.OSNetworkSystem.writeSocketImpl(Native Method)
at org.apache.harmony.luni.platform.OSNetworkSystem.write(OSNetworkSystem.java:723)
at org.apache.harmony.luni.net.PlainSocketImpl.write(PlainSocketImpl.java:578)
at org.apache.harmony.luni.net.SocketOutputStream.write(SocketOutputStream.java:59)
at com.skyblue.service.media.StreamProxy.processRequest(StreamProxy.java:204)
at com.skyblue.service.media.StreamProxy.run(StreamProxy.java:103)
at java.lang.Thread.run(Thread.java:1096)
Parece que MediaPlayer se volvió más inteligente. Y si paso esa url "http://127.0.0.1:%d/%s"
no solo quiere obtener bytes sino también una respuesta http "completa".
También me pregunto si hay alguna otra forma de implementar el almacenamiento en búfer? Como sé, el MediaPlayer solo consume archivos y urls. La solución con archivos no funciona. Así que tengo que usar socket para transmitir la transmisión.
Gracias