web-dev-qa-db-ja.com

AndroidのMediaPlayerが再生用にいくつかのライブストリームを準備するのになぜこんなに時間がかかるのですか?

Android MediaPlayerが異なるストリームでのライブストリーム再生の準備にかかる時間に大きな違いを見つけています。

ハードデータ

PrepareAsync()とonPrepared(MediaPlayer mp)コールバックの間にロギングを追加し、いくつかのストリームをそれぞれ数回テストしました。各ストリームの時間は非常に一貫しており(+/- 1秒)、結果は次のとおりです。

  1. MPRニュースストリーム:27秒(http://newsstream1.publicradio.org:80/)
  2. MPRクラシック音楽ストリーム:15秒(http://classicalstream1.publicradio.org:80/)
  3. MPR現在のストリーム:7秒(http://currentstream1.publicradio.org:80/)
  4. PRIストリーム:52秒(http://pri-ice.streamguys.biz/pri1)

テストは、Android 2.3.4の3G接続(〜1100 Kbps)のNexus Sで実行されました。

非ストリーミングMP3オーディオファイルの再生は問題ではありません。

以下は、ストリームの再生方法のスニペットです。

MediaPlayerを準備します。

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

次に、onPrepared(MediaPlayer mp)で:

mediaPlayer.start();

一部のストリームを準備するのに他のストリームを準備するのにそれほど時間がかかるのはなぜですか?上記のデータは、mightamountに基づいていることを示唆しているようですバッファリングされたデータであり、バッファリングされたオーディオコンテンツのdurationではありません。これは本当にあるのでしょうか?

アップデート: Android 1.6、2.2、2.3.4の物理デバイスおよび1.6、2.1、2.2、2.3.1、2.3のエミュレータでライブストリーミングをテストしました。 3. 2.3.3と2.3.4で長い遅延しか見られない古いバージョンは5秒以内に再生を開始します。

49
Jeremy Haberman

一定の時間ではなく、一定量のデータをバッファリングしているようです。さまざまなタイプのNPRストリームのビットレートが頭上からわからない場合、データは次のようになります。

  1. MPRニュースストリーム:27秒( http://newsstream1.publicradio.org:80/ )、64 kbps
  2. MPRクラシック音楽ストリーム:15秒( http://classicalstream1.publicradio.org:80/ )、128 kbps
  3. MPR現在のストリーム:7秒( http://currentstream1.publicradio.org:80/ )、128 kbps
  4. PRIストリーム:52秒( http://pri-ice.streamguys.biz/pri1 )、32 kbps

2つの128 kbpsストリーム間の不一致は別として、ビットレートとバッファリング期間の間には非常に良い相関があります。

いずれにせよ、Androidはオープンソースなので、いつでも それが何をしているかを見る です。残念ながら、prepareAsync()prepare()はネイティブメソッドであり、バッファ関連のイベントもネイティブプロセスからディスパッチされるようです。

OnBufferingUpdateListenerをMediaPlayerにアタッチして、バッファー状態に関するより細かい更新を取得しようとしましたか?イベントが配信される速度と、さまざまなストリーム全体の各イベントでバッファが占める割合を比較すると興味深いかもしれません。ストリームのビットレートに対してそれを相互参照することができ、32 kbpsでの4秒間のバッファリングが128 kbpsでの1秒間のバッファリングと同じパーセンテージでバッファを満たす場合、私はあなたが答えを見つけたと思います。

24
aroth

スイッチMediaPlayer by FFmpeg Media PlayerMediaPlayerよりもうまく機能しますストリームをテストしたい場合は demo でそれを行うことができます彼らが持っている。

7
4gus71n

私は最近、ストリーミングオーディオプロバイダーでこの同じ問題をデバッグしました。この問題は、32 kbps以下のステージファイトおよびストリーミングソースに関連しています。 24、32、48、64、128 kbpsでの応答時間を測定しながら、同じストリーミングを進めました。

  • 24-> 46秒でストリーミングを開始
  • 32-> 24秒でストリーミングを開始
  • 48-> 2秒でストリーミングを開始
  • 64-> 2秒でストリーミングを開始
  • 128->ストリーミング開始まで2秒

これは、各ビットレートで平均10回以上の平均的な一貫したワイヤレス接続によるものです。 Travisが指摘したように、鍵となるのは、stagefrightがオーディオをバッファする時間を把握できないことでした。時々、「エラー:1、-21492389」などのメッセージが表示され、ステージフライトプレーヤーを静かにクラッシュさせるように見えました。私はこれを追跡してみましたが、非常に遅いストリーム(サブ24 kbps)は、デバイスがオーディオストリームのスペースを使い果たすまでバッファリングするため、バッファオーバーフローを引き起こすようであるという結論に達しました。

このテスト全体でOnBufferingUpdateListenerがまったく起動しなかったことを付け加えておきます。何のためにあるのかわかりません。上記のNPRアプリと同じように、読み込みの進行状況を確認する唯一の方法は、読み込みをプロキシすることだと思います。

4
Nick Campion

Icecastからストリーミングしている場合は、burst-size設定:

バーストサイズは、接続時にクライアントにバーストするデータの量(バイト単位)です。バーストオンコネクトと同様に、これはメディアプレーヤーが使用するプリバッファをすばやく満たすためです。デフォルトは64キロバイトです。これはほとんどのクライアントで使用される一般的なサイズであるため、通常は変更する必要はありません。この設定は、マウント設定で上書きされない限り、すべてのマウントポイントに適用されます。この値がキューサイズよりも小さいことを確認してください。必要な場合は、キューサイズを増やして、目的のバーストサイズよりも大きくしてください。そうしないと、最初のバーストが原因で接続がすでにキューサイズの制限を超えているため、リスナークライアント接続の試行が中止される可能性があります。

burst-sizeをサーバー上で131072に変更すると、現在Androidに基づいたアプリMediaPlayerをベースにしたアプリが大幅に遅延することなくストリームを再生します。

2
Matt Harrington

私はこれを、3つの高速、7つの低速の10個のデータポイントで試しました。一貫性があります。つまり、高速ストリームは高速で、低速ストリームは常に低速です。

これは、サーバーが提供する 'content-length'に関連していると思います。content-lengthが適切に指定されていない場合、Androidは、どれだけバッファリングするかわかりません。

間違っている可能性があり、ワイヤーシェアリングまでは行きませんでした。

1
Travis Biehn

この問題が発生したとき、プレーヤーを開く前にストリームが利用可能かどうかをテストすることにしました。ユーザーに長時間待機させ、音楽が正常に開始される場合(そうではありませんが、問題ないとします)。最悪のシナリオは、彼を長い間待たせ、音楽が開始されないことです。したがって、2つの状況があります。

  • ラジオ局のようなライブストリーミングシナリオ。
  • オンラインで入手できる記録されたmp3ファイル。

無線シナリオで、ポートが接続を受け入れているかどうかを確認できます(オープン/クローズ状態)。開いている場合は、プレーヤーで音楽を準備し、それ以外の場合は準備しないでください。

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

mp3ファイルのシナリオでは、状況が少し異なります。 http要求の後に続く応答コードを確認する必要があります。

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