Audio von einer URL in Android mit MediaPlayer streamen?

86

Ich habe versucht, MP3s über http mit der in Android integrierten MediaPlayer-Klasse zu streamen. Die Dokumentation würde mir vorschlagen, dass dies so einfach sein sollte wie:

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

Ich erhalte jedoch wiederholt Folgendes. Ich habe auch verschiedene URLs ausprobiert. Bitte sag mir nicht, dass Streaming auf MP3s nicht funktioniert.

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)

Jede Hilfe sehr geschätzt, danke S.

Pandalover
quelle
Einige Fragen: (1) Welche SDK-Version verwenden Sie? (2) Auf welchen Geräten testen Sie? Dies funktioniert gut mit SDK 2.0.1, das auf einem Droid getestet wird.
Roman Nurik
Hallo Roman, danke, dass du dir die Zeit genommen hast. Ich versuche dies gegen 1.6 und benutze ein HTC Hero. Ich werde es in Anbetracht Ihrer Kommentare auf 2.01 versuchen, aber es wäre ein lächerliches Ergebnis, wenn dies nur auf Geräten der Version 2.x und höher funktionieren würde.
Pandalover
Habe es gerade auf einem 2.01 Emulator versucht. Funktioniert leider nicht. Ich bin fasziniert, dies gegen ein echtes 1.6-Gerät und ein echtes 2.01-Gerät zu versuchen. Ich bin in Google Test am 4 .. Vielleicht muss ich bis dahin warten. Ich würde es aber lieber nicht müssen.
Pandalover
Ich vermute nicht, dass 2.0 vs. 2.0.1 einen Unterschied machen wird, aber Emulator vs. ein Live-Gerät kann einen Unterschied machen. Ich bin überrascht, dass dies beim Hero nicht funktioniert hat. Ich werde es mir ansehen und sehen, ob ich eine bessere Antwort bekommen kann. Außerdem sollten Sie nur zur Überprüfung der geistigen Gesundheit sicherstellen, dass Sie die INTERNET-Berechtigung im Manifest angefordert haben.
Roman Nurik
Hey, nur aus der Diskussion heraus, ich habe eine Frage. Wenn ich mp.setDataSource (URL_OF_FILE) verwende; Wir müssen keine Datei für das Audio-Streaming speichern. Ist es nicht? Auf diese Weise können Sie Audio von jedem Ort aus am besten streamen. Irgendwelche Ideen?
Böhmische

Antworten:

78

einfacher Media Player mit Streaming-Beispiel. Für den XML-Teil benötigen Sie eine Schaltfläche mit der ID button1 und zwei Bilder in Ihrem Zeichenordner mit den Namen button_pause und button_play. Vergessen Sie nicht, die Internetberechtigung in Ihr Manifest aufzunehmen.

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
quelle
Es gibt ein kleines Problem damit: Wenn ich mein Telefon sperre, während der MediaPlayer abgespielt wird, stürzt meine App ab, wenn ich es entsperre.
CiaranC94
3
Ich habe gerade versucht, die Zeile "mediaPlayer.release ()" in onPause () auskommentieren zu lassen, und jetzt stürzt meine App beim Entsperren nicht ab.
CiaranC94
@PiyushMishra diese Funktion wird von der Entwicklerkonsole akzeptiert? Da meine App abgelehnt wird, habe ich Vitamio 4.x Version
Pallavi
35

Android MediaPlayer unterstützt das native Streaming von MP3 erst ab 2.2. In älteren Versionen des Betriebssystems scheint es nur 3GP nativ zu streamen. Sie können den Taschenreisecode ausprobieren, obwohl er alt ist (es gibt einen neue Version ) und ich Probleme hatte, ihn klebrig zu machen - er würde stottern, wenn er den Puffer wieder auffüllt.

Die NPR News App für Android ist Open Source und verwendet einen lokalen Proxyserver, um MP3-Streaming in Versionen des Betriebssystems vor 2.2 zu verarbeiten. Sie können den entsprechenden Code in den Zeilen 199-216 (r94) hier sehen: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/ PlaybackService.java?r=7cf2352b5c3c0fbcdc18a5a8c67d836577e7e8e3

Und das ist die StreamProxy-Klasse: http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java?r=e4984187f45c39a54ea6c88f71197762dbe10e72

