2012-07-23 4 views
19

ローカルのプロキシサーバーを実行するオーディオストリーミングアプリがあります。ローカルプロキシサーバは、インターネットストリーミングソースへのhttp接続を行い、ストリーミングデータをローカルに取得し、バッファリングする。 、 - はその後、内部のアプリでは、私が(1.5 ... 4.0 Androidデバイスと異なるOSのバージョンをたっぷり使って)アンドロイドメディアプレーヤー - 範囲リクエストを無効にする方法(Nexus 7でオーディオストリーミングが途切れている)

mediaPlayer.setDataSource(...); // the url of the local proxy server 

すべてが大丈夫だった方法を使用して、ローカルプロキシサーバーに接続するためのMediaPlayerを使用しますNexus 7がリリースされるまで

Nexus 7では、メディアプレーヤーがローカルプロキシサーバーからのソースの再生を拒否します。

ログを調べたとき、MediaPlayerが範囲要求を内部的に使用しているようです。 私のローカルプロキシサーバーはそれを処理しません。 HTTP/1.0 200 OKとそのデータを返します。 はしかし、メディアプレーヤーは、そのようにしないと例外がスローされます:http仕様によると

Caused by: libcore.io.ErrnoException 
?:??: W/?(?): [ 07-18 00:08:35.333 4962: 5149 E/radiobee ] 
?:??: W/?(?): : sendto failed: ECONNRESET (Connection reset by peer) 
?:??: W/?(?): at libcore.io.Posix.sendtoBytes(Native Method) 
?:??: W/?(?): at libcore.io.Posix.sendto(Posix.java:146) 
?:??: W/?(?): at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java: 
?:??: W/?(?): at libcore.io.IoBridge.sendto(IoBridge.java:473) 
We requested a content range, but server didn't support that. (responded with 200) 

