Acceso a la caché del reproductor multimedia

Quiero mover un archivo mp3 progresivamente transmitido a la tarjeta SD una vez que esté completamente cargado. ¿Hay alguna forma de lograrlo?

He visto que el MediaPlayer descarga completamente el archivo completo mientras que la transmisión progresiva y luego podemos buscar cualquier parte del archivo. Quiero mover un archivo completamente transmitido al almacenaje externo de modo que la reproducción futura no pierda datos y batería.

El comentario sobre el post original te señala la dirección correcta, pero pensé que podría ser útil exponer un poco …

Lo que he hecho es construir un servidor proxy ligero usando Naga y las bibliotecas Apache HTTP. Debe haber un montón de ejemplos por ahí para obtener los fundamentos de esta parte. Proporcione al MediaPlayer una URL localhost apropiada para que abra un socket a su proxy. Cuando MediaPlayer realiza una solicitud, utilice el proxy para enviar una solicitud equivalente al host de medios actual. Recibirás datos byte [] en el método packetReceived del proxy, que utilizo para construir un HttpGet y enviarlo en su camino con AndroidHttpClient.

Usted recibirá una HttpResponse y puede utilizar la HttpEntity dentro para acceder a los datos de bytes de transmisión. Estoy usando un ReadableByteChannel, así:

 HttpEntityWrapper entity = (HttpEntityWrapper)response.getEntity(); ReadableByteChannel src = Channels.newChannel(entity.getContent()); 