Die NPR-App erhält beim Streaming manchmal immer noch den "Fehler (-38, 0)". Dies kann ein Threading-Problem oder ein Netzwerkänderungsproblem sein. Überprüfen Sie den Issue-Tracker auf Updates .

Jwadsack
quelle
Bist du dir da absolut sicher? Mein Verständnis ist, dass es mit dem Pantomimentyp zu tun hatte. Können Sie überprüfen, ob t mit dem richtigen MIME-Typ vor 2.1 funktioniert? Ich arbeite gerade an etwas anderem und konnte es eine Weile nicht überprüfen.
Pandalover
1
Gemäß den Versionshinweisen zu 2.2 ( developer.android.com/sdk/android-2.2-highlights.html ) enthält es ein "New Media Framework (Stagefright), das die lokale Dateiwiedergabe und das progressive HTTP-Streaming unterstützt". Bei all meinen Tests konnte ich kein 2.1-Gerät direkt von einem Shoutcast-Server streamen lassen. Ich glaube, dass das Problem darin besteht, dass Shoutcast-Server ein Protokoll von ICY / 1.1 anstelle von HTTP / 1.1 zurückgeben und der Media Player darauf reagiert, da er nicht weiß, wie er auf diesen Inhalt reagieren soll.
Jwadsack
@jwadsack Was ist, wenn die Audiodateien einmal heruntergeladen werden sollen und der Benutzer die Dateien dann auch offline abspielen kann?
Devendra Singh
@ DevendraSingh Ich weiß nicht, ob Sie die Datei speichern können, während sie mit der aktuellen Media Player-Implementierung gestreamt wird (diese Antwort ist fast fünf Jahre alt und hat sich seit 2.2 stark geändert). Wenn nichts anderes, können Sie nach diesem Beispiel einen Proxy erstellen und die Datei in den Speicher schreiben, während Sie sie durch den Proxy leiten.
Jwadsack
11

Ich denke, dass Sie versuchen, ein .pls direkt oder ähnliches zu spielen.

Probieren Sie es aus:

1: der Code

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

2: die .pls-Datei

Diese URL stammt nur als Beispiel von BBC. Es war eine .pls-Datei, die ich unter Linux heruntergeladen habe

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

und dann habe ich mit vim geöffnet (benutze deinen Lieblingseditor;) und ich habe die echten URLs in dieser Datei gesehen. Leider sind nicht alle .pls so einfach.

Ich habe gelesen, dass 1.6 das Streamen von MP3 über http nicht unterstützen würde, aber ich habe gerade den obigen Code mit Android 1.6 und 2.2 getestet und hatte kein Problem.

Viel Glück!

Pabluez
quelle
6
Denken Sie daran, dass Sie beim Streamen von Musik mediaplayer.prepareAsync und nicht mediaplayer.prepare verwenden müssen. Daher können Sie mediaplayer.create () nicht verwenden, da eine der Funktionen .create () Ihr Media Player-Objekt direkt in den Status "Vorbereitet" versetzt, von dem aus Sie "prepareAsync" nicht aufrufen können, das Sie zum Streamen benötigen. developer.android.com/reference/android/media/MediaPlayer.html
marienke
4

Verwenden

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

Ich hatte den gleichen Fehler wie Sie und es stellte sich heraus, dass mit dem Code nichts falsch war. Das Problem war, dass der Webserver den falschen Content-Type-Header sendete.

Versuchen Sie es mit Wireshark oder ähnlichem, um festzustellen, welchen Inhaltstyp der Webserver sendet.

doep
quelle
für mp3-
dateien
1
Wie haben Sie diese Datei gestreamt?
Nauman Khalid
1

Kein Aufruf mp.start mit einem OnPreparedListener, um den Nullzustand im Protokoll zu vermeiden.

Fred Grott
quelle
Ich erhalte immer noch die Protokollzeile 05-22 20: 26: 13.625: E / MediaPlayer (23818): Stopp im Status 0 aufgerufen, obwohl ich meinen Media Player in der Funktion prepare () starte. Ich habe auch eine onError-Funktion, mit der ich das Media Player-Objekt zurücksetze. Es dauert immer noch bis zu 2 Minuten, bis mein Stream abgespielt wird. Siehe meine Frage hier: stackoverflow.com/questions/16672568/…
marienke