を、サーバはHTTP/1.0ではなく1.1で応答した場合、クライアントは範囲要求を発射してはならない(1.0

また、サーバが範囲要求をサポートしていない場合は、200 OKで応答するとうまくいくはずですが(これは私がやっていることです)、MediaPlayerの実装ですNexus 7ではそれが好きではありません。

私は、このスレッドを見てみました: HTTP: How should I respond to "Range: bytes=" when Range is unsupported?

、彼らは200 OKとの応答が十分でなければならないが、残念ながらそれは助けにはならないと主張しています。

これがJelly Beanの問題か、具体的なNexus 7実装の問題であるかどうかはわかりませんが、まだ解決しなければならない問題です。

もう一度、同じアプリを使用して、他の多くのAndroid搭載端末では範囲のリクエストはありません。何らかの理由で、これらの範囲リクエストがNexus 7で発生しています(これは他のAndroid搭載端末でも発生する可能性がありますが、これまでのところこれまで私には起こりませんでした)。

MediaPlayerの範囲要求を無効にする方法はありますか?

誰も私のプロキシサーバーのロジック(正確には、この範囲の要求を受け取った場合、返す必要がありますか?

「HTTP/1.0 206 OK \ r \ n部分コンテンツ\ r \ n \ r \ n」のようなものを返さなければならないようですが、おそらく部分的なコンテンツの最後に値があるはずです。これが何であるべきかを確かめてください。

あなたのご協力をお待ちしております。

おかげ..

+2

ゼリービーンの問題(Nexus 7だけではない)が確認できます。最近、Ice Cream SandwichからJelly Beanに更新されたさまざまなNexus端末でも発生しました。 誰かがJelly Beanのローカルプロキシサーバーに対してMediaPlayerを使用できましたか? – user1512464

+0

この問題も(Jelly Bean上で)確認できます。ただし、プロキシは使用していません。メディアプレーヤーを使用してオーディオストリームに直接アクセスします。 – pulse00

+0

これは、Jelly Beanの回帰のようです。私はbugtrackerに関する問題を作成しました:https://code.google.com/p/android/issues/detail?id=35790 – pulse00

答えて

8

私は大規模なオーディオストリーミングアプリ(つまり、MediaPlayerのにオーディオをストリーミングするために、ローカルホストのHTTPプロキシを使用しています)上で動作し、私は、すぐに私は私の中でJellyBeanデバイスを得たとして、この問題に遭遇しましたGoogle I/O 2012に手を差し伸べてください。

私たちのアプリケーションをさまざまなデバイスでテストすると、自動クラッシュログやユーザーのログから受け取った情報を使って、特定のMediaPlayerの実装が不安定な(そしてときには全く精神病的な)方法で動作することに気付きました。

あまり詳しく説明しませんが、これは私が見たものです。実装によっては、同じURLに対して複数のリクエスト(何回か5回以上)が行われることがあります。これらの要求は、それぞれが異なるバイト範囲(通常は最初または最後の128バイト)であるという点で、少しずつ異なります。結論として、MediaPlayerは埋め込まれたメタデータを見つけようとしていましたが、ある時点の後にはそれをあきらめ、通常の範囲外の要求を行います。

これは、JellyBean MediaPlayerの実装が何をしているのかではなく、単にAndroidのメディアフレームワークのすごくて一般的な断片化の例です。しかし、上記の状況を解決するには、JellyBean問題への解決策でもあった、それは次のとおりです。

は、あなたのローカルプロキシこれはTranfer-エンコードとContent-Lengthヘッダを置き換えchunked encoding

で応答しておいてください。チャンクヘッダ。つまり、要求側のクライアントはリソースの全長を知りません。したがって、範囲要求を行うことはできません。受信したチャンクを処理するだけです。

私はこれがハックだと言いましたが、うまくいきます。その副作用がないわけではありません:メディアプレーヤーのバッファの進行状況は、オーディオの長さ(そのうちの1つ)を知らないため正しくないため、自分のバッファリング計算を使用する必要があります(ストリーミングしていますあなたのプロキシを経由してMediaPlayerに至るまで、あなたは全体の長さを知るでしょう)。

+0

これは私がJelly Beanのデバイスについても実行した問題の興味深いアプローチです。私のサーバーはMP3をストリームし、範囲要求に応答します。 MediaPlayerはほとんどのファイルを1回要求しますが、いくつかのファイルがこの不規則な動作を引き起こします(要求の数とバイトオフセットは異なりますが、特定のファイルの動作は確定的です)。 チャンク転送転送が失敗しました。 MediaPlayerは、最初の応答の直後に範囲要求を行い、そのヘッダを無視しました。パケットトレース:http://pastebin.com/LiN6sKYH 欠けているものがありますか?ストリーミングエンドポイントはローカルでなければなりませんか? –

11

最終的にこれをきれいに解決しました。私たちの場合、私たちはストリーミングサーバーを完全に制御できますが、ローカルプロキシでもこれを行うことができます。 Build.VERSION_CODES.ICE_CREAM_SANDWICH以降、MediaPlayerオブジェクトのヘッダーを設定することは可能です。私たちのアプリではユーザーがオーディオストリームの中を探し出すことができるようになり、このRangeヘッダーをクライアントに実装しました。サーバーが適切なヘッダーで応答する場合、MediaPlayerはストリームを要求するために複数回試行しません。

Content-Type: audio/mpeg 
Accept-Ranges: bytes 
Content-Length: XXXX 
Content-Range: bytes XXX-XXX/XXX 
Status: 206 

重要な部分は206ステータスコード(部分コンテンツ)である:当社のサーバーヘッダーはアンドロイドクライアントのために今のように見えるものです

。このヘッダーを送信しないと、アンドロイドクライアントはソースの再要求を試みます。

ストリームでシークできない場合は、Rangeヘッダーを常に0-some arbitrary large numberに設定するだけです。

6

シークまたはスキップするか、接続が失われてMediaPlayerがプロキシサーバーに再接続し続けると、クライアントから要求と範囲(int)を取得した後、ステータス206でこの応答を送信する必要があります。

String headers += "HTTP/1.0 206 OK\r\n"; 
headers += "Content-Type: audio/mpeg\r\n"; 
headers += "Accept-Ranges: bytes\r\n"; 
headers += "Content-Length: " + (fileSize-range) + "\r\n"; 
headers += "Content-Range: bytes "+range + "-" + fileSize + "/*\r\n"; 
headers += "\r\n"; 
関連する問題