android media player - how to disable range request? (broken audio streaming on Nexus 7)

懵懂的女人 提交于 2019-12-02 14:43:24

We've finally solved this in a clean way. In our case we have full control over the streaming server, but i guess you could do this with a local proxy as well. Since Build.VERSION_CODES.ICE_CREAM_SANDWICH it's possible to set headers for the MediaPlayer object. As our app enables the user to seek inside the audio stream, we've implemented this Range header on the client. If the server responds with the proper headers, the MediaPlayer will not try multimple times to request the stream.

That's what our server headers look like now for the android client:

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

The important part is the 206 status code (partial content). If you don't send this header, the android client will try to re-request the source, no matter what.

If your player doesn't allow seeking in the stream, you could simply always set the Range header to 0-some arbitrary large number.

I work on a large scale audio streaming app (that uses a local host HTTP proxy to stream audio to MediaPlayer) and I ran into this issue as soon as I got a JellyBean device in my hands at Google I/O 2012.

When quality testing our application on different devices (and with information received from our automated crash logs and user submitted logs), we noticed that certain MediaPlayer implementations behaved in what I would call an erratic (and sometimes downright psychotic) manner.

Without going into too much detail, this is what I saw: some implementations would make multiple requests (some times 5+) for the same URL. These requests were all slightly different from each other in that each one was for a different byte range (usually for the first or last 128 bytes). The conclusion was that the MediaPlayer was trying to find embedded metadata, then would after some point it would give up and just make a regular non-range request.

That is not what the stock JellyBean MediaPlayer implementation is doing, it just an example of the whacky-ness and general fragmentation of the media framework on Android. However, the solution to the above situation was also the solution to the JellyBean problem, and that is:

Have your local proxy respond with chunked encoding

This replaces the Content-Length header with a Tranfer-Encoding: chunked header. This means the requesting client will not know the total length of the resource and thus cannot make a range-request, it just has to deal with the chunks as they are received.

Like I said this is a hack, but it works. It is not without its side effects: media player buffer progress will be incorrect since it doesn't know the length of the audio (is one of them), to get around that you will have to use your own buffering computation (you are streaming from somewhere through your proxy to MediaPlayer, right? So you will know the total length).

When you seek or skip or the connection is lost and MediaPlayer keeps reconnecting to the proxy server, you must send this response with Status 206 after you get the request and range(int) from the client.

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";
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!