Streaming audio da un URL in Android utilizzando MediaPlayer?


86

Ho provato a eseguire lo streaming di mp3 su http utilizzando la classe MediaPlayer incorporata di Android. La documentazione mi suggerirebbe che questo dovrebbe essere facile come:

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

Tuttavia ricevo ripetutamente quanto segue. Ho provato anche diversi URL. Per favore, non dirmi che lo streaming non funziona sugli 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)

Qualsiasi aiuto molto apprezzato, grazie S


Alcune domande: (1) quale versione dell'SDK stai utilizzando? (2) Su quali dispositivi stai provando? Funziona bene su SDK 2.0.1, test su un Droid.
Roman Nurik

Ciao Roman, grazie per aver dedicato del tempo. Sto provando questo contro 1.6 e sto usando un HTC Hero. Lo proverò su 2.01 alla luce dei tuoi commenti, ma sarebbe un risultato ridicolo se funzionasse solo su dispositivi 2.xe superiori fuori dalla scatola.
Pandalover

L'ho appena provato su un emulatore 2.01. Purtroppo non funziona. Sono curioso di provare questo contro un vero dispositivo 1.6 e un vero dispositivo 2.01. Sono nei test di Google il 4. Forse dovrò aspettare fino ad allora. Preferirei non doverlo fare però.
Pandalover

Non sospetto che 2.0 contro 2.0.1 farà alcuna differenza, ma l'emulatore contro un dispositivo live può fare la differenza. Sono sorpreso che questo non abbia funzionato su Hero. Lo esaminerò e vedrò se riesco a ottenere una risposta migliore. Inoltre, proprio come controllo di integrità, dovresti assicurarti di aver richiesto l'autorizzazione INTERNET nel manifest.
Roman Nurik

Ehi, appena fuori discussione, ho una domanda. Se utilizzo mp.setDataSource (URL_OF_FILE); Non è necessario salvare alcun file per lo streaming audio. Non è vero? In questo modo è il modo migliore per riprodurre in streaming l'audio da qualsiasi luogo. Qualche idea?
Bohemian

Risposte:


78

semplice Media Player con esempio di streaming.Per la parte xml hai bisogno di un pulsante con id button1 e due immagini nella tua cartella disegnabile con il nome button_pause e button_play e per favore non dimenticare di aggiungere l'autorizzazione Internet nel tuo manifest.

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;
    }
}

C'è un piccolo problema con questo, se blocco il mio telefono durante la riproduzione di MediaPlayer, la mia app si blocca quando lo sblocco.
CiaranC94

3
Ho appena provato a commentare la riga "mediaPlayer.release ()" in onPause (), e ora la mia app non si blocca allo sblocco.
CiaranC94

@PiyushMishra queste funzionalità sono accettate dalla console degli sviluppatori? Poiché la mia app viene rifiutata b'coz, ho usato la versione 4.x di Vitamio
Pallavi

35

Android MediaPlayer non supporta lo streaming di MP3 in modo nativo fino alla 2.2. Nelle versioni precedenti del sistema operativo sembra trasmettere solo 3GP in modo nativo. Puoi provare il codice pocketjourney, anche se è vecchio (c'è una nuova versione qui ) e ho avuto problemi a renderlo appiccicoso - balbettava ogni volta che riempiva il buffer.

L'app NPR News per Android è open source e utilizza un server proxy locale per gestire lo streaming MP3 nelle versioni del sistema operativo precedenti alla 2.2. Puoi vedere il codice pertinente nelle righe 199-216 (r94) qui: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/ PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

E questa è la classe StreamProxy: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=e4984187f45c39a54ea6c88f71197762dbe10e72

Anche l'app NPR riceve ancora "l'errore (-38, 0)" a volte durante lo streaming. Potrebbe essere un problema di threading o un problema di modifica della rete. Controlla il tracker dei problemi per gli aggiornamenti .


Ne sei assolutamente sicuro? La mia comprensione è che aveva a che fare con il tipo mimo. Potresti controllare se t funziona con il tipo MIME corretto prima della 2.1? Sto lavorando a qualcos'altro in questo momento e non ho potuto controllare per un po '.
Pandalover

1
Secondo le note di rilascio 2.2 ( developer.android.com/sdk/android-2.2-highlights.html ), include un "Nuovo framework multimediale (Stagefright) che supporta la riproduzione di file locali e lo streaming progressivo HTTP". In tutti i miei test non sono riuscito a ottenere un dispositivo 2.1 per lo streaming direttamente da un server shoutcast. Credo che il problema sia che i server shoutcast restituiscono un protocollo di ICY / 1.1 invece di HTTP / 1.1 e il lettore multimediale si blocca su questo perché non sa come rispondere a quel contenuto.
jwadsack

@jwadsack cosa succede se i file audio devono essere scaricati una volta e l'utente può riprodurre i file anche offline?
Devendra Singh

@DevendraSingh Non so se puoi salvare il file mentre è in streaming con l'attuale implementazione del lettore multimediale (questa risposta ha quasi cinque anni e molto è cambiato dalla 2.2). Se non altro, potresti creare un proxy seguendo questo esempio e scrivere il file nell'archivio mentre lo passi attraverso il proxy.
jwadsack

11

Immagino che tu stia cercando di riprodurre direttamente un .pls o qualcosa di simile.

prova questo:

1: il codice

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

2: il file .pls

Questo URL proviene dalla BBC solo come esempio. Era un file .pls che su Linux ho scaricato con

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

e poi ho aperto con vim (usa il tuo editor preferito;) e ho visto gli URL reali all'interno di questo file. Sfortunatamente non tutti i file .pls sono testo semplice come questo.

Ho letto che 1.6 non supporta lo streaming di mp3 su http, ma ho appena testato il codice sopra con Android 1.6 e 2.2 e non ho riscontrato alcun problema.

in bocca al lupo!


7
Ricorda che se vuoi riprodurre musica in streaming devi usare mediaplayer.prepareAsync e non mediaplayer.prepare. Pertanto non puoi usare mediaplayer.create () perché nessuna delle funzioni .create () porta il tuo oggetto Media Player direttamente nello stato Preparato, da cui non puoi chiamare prepareAsync, che devi fare per eseguire lo streaming. developer.android.com/reference/android/media/MediaPlayer.html
marienke

4

Uso

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

2

Ho avuto lo stesso errore che hai tu e si è scoperto che non c'era nulla di sbagliato nel codice. Il problema era che il server web inviava un'intestazione Content-Type errata.

Prova WireShark o qualcosa di simile per vedere quale tipo di contenuto sta inviando il server web.


per i file mp3 dovrebbe essere Content-Type: audio / mpeg che ha risolto il mio problema :)
doep

1
Come hai trasmesso quel file?
Nauman Khalid


1

Nessuna chiamata mp.start con un OnPreparedListener per evitare lo stato zero nel registro ..


Ricevo ancora la riga di registro 05-22 20: 26: 13.625: E / MediaPlayer (23818): stop chiamato nello stato 0 anche se avvio il mio Media Player nella funzione ready (). Ho anche una funzione onError in cui reimposto l'oggetto Media Player. Occorrono ancora fino a 2 minuti per avviare la riproduzione dello streaming. Vedere la mia domanda qui: stackoverflow.com/questions/16672568/...
marienke
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.