¿Transmitir audio desde una URL en Android usando MediaPlayer?

86

He estado tratando de transmitir mp3 a través de http usando la clase MediaPlayer integrada de Android. La documentación me sugeriría que esto debería ser tan fácil como:

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(URL_OF_FILE);
mp.prepare();
mp.start();

Sin embargo, obtengo lo siguiente repetidamente. También probé diferentes URL. Por favor, no me digas que la transmisión no funciona en mp3.

E/PlayerDriver(   31): Command PLAYER_SET_DATA_SOURCE completed with an error or info PVMFErrNotSupported
W/PlayerDriver(   31): PVMFInfoErrorHandlingComplete
E/MediaPlayer(  198): error (1, -4)
E/MediaPlayer(  198): start called in state 0
E/MediaPlayer(  198): error (-38, 0)
E/MediaPlayer(  198): Error (1,-4)
E/MediaPlayer(  198): Error (-38,0)

Cualquier ayuda muy apreciada, gracias S

Pandalover
fuente
Algunas preguntas: (1) ¿Qué versión de SDK estás usando? (2) ¿En qué dispositivo (s) está probando? Esto funciona bien en SDK 2.0.1, probando en un Droid.
Roman Nurik
Hola Roman, gracias por tomarte el tiempo. Estoy probando esto contra 1.6 y estoy usando un HTC Hero. Lo probaré en 2.01 a la luz de sus comentarios, pero sería un resultado ridículo si esto solo funcionara en dispositivos 2.xy superiores listos para usar.
Pandalover
Lo probé en un emulador 2.01. Desafortunadamente, no funciona. Estoy intrigado por probar esto contra un dispositivo 1.6 real y un dispositivo 2.01 real. Estoy en las pruebas de Google el día 4. Quizás tenga que esperar hasta entonces. Sin embargo, preferiría no tener que hacerlo.
Pandalover
No sospecho que 2.0 vs. 2.0.1 hará alguna diferencia, pero el emulador vs. un dispositivo en vivo puede marcar la diferencia. Me sorprende que esto no haya funcionado en Hero. Lo investigaré y veré si puedo obtener una mejor respuesta. Oh, también, solo como una verificación de cordura, debe asegurarse de haber solicitado el permiso de INTERNET en el manifiesto.
Roman Nurik
Oye, salgo de la discusión, tengo una pregunta. Si uso mp.setDataSource (URL_OF_FILE); No necesitamos guardar ningún archivo para la transmisión de audio. ¿No es así? De esa manera, es la mejor manera de transmitir audio desde cualquier ubicación. ¿Algunas ideas?
Bohemio

Respuestas:

78

Reproductor multimedia simple con ejemplo de transmisión.Para la parte xml, necesita un botón con id button1 y dos imágenes en su carpeta dibujable con el nombre button_pause y button_play y no olvide agregar el permiso de Internet en su manifiesto.

public class MainActivity extends Activity {
private Button btn;
/**
 * help to toggle between play and pause.
 */
private boolean playPause;
private MediaPlayer mediaPlayer;
/**
 * remain false till media is not completed, inside OnCompletionListener make it true.
 */
private boolean intialStage = true;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn = (Button) findViewById(R.id.button1);
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    btn.setOnClickListener(pausePlay);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

private OnClickListener pausePlay = new OnClickListener() {

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        // TODO Auto-generated method stub

        if (!playPause) {
            btn.setBackgroundResource(R.drawable.button_pause);
            if (intialStage)
                new Player()
                        .execute("http://www.virginmegastore.me/Library/Music/CD_001214/Tracks/Track1.mp3");
            else {
                if (!mediaPlayer.isPlaying())
                    mediaPlayer.start();
            }
            playPause = true;
        } else {
            btn.setBackgroundResource(R.drawable.button_play);
            if (mediaPlayer.isPlaying())
                mediaPlayer.pause();
            playPause = false;
        }
    }
};
/**
 * preparing mediaplayer will take sometime to buffer the content so prepare it inside the background thread and starting it on UI thread.
 * @author piyush
 *
 */

class Player extends AsyncTask<String, Void, Boolean> {
    private ProgressDialog progress;

    @Override
    protected Boolean doInBackground(String... params) {
        // TODO Auto-generated method stub
        Boolean prepared;
        try {

            mediaPlayer.setDataSource(params[0]);

            mediaPlayer.setOnCompletionListener(new OnCompletionListener() {

                @Override
                public void onCompletion(MediaPlayer mp) {
                    // TODO Auto-generated method stub
                    intialStage = true;
                    playPause=false;
                    btn.setBackgroundResource(R.drawable.button_play);
                    mediaPlayer.stop();
                    mediaPlayer.reset();
                }
            });
            mediaPlayer.prepare();
            prepared = true;
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            Log.d("IllegarArgument", e.getMessage());
            prepared = false;
            e.printStackTrace();
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            prepared = false;
            e.printStackTrace();
        }
        return prepared;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        if (progress.isShowing()) {
            progress.cancel();
        }
        Log.d("Prepared", "//" + result);
        mediaPlayer.start();

        intialStage = false;
    }

