Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


¿Alguien tiene MediaPlayer trabajando con ParcelFileDescriptor y createPipe ()?

Relacionado con mi reciente pregunta sobre MediaRecorder y createPipe() , y una discusión de la técnica createPipe() en esta otra pregunta SO , ahora estoy tratando de conseguir MediaPlayer para trabajar con el contenido servido por un ContentProvider través de ParcelFileDescriptor y createPipe() .

Este proyecto muestra mi trabajo hasta la fecha. Se basa en un ejemplo anterior que reproduce un clip OGG almacenado como un recurso sin formato . Por lo tanto, sé que mi clip está bien.

He cambiado mi configuración de MediaPlayer a:

  private void loadClip() { try { mp=new MediaPlayer(); mp.setDataSource(this, PipeProvider.CONTENT_URI.buildUpon() .appendPath("clip.ogg") .build()); mp.setOnCompletionListener(this); mp.prepare(); } catch (Exception e) { goBlooey(e); } } 

A través de PipeProvider en PipeProvider , veo que mi Uri está siendo construido correctamente.

PipeProvider es el mismo que en este proyecto de ejemplo , que funciona para servir PDF a Adobe Reader, lo que limita la forma de atornillado de mi código puede ser. Todos los derechos reservados

Específicamente, openFile() crea un pipe desde ParcelFileDescriptor :

  @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { ParcelFileDescriptor[] pipe=null; try { pipe=ParcelFileDescriptor.createPipe(); AssetManager assets=getContext().getResources().getAssets(); new TransferTask(assets.open(uri.getLastPathSegment()), new AutoCloseOutputStream(pipe[1])).start(); } catch (IOException e) { Log.e(getClass().getSimpleName(), "Exception opening pipe", e); throw new FileNotFoundException("Could not open pipe for: " + uri.toString()); } return(pipe[0]); } 

Donde el hilo de fondo realiza una copia típica de secuencia a secuencia:

  static class TransferTask extends Thread { InputStream in; OutputStream out; TransferTask(InputStream in, OutputStream out) { this.in=in; this.out=out; } @Override public void run() { byte[] buf=new byte[1024]; int len; try { while ((len=in.read(buf)) > 0) { out.write(buf, 0, len); } in.close(); out.close(); } catch (IOException e) { Log.e(getClass().getSimpleName(), "Exception transferring file", e); } } } 

Sin embargo, MediaPlayer ahoga:

 10-16 13:33:13.203: E/MediaPlayer(3060): Unable to to create media player 10-16 13:33:13.203: D/MediaPlayer(3060): Couldn't open file on client side, trying server side 10-16 13:33:13.207: E/TransferTask(3060): Exception transferring file 10-16 13:33:13.207: E/TransferTask(3060): java.io.IOException: write failed: EPIPE (Broken pipe) 10-16 13:33:13.207: E/TransferTask(3060): at libcore.io.IoBridge.write(IoBridge.java:462) 10-16 13:33:13.207: E/TransferTask(3060): at java.io.FileOutputStream.write(FileOutputStream.java:187) 10-16 13:33:13.207: E/TransferTask(3060): at com.commonsware.android.audiolstream.PipeProvider$TransferTask.run(PipeProvider.java:120) 10-16 13:33:13.207: E/TransferTask(3060): Caused by: libcore.io.ErrnoException: write failed: EPIPE (Broken pipe) 10-16 13:33:13.207: E/TransferTask(3060): at libcore.io.Posix.writeBytes(Native Method) 10-16 13:33:13.207: E/TransferTask(3060): at libcore.io.Posix.write(Posix.java:178) 10-16 13:33:13.207: E/TransferTask(3060): at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191) 10-16 13:33:13.207: E/TransferTask(3060): at libcore.io.IoBridge.write(IoBridge.java:457) 10-16 13:33:13.207: E/TransferTask(3060): ... 2 more 10-16 13:33:13.211: E/MediaPlayer(3060): Unable to to create media player 10-16 13:33:13.218: E/TransferTask(3060): Exception transferring file 10-16 13:33:13.218: E/TransferTask(3060): java.io.IOException: write failed: EPIPE (Broken pipe) 10-16 13:33:13.218: E/TransferTask(3060): at libcore.io.IoBridge.write(IoBridge.java:462) 10-16 13:33:13.218: E/TransferTask(3060): at java.io.FileOutputStream.write(FileOutputStream.java:187) 10-16 13:33:13.218: E/TransferTask(3060): at com.commonsware.android.audiolstream.PipeProvider$TransferTask.run(PipeProvider.java:120) 10-16 13:33:13.218: E/TransferTask(3060): Caused by: libcore.io.ErrnoException: write failed: EPIPE (Broken pipe) 10-16 13:33:13.218: E/TransferTask(3060): at libcore.io.Posix.writeBytes(Native Method) 10-16 13:33:13.218: E/TransferTask(3060): at libcore.io.Posix.write(Posix.java:178) 10-16 13:33:13.218: E/TransferTask(3060): at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191) 10-16 13:33:13.218: E/TransferTask(3060): at libcore.io.IoBridge.write(IoBridge.java:457) 10-16 13:33:13.218: E/TransferTask(3060): ... 2 more 

