Streaming audio depuis une URL sous Android à l'aide de MediaPlayer

86

J'ai essayé de diffuser des mp3 sur http en utilisant la classe MediaPlayer intégrée à Android. La documentation me suggère que cela devrait être aussi simple que:

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

Cependant, je reçois ce qui suit à plusieurs reprises. J'ai également essayé différentes URL. Ne me dites pas que le streaming ne fonctionne pas sur les 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)

Toute aide très appréciée, merci S

Pandalover
la source
Quelques questions: (1) quelle version du SDK utilisez-vous? (2) Sur quel (s) appareil (s) testez-vous? Cela fonctionne bien sur le SDK 2.0.1, en testant sur un droïde.
Roman Nurik
Salut Roman, merci d'avoir pris le temps. J'essaye ceci contre 1.6 et j'utilise un HTC Hero. Je vais l'essayer sur 2.01 à la lumière de vos commentaires, mais ce serait un résultat ridicule si cela ne fonctionnait que sur les appareils 2.x et supérieurs prêts à l'emploi.
Pandalover
Je viens de l'essayer sur un émulateur 2.01. Cela ne fonctionne pas malheureusement. Je suis intrigué d'essayer ceci contre un vrai appareil 1.6 et un vrai appareil 2.01. Je suis en test Google le 4. Je devrai peut-être attendre jusque-là. Je préférerais ne pas avoir à le faire.
Pandalover
Je ne pense pas que 2.0 contre 2.0.1 fera une différence, mais l'émulateur contre un appareil en direct peut faire une différence. Je suis surpris que cela n'ait pas fonctionné sur le héros. Je vais l'examiner et voir si je peux obtenir une meilleure réponse. Oh aussi, juste pour vérifier la cohérence, vous devez vous assurer que vous avez demandé l'autorisation INTERNET dans le manifeste.
Roman Nurik
Hé juste en dehors de la discussion, j'ai une question. Si j'utilise mp.setDataSource (URL_OF_FILE); Nous n'avons pas besoin de sauvegarder de fichier pour le streaming audio. N'est-ce pas? De cette façon, c'est le meilleur moyen de diffuser de l'audio depuis n'importe quel endroit. Des idées?
Bohemian

Réponses:

78

Lecteur multimédia simple avec exemple de streaming.Pour la partie xml, vous avez besoin d'un bouton avec id button1 et de deux images dans votre dossier dessinable avec le nom button_pause et button_play et n'oubliez pas d'ajouter l'autorisation Internet dans votre manifeste.

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
la source
Il y a un léger problème avec cela, si je verrouille mon téléphone pendant la lecture du MediaPlayer, mon application se bloque lorsque je la déverrouille.
CiaranC94
3
Je viens d'essayer de commenter la ligne "mediaPlayer.release ()" dans onPause (), et maintenant mon application ne plante pas lors du déverrouillage.
CiaranC94
@PiyushMishra ces fonctionnalités sont-elles acceptées par la console développeur? Comme mon application est rejetée b'coz, j'ai utilisé la version Vitamio 4.x
Pallavi
35

Android MediaPlayer ne prend pas en charge le streaming de MP3 de manière native jusqu'à la version 2.2. Dans les anciennes versions du système d'exploitation, il semble que le flux 3GP ne soit diffusé qu'en mode natif. Vous pouvez essayer le code pocketjourney, bien qu'il soit ancien (il y a une nouvelle version ici ) et j'ai eu du mal à le rendre collant - il bégayait chaque fois qu'il remplissait le tampon.

L'application NPR News pour Android est open source et utilise un serveur proxy local pour gérer le streaming MP3 dans les versions du système d'exploitation antérieures à la 2.2. Vous pouvez voir le code correspondant aux lignes 199-216 (r94) ici: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/ PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

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

L'application NPR reçoit également parfois «l'erreur (-38, 0)» lors de la diffusion. Cela peut être un problème de thread ou un problème de changement de réseau. Vérifiez le suivi des problèmes pour les mises à jour .