Haga lo que quiera con los datos mientras lo lee de nuevo (como el caché en un archivo en la tarjeta SD). Para pasar el material correcto al MediaPlayer, obtenga el SocketChannel desde el cliente Socket, primero escriba los encabezados de respuesta directamente a ese canal y, a continuación, proceda a escribir los datos de bytes de la entidad. Estoy utilizando un NIO ByteBuffer en un bucle while (el cliente es un Socket y el búfer es un ByteBuffer).

 int read, written; SocketChannel dst = client.getChannel(); while (dst.isConnected() && dst.isOpen() && src.isOpen() && (read = src.read(buffer)) >= 0) { try { buffer.flip(); // This is one point where you can access the stream data. // Just remember to reset the buffer position before trying // to write to the destination. if (buffer.hasRemaining()) { written = dst.write(buffer); // If the player isn't reading, wait a bit. if (written == 0) Thread.sleep(15); buffer.compact(); } } catch (IOException ex) { // handle error } } 

Puede que tenga que alterar el encabezado de host en la respuesta antes de pasarlo junto al reproductor de modo que parece que su proxy es el remitente, pero estoy lidiando con una implementación propietaria de MediaPlayer para que el comportamiento podría ser un poco diferente. Espero que ayude.

La idea es crear un proxy que el reproductor multimedia pueda leer, en lugar de leer datos directamente desde la web.

He utilizado danikula / AndroidVideoCache que es muy simple de construir / usar. Lo usé para Audio no Video, pero es lo mismo.

Es tarde, pero me di cuenta de que la mayoría de la gente todavía necesita una solución. Mi solución basada en DiskLruCache de JakeWharton . Necesitamos dos cosas

  • AsyncTask para leer el archivo o descargarlo de la red y almacenarlo en caché

  • Devolución de llamada para obtener InputStram / FileDescriptor de caché

Paso 1:

 import android.content.Context; import android.os.AsyncTask; import org.apache.commons.io.IOUtils; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; // you can use FileDescriptor as // extends AsyncTask<String, Void, FileDescriptor> public class AudioStreamWorkerTask extends AsyncTask<String, Void, FileInputStream> { private OnCacheCallback callback = null; private Context context = null; public AudioStreamWorkerTask(Context context, OnCacheCallback callback) { this.context = context; this.callback = callback; } @Override protected FileInputStream doInBackground(String... params) { String data = params[0]; // Application class where i did open DiskLruCache DiskLruCache cache = MyApplication.getDiskCache(context); if (cache == null) return null; String key = hashKeyForDisk(data); final int DISK_CACHE_INDEX = 0; long currentMaxSize = cache.getMaxSize(); float percentageSize = Math.round((cache.size() * 100.0f) / currentMaxSize); if (percentageSize >= 90) // cache size reaches 90% cache.setMaxSize(currentMaxSize + (10 * 1024 * 1024)); // increase size to 10MB try { DiskLruCache.Snapshot snapshot = cache.get(key); if (snapshot == null) { Log.i(getTag(), "Snapshot is not available downloading..."); DiskLruCache.Editor editor = cache.edit(key); if (editor != null) { if (downloadUrlToStream(data, editor.newOutputStream(DISK_CACHE_INDEX))) editor.commit(); else editor.abort(); } snapshot = cache.get(key); } else Log.i(getTag(), "Snapshot found sending"); if (snapshot != null) return (FileInputStream) snapshot.getInputStream(DISK_CACHE_INDEX); } catch (IOException e) { e.printStackTrace(); } Log.i(getTag(), "File stream is null"); return null; } @Override protected void onPostExecute(FileInputStream fileInputStream) { super.onPostExecute(fileInputStream); if (callback != null) { if (fileInputStream != null) callback.onSuccess(fileInputStream); else callback.onError(); } callback = null; context = null; } public boolean downloadUrlToStream(String urlString, OutputStream outputStream) { HttpURLConnection urlConnection = null; try { final URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); InputStream stream = urlConnection.getInputStream(); // you can use BufferedInputStream and BufferOuInputStream IOUtils.copy(stream, outputStream); IOUtils.closeQuietly(outputStream); IOUtils.closeQuietly(stream); Log.i(getTag(), "Stream closed all done"); return true; } catch (final IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) IOUtils.close(urlConnection); } return false; } private String getTag() { return getClass().getSimpleName(); } private String hashKeyForDisk(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } private String bytesToHexString(byte[] bytes) { // http://stackoverflow.com/questions/332079 StringBuilder sb = new StringBuilder(); for (byte aByte : bytes) { String hex = Integer.toHexString(0xFF & aByte); if (hex.length() == 1) sb.append('0'); sb.append(hex); } return sb.toString(); } } 

Paso 2:

 public interface OnCacheCallback { void onSuccess(FileInputStream stream); void onError(); } 

Ejemplo

 final String path = "http://www.example.com/test.mp3"; new AudioStreamWorkerTask (TestActivity.this, new OnCacheCallback() { @Override public void onSuccess(FileInputStream fileInputStream) { Log.i(getClass().getSimpleName() + ".MediaPlayer", "now playing..."); if (fileInputStream != null) { // reset media player here if necessary mediaPlayer = new MediaPlayer(); try { mediaPlayer.setDataSource(fileInputStream.getFD()); mediaPlayer.prepare(); mediaPlayer.setVolume(1f, 1f); mediaPlayer.setLooping(false); mediaPlayer.start(); fileInputStream.close(); } catch (IOException | IllegalStateException e) { e.printStackTrace(); } } else { Log.e(getClass().getSimpleName() + ".MediaPlayer", "fileDescriptor is not valid"); } } @Override public void onError() { Log.e(getClass().getSimpleName() + ".MediaPlayer", "Can't play audio file"); } }).execute(path); 

Nota:

Esto se prueba pero la muestra ruda para la caché de archivos de audio, puede haber algunos problemas si encuentra algo por favor infórmenme 🙂

  • Mostrar el almacenamiento intermedio de MediaPlayer en la barra Buscar como progreso secundario
  • Notificación mediante RemoteViews no funciona
  • MediaPlayer cortar la reproducción demasiado pronto en Lollipop cuando la pantalla está apagada
  • MediaPlayer de Android setSurface mientras está en estado de pausa
  • Cómo separar / liberar la vista de superficie de android mediaplayer
  • Uso de MediaPlayer para reproducir el mismo archivo varias veces con superposición
  • MediaPlayer.getCurrentPosition ()> mediaPlayer.getDuration () al final de la reproducción del archivo mp3
  • Integración de un codec a un marco multimedia de Android
  • ¿Cómo evitar que el exoplayer se recargue en caso de retroceso?
  • Transmisión de audio mediante el servicio
  • Lista completa de los códigos de error de MediaPlayer
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.