web-dev-qa-db-ger.com

Warum dauert es so lange, bis der MediaPlayer von Android einige Livestreams für die Wiedergabe vorbereitet?

Ich finde große Unterschiede in der Zeit, die der Android MediaPlayer benötigt, um die Live-Stream-Wiedergabe mit verschiedenen Streams vorzubereiten.

Die harten Daten

Ich habe die Protokollierung zwischen preparAsync () und dem onPrepared (MediaPlayer mp) -Rückruf hinzugefügt und mehrere Streams jeweils ein paar Mal getestet. Die Zeiten für jeden Strom waren sehr konstant (+/- eine Sekunde) und hier sind die Ergebnisse:

  1. MPR-Nachrichtenstrom: 27 Sekunden (http://newsstream1.publicradio.org:80/)
  2. MPR-Stream für klassische Musik: 15 Sekunden (http://classicalstream1.publicradio.org:80/)
  3. MPR Der aktuelle Stream: 7 Sekunden (http://currentstream1.publicradio.org:80/)
  4. PRI-Stream: 52 Sekunden (http://pri-ice.streamguys.biz/pri1)

Die Tests wurden an einem Nexus S mit Android 2.3.4 über eine 3G-Verbindung (~ 1100 Kbps) durchgeführt.

Das Abspielen von nicht-Streaming-MP3-Audiodateien ist kein Problem.

Hier sind ein paar Ausschnitte davon, wie ich die Streams spiele:

Bereiten Sie den MediaPlayer vor:

...
mediaPlayer.setDataSource(playUrl);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepareAsync();
...

Dann in onPrepared (MediaPlayer mp):

mediaPlayer.start();

Warum dauert es so lange, einige Streams vorzubereiten, andere aber nicht? Die obigen Daten lassen vermuten, dass möglicherweise auf dem Betrag der Daten basiert, die gepuffert wurden, und nicht auf dem duration des gepufferten Audioinhalts. Könnte das wirklich sein?

Update: Ich habe Live-Streaming auf physischen Geräten mit Android 1.6, 2.2 und 2.3.4 und Emulatoren mit 1.6, 2.1, 2.2, 2.3.1 und 2.3.3 getestet. Ich sehe nur die lange Verzögerung in 2.3.3 und 2.3.4. Die älteren Versionen starten die Wiedergabe innerhalb von 5 Sekunden.

47
Jeremy Haberman

Es scheint, dass es eine feste Datenmenge anstelle einer festen Zeitdauer puffert. Für jeden, der die Bitraten verschiedener NPR-Streams nicht kennt, sehen die Daten so aus:

  1. MPR-Nachrichtenstrom: 27 Sekunden ( http://newsstream1.publicradio.org:80/ ), 64 kbps
  2. MPR-Stream für klassische Musik: 15 Sekunden ( http://classicalstream1.publicradio.org:80/ ), 128 kbps
  3. MPR Der aktuelle Stream: 7 Sekunden ( http://currentstream1.publicradio.org:80/ ), 128 kbps
  4. PRI-Stream: 52 Sekunden ( http://pri-ice.streamguys.biz/pri1 ), 32 kbps

Abgesehen von der Diskrepanz zwischen den beiden 128-kbps-Strömen besteht eine sehr gute Korrelation zwischen der Bitrate und der Pufferdauer.

In jedem Fall ist Android Open-Source, sodass Sie immer schauen können, was es tut . Leider sind prepareAsync() und prepare() native Methoden, und es scheint, dass Ereignisse, die mit dem Puffer zusammenhängen, auch von einem systemeigenen Prozess ausgelöst werden. 

Haben Sie versucht, eine OnBufferingUpdateListener an den MediaPlayer anzuhängen, um feinere Updates über den Pufferstatus zu erhalten? Es kann interessant sein, die Rate zu vergleichen, mit der die Ereignisse übermittelt werden und um wie viel Prozent der Puffer für jedes Ereignis in den verschiedenen Streams gefüllt wird. Sie können auf die Stream-Bitraten verweisen, und wenn 4 Sekunden Pufferung bei 32 kbps den Puffer zu demselben Prozentsatz wie 1 Sekunde Pufferung bei 128 kbps füllen, haben Sie Ihre Antwort gefunden.

23
aroth

Wechseln Sie MediaPlayer durch FFmpegMediaPlayer funktioniert viel besser als die MediaPlayer wenn Sie Ihre Streams testen möchten, können Sie dies über die demo tun, die sie haben.

7
4gus71n

Ich habe dieses Problem kürzlich mit einem Streaming-Audio-Provider debuggt. Das Problem bezieht sich auf Stagefright- und Streaming-Quellen mit 32 Kbit/s und weniger. Wir haben das gleiche Streaming durchlaufen und die Antwortzeit mit 24, 32, 48, 64 und 128 kbps gemessen.

  • 24 -> 46 Sekunden zum Starten des Streamings
  • 32 -> 24 Sekunden, um mit dem Streaming zu beginnen
  • 48 -> 2 Sekunden zum Starten des Streamings
  • 64 -> 2 Sekunden zum Starten des Streamings
  • 128 -> 2 Sekunden zum Starten des Streamings

Hierbei handelt es sich um eine konsistente drahtlose Verbindung, die bei jeder Bitrate über 10 Versuche gemittelt wird. Der Schlüssel war, wie Travis betonte, der, dass der Bühnenfrost nicht herausfinden konnte, wie lange das Audio gepuffert werden sollte. Manchmal sah ich eine Meldung 'error: 1, -21492389' oder so, was den Stagefright-Spieler lautlos zum Absturz brachte. Ich versuchte, das aufzuspüren, und kam schließlich zu dem Schluss, dass die sehr langsamen Streams (unter 24 kbps) einen Pufferüberlauf verursachten, da sie zwischenspeichern würden, bis das Gerät keinen Platz mehr für den Audiostream hatte.

Ich wollte hinzufügen, dass OnBufferingUpdateListener während des gesamten Tests für mich überhaupt nicht ausgelöst wurde. Ich weiß nicht, wozu es da ist. Ich denke, der einzige Weg, um zu sagen, wie das Laden abläuft, besteht darin, das Laden ähnlich wie bei der oben erwähnten NPR-App zu testen.

4
Nick Campion

Wenn Sie von Icecast aus streamen, werfen Sie einen Blick auf die Einstellung burst-size:

Die Burst-Größe ist die Datenmenge (in Bytes), die an einen Client gesendet werden soll zur Verbindungszeit. Wie bei Burst-on-Connect soll dies schnell das .__ füllen. Vorpuffer für Mediaplayer. Der Standardwert ist 64 KByte. Dies ist eine Typische Größe, die von den meisten Clients verwendet wird. Daher ist das Ändern normalerweise nicht __. erforderlich. Diese Einstellung gilt für alle Mountpunkte, sofern sie nicht in .__ überschrieben werden. die Mount-Einstellungen. Stellen Sie sicher, dass dieser Wert kleiner ist als die Warteschlangengröße Erhöhen Sie ggf. die Warteschlangengröße, um größer als gewünscht zu sein Burst-Größe. Andernfalls kann es zu einem Abbruch des Listener-Clients kommen Verbindungsversuche aufgrund eines anfänglichen Bursts, der zur Verbindung führt bereits die Warteschlangengröße überschritten.

Ich erhöhte den burst-size auf 131072 auf meinem Server und jetzt spielt meine auf MediaPlayer basierende Android-App Streams ohne viel Verzögerung ab.

2
Matt Harrington

Ich habe dies mit 10 Datenpunkten ausprobiert, drei schnell, 7 langsam .. __ Es ist konsistent, dass ein schneller Stream schnell und ein langsamer immer langsam ist.

Ich denke, es hängt mit der vom Server bereitgestellten "Inhaltslänge" zusammen. Android weiß nicht, wie viel gepuffert werden soll, wenn die Inhaltslänge nicht ordnungsgemäß angegeben wird.

Könnte falsch sein, ging nicht so weit wie Wiresharking.

1
Travis Biehn

Als ich dieses Problem hatte, entschied ich mich vor dem Öffnen des Players zu testen, ob Stream verfügbar ist. Wenn Sie den Benutzer veranlassen, lange zu warten, und die Musik startet die Musik in Ordnung (dies ist nicht der Fall, aber nehmen wir an, es ist in Ordnung). Der schlimmste Fall ist, ihn dazu zu zwingen, lange zu warten, und die Musik wird gestartet Beginnen Sie nie! .__ So haben wir zwei Situationen:

  • Das Live-Streaming-Szenario wie ein Radiosender.
  • Die aufgezeichnete MP3-Datei, die online verfügbar ist.

Beim Radio-Szenario könnten wir prüfen, ob der Port Verbindungen akzeptiert (Zustand Öffnen/Schließen). Wenn es geöffnet ist, bereiten Sie den Player auf die Musik vor, sonst bereiten Sie sie überhaupt nicht vor.

public static boolean isLiveStreamingAvailable() {
        SocketAddress sockaddr = new InetSocketAddress(STREAMING_Host, STREAMING_PORT);
        // Create your socket
        Socket socket = new Socket();
        boolean online = true;
        // Connect with 10 s timeout
        try {
            socket.connect(sockaddr, 10000);
        } catch (SocketTimeoutException stex) {
            // treating timeout errors separately from other io exceptions
            // may make sense
            return false;
        } catch (IOException iOException) {
            return false;
        } finally {
            // As the close() operation can also throw an IOException
            // it must caught here
            try {
                socket.close();
            } catch (IOException ex) {
                // feel free to do something moderately useful here, eg log the event
            }

        }
        return true;
    }

Beim mp3-Dateiszenario sind die Dinge ein bisschen anders. Sie sollten nach dem Antwortcode suchen, der auf die http-Anforderung folgt.

public static boolean isRecordedStreamingAvailable() {
        try {
            HttpURLConnection.setFollowRedirects(false);
            // note : you may also need
            //        HttpURLConnection.setInstanceFollowRedirects(false)
            HttpURLConnection con =
                    (HttpURLConnection) new URL(RECORDED_URL).openConnection();
            con.setRequestMethod("HEAD");
            return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
0
LiTTle