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

前端 未结 3 1636
轮回少年
轮回少年 2021-01-30 06:03

I have a audio streaming app, which runs a local proxy server. The local proxy server makes a http connection to a internet streaming source, gets and buffers locally the stream

相关标签:
3条回答
  • 2021-01-30 06:05

    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).

    0 讨论(0)
  • 2021-01-30 06:15

    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";
    
    0 讨论(0)
  • 2021-01-30 06:22

    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.

    0 讨论(0)
提交回复
热议问题