jwadsack
la source
En êtes-vous absolument sûr? Je crois comprendre que c'était à voir avec le type mime. Pourriez-vous vérifier si t fonctionne avec le bon type MIME avant 2.1? Je travaille sur autre chose en ce moment et je n'ai pas pu vérifier pendant un moment.
Pandalover
1
Selon les notes de publication de la version 2.2 ( developer.android.com/sdk/android-2.2-highlights.html ), il inclut un «nouveau cadre multimédia (Stagefright) qui prend en charge la lecture de fichiers locaux et le streaming progressif HTTP». Dans tous mes tests, je n'ai pas pu obtenir un appareil 2.1 pour diffuser directement à partir d'un serveur shoutcast. Je crois que le problème est que les serveurs shoutcast renvoient un protocole ICY / 1.1 plutôt que HTTP / 1.1 et que le lecteur multimédia se déclenche car il ne sait pas comment répondre à ce contenu.
jwadsack
@jwadsack et si les fichiers audio devaient être téléchargés une fois et que l'utilisateur pouvait également lire les fichiers hors ligne?
Devendra Singh du
@DevendraSingh Je ne sais pas si vous pouvez enregistrer le fichier pendant qu'il est en streaming avec l'implémentation actuelle du lecteur multimédia (cette réponse a presque cinq ans et beaucoup de choses ont changé depuis 2.2). Si rien d'autre, vous pouvez créer un proxy en suivant cet exemple et écrire le fichier dans le stockage pendant que vous le transmettez via le proxy.
jwadsack du
11

Je suppose que vous essayez de jouer un .pls directement ou quelque chose de similaire.

essayez ceci:

1: le code

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

2: le fichier .pls

Cette URL est de la BBC à titre d'exemple. C'était un fichier .pls que j'ai téléchargé sous Linux avec

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

puis j'ai ouvert avec vim (utilisez votre éditeur préféré;) et j'ai vu les vraies URL à l'intérieur de ce fichier. Malheureusement, tous les .pls ne sont pas du texte brut comme ça.

J'ai lu que 1.6 ne prendrait pas en charge le streaming mp3 sur http, mais, je viens de tester le code ci-dessus avec Android 1.6 et 2.2 et je n'ai eu aucun problème.

bonne chance!

Pabluez
la source
7
N'oubliez pas que si vous souhaitez diffuser de la musique en streaming, vous devez utiliser mediaplayer.prepareAsync et non mediaplayer.prepare. Par conséquent, vous ne pouvez pas utiliser mediaplayer.create () car l'une des fonctions .create () prend votre objet Media Player directement dans l'état Préparé, à partir duquel vous ne pouvez pas appeler prepareAsync, ce que vous devez faire pour diffuser. developer.android.com/reference/android/media/MediaPlayer.html
marienke
4

Utilisation

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

J'ai eu la même erreur que vous et il s'est avéré qu'il n'y avait rien de mal avec le code. Le problème était que le serveur Web envoyait le mauvais en-tête Content-Type.

Essayez WireShark ou quelque chose de similaire pour voir quel type de contenu le serveur Web envoie.

Doep
la source
pour les fichiers mp3, il devrait être Content-Type: audio / mpeg Cela a résolu mon problème :)
doep
1
Comment avez-vous diffusé ce fichier?
Nauman Khalid
2

À la recherche de mes projets:

  1. https://github.com/master255/ImmortalPlayer Prise en charge de http / FTP, un thread pour lire, envoyer et enregistrer les données en cache. Le moyen le plus simple et le travail le plus rapide. Logique complexe - la meilleure façon!
  2. https://github.com/master255/VideoViewCache Simple Videoview avec cache. Deux threads pour jouer et enregistrer des données. Mauvaise logique, mais si vous en avez besoin, utilisez ceci.
Maître
la source
1

Aucun appel mp.start avec un OnPreparedListener pour éviter l'état zéro dans le journal.

Fred Grott
la source
Je reçois toujours la ligne de journal 05-22 20: 26: 13.625: E / MediaPlayer (23818): stop appelé à l'état 0 même si je démarre mon Media Player dans la fonction prepare (). J'ai également une fonction onError où je réinitialise l'objet Media Player. La lecture de mon flux prend encore jusqu'à 2 minutes. Voir ma question ici: stackoverflow.com/questions/16672568/…
marienke