¿Alguien ha visto el código de trabajo para usar createPipe() para servir los medios a MediaPlayer ?

¡Gracias por adelantado!

  • MediaPlayer TimeoutException
  • Varios MediaPlayers no funcionan en Nexus 5
  • Prácticas recomendadas para la transmisión de audio
  • Android mediaplayer errores de audio / tartamudez sólo en los dispositivos más nuevos
  • IllegalStateException en MediaPlayer
  • Error de VideoView getCurrentPosition () en Acer Iconia A200
  • Error de MediaPlayer / VideoView de Android (1, -2147483648)
  • ¿Cómo puedo acceder a los códigos de estado de MediaMetadataRetriever.setDataSource (...)?
  • 3 Solutions collect form web for “¿Alguien tiene MediaPlayer trabajando con ParcelFileDescriptor y createPipe ()?”

    No estoy seguro de que esto pueda funcionar. Cuando ejecuto este código veo este rastreo:

     I/AudioSystem(30916): getting audio flinger I/AudioSystem(30916): returning new audio session id D/IAudioFlinger(30916): newAudioSessionId In D/AudioFlinger(28138): nextUniqueId, current 178 D/IAudioFlinger(30916): newAudioSessionId Out, id = 178 D/MediaPlayer(30916): setDataSource(Context context, content://com.commonsware.android.audiolstream/clip.ogg, Map<String, String> headers) in D/MediaPlayer(30916): setDataSource(FileDescriptor fd) in E/MediaPlayerService(28138): offset error 

    Ese "error de compensación" proviene de las siguientes líneas en MediaPlayerService.cpp en AOSP, donde hace un fstat () en el lado de lectura del tubo:

     status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length) { struct stat sb; int ret = fstat(fd, &sb); .... if (offset >= sb.st_size) { LOGE("offset error"); ::close(fd); return UNKNOWN_ERROR; } 

    Y sb.st_size se denomina -1 (vía getStatSize () en el ParcelFileDescriptor en el nivel Java). El manejador de errores cierra el descriptor, de ahí el error de tubería roto poco después.

    En mi experiencia MediaPlayer tiene muchos bits rotos como este. Nunca he visto que funcione para nada, pero directamente en los archivos locales, y (muy problemático) para la transmisión HTTP. Acabé portando FFmpeg para trabajar en torno a sus numerosas fallas.

    He intentado utilizar las pipas con MediaPlayer vía un ContentProvider usando PipeDataWriter (que utiliza básicamente una pipa y un hilo).

    El problema es que el descriptor de archivo esperado por el MediaPlayer, al menos para el contenido de video, debe ser buscable, y no se puede hacer un fseek en un tubo.

    En la tesis, openAssetFile() en su ContentProvider puede ser anulada. Un AssetFileDescriptor puede ser devuelto con el tamaño declarado y el desplazamiento.

     @Override public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException { ParcelFileDescriptor fd = openFile(uri, mode); return fd != null ? new AssetFileDescriptor(fd, offset, size) : null; } 

    Estos valores se pasan a setDataSource() nativo setDataSource() en MediaPlayer (compruebe el MediaPlayer.java para obtener más información).

    Si la comprobación de error en MediaPlayerService.cpp es (offset> = sb.st_size), un desplazamiento menor que -1 (el tamaño presumido del contenido) o un tamaño declarado positivo no desencadenan el error.

    Esto debería ser un buen punto de partida para un hack limpio, pero tengo mala suerte en mis pruebas. El mudo MediaPlayer parece leer todo el "archivo" antes de jugar, causando un tubo roto por delante.

    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.