    public Player() {
        progress = new ProgressDialog(MainActivity.this);
    }

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        this.progress.setMessage("Buffering...");
        this.progress.show();

    }
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    if (mediaPlayer != null) {
        mediaPlayer.reset();
        mediaPlayer.release();
        mediaPlayer = null;
    }
}
PiyushMishra
fuente
Hay un pequeño problema con esto, si bloqueo mi teléfono mientras se reproduce MediaPlayer, mi aplicación se bloquea cuando la desbloqueo.
CiaranC94
3
Intenté comentar la línea "mediaPlayer.release ()" en onPause (), y ahora mi aplicación no se bloquea al desbloquear.
CiaranC94
@PiyushMishra ¿esta función es aceptada por la consola de desarrollo? Como mi aplicación es rechazada, porque he usado la versión Vitamio 4.x
Pallavi
35

Android MediaPlayer no admite la transmisión de MP3 de forma nativa hasta la 2.2. En versiones anteriores del sistema operativo, parece que solo transmite 3GP de forma nativa. Puede probar el código pocketjourney, aunque es antiguo (hay una nueva versión aquí ) y tuve problemas para hacerlo pegajoso: tartamudeaba cada vez que rellenaba el búfer.

La aplicación NPR News para Android es de código abierto y utiliza un servidor proxy local para manejar la transmisión de MP3 en versiones del sistema operativo anteriores a la 2.2. Puede ver el código relevante en las líneas 199-216 (r94) aquí: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/ PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

Y esta es la clase StreamProxy: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=e4984187f45c39a54ea6c88f71197762dbe10e72

La aplicación NPR también sigue recibiendo el "error (-38, 0)" a veces durante la transmisión. Esto puede ser un problema de subprocesos o un problema de cambio de red. Consulte el rastreador de problemas para obtener actualizaciones .

jwadsack
fuente
¿Estás absolutamente seguro de esto? Tengo entendido que tenía que ver con el tipo mimo. ¿Podría comprobar si t funciona con el tipo MIME correcto antes de 2.1? Estoy trabajando en otra cosa en este momento y no pude comprobarlo durante un tiempo.
Pandalover
1
Según las notas de la versión 2.2 ( developer.android.com/sdk/android-2.2-highlights.html ), incluye un "Nuevo marco de medios (Stagefright) que admite la reproducción de archivos locales y la transmisión progresiva HTTP". En todas mis pruebas, no pude hacer que un dispositivo 2.1 transmitiera directamente desde un servidor shoutcast. Creo que el problema es que los servidores shoutcast devuelven un protocolo de ICY / 1.1 en lugar de HTTP / 1.1 y el reproductor multimedia se tropieza con esto porque no sabe cómo responder a ese contenido.
jwadsack
@jwadsack, ¿qué pasa si los archivos de audio deben descargarse una vez y el usuario también puede reproducirlos sin conexión?
Devendra Singh
@DevendraSingh No sé si puede guardar el archivo mientras se transmite con la implementación actual del reproductor multimedia (esta respuesta tiene casi cinco años y ha cambiado mucho desde 2.2). Si nada más, puede crear un proxy siguiendo este ejemplo y escribir el archivo en el almacenamiento mientras lo pasa a través del proxy.
jwadsack
11

Supongo que estás intentando reproducir un .pls directamente o algo similar.

probar esto:

1: el código

mediaPlayer = MediaPlayer.create(this, Uri.parse("http://vprbbc.streamguys.net:80/vprbbc24.mp3"));
mediaPlayer.start();

2: el archivo .pls

Esta URL es de BBC solo como ejemplo. Era un archivo .pls que descargué en linux con

wget http://foo.bar/file.pls

y luego abrí con vim (usa tu editor favorito;) y he visto las URL reales dentro de este archivo. Desafortunadamente, no todos los .pls son texto sin formato como ese.

He leído que 1.6 no admitiría la transmisión de mp3 a través de http, pero acabo de probar el código obove con Android 1.6 y 2.2 y no tuve ningún problema.

¡buena suerte!

Pabluez
fuente
7
Recuerde que si desea transmitir música, debe usar mediaplayer.prepareAsync y no mediaplayer.prepare. Por lo tanto, no puede usar mediaplayer.create () porque cualquiera de las funciones .create () lleva su objeto Media Player directamente al estado Preparado, desde el cual no puede llamar a prepareAsync, que debe hacerlo para transmitir. developer.android.com/reference/android/media/MediaPlayer.html
marienke
4

Utilizar

 mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
 mediaplayer.prepareAsync();
 mediaplayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
      @Override
      public void onPrepared(MediaPlayer mp) {
          mediaplayer.start();
      }
 });
Shshank Bhong
fuente
2

Tuve el mismo error que tú y resultó que no había ningún problema con el código. El problema era que el servidor web estaba enviando un encabezado de tipo de contenido incorrecto.

Pruebe Wireshark o algo similar para ver qué tipo de contenido está enviando el servidor web.

doep
fuente
para archivos mp3 debería ser Content-Type: audio / mpeg Eso resolvió mi problema :)
doep
1
¿Cómo transmitiste ese archivo?
Nauman Khalid
1

No llame a mp.start con un OnPreparedListener para evitar el estado cero en el registro.

Fred Grott
fuente
Todavía obtengo la línea de registro 05-22 20: 26: 13.625: E / MediaPlayer (23818): detener la llamada en el estado 0 aunque inicie mi reproductor multimedia en la función preparada (). También tengo una función onError donde restablezco el objeto Media Player. Todavía se necesitan hasta 2 minutos para que mi transmisión comience a reproducirse. Vea mi pregunta aquí: stackoverflow.com/questions/16672568/…
marienke