我有一个音频流应用程序,它运行的本地代理服务器。 本地代理服务器,使HTTP连接到互联网流媒体源,获取并在本地缓存的数据流。 然后,在里面的应用程序,我用的MediaPlayer连接到本地代理服务器,使用方法
mediaPlayer.setDataSource(...); // the url of the local proxy server
一切都很好(有大量的Android设备和不同的操作系统版本 - 1.5 ... 4.0),直到的Nexus 7发布。
在Nexus 7和媒体播放器拒绝播放从本地代理服务器的源。
当我在日志接过一看,好像MediaPlayer的使用范围请求内部。 我的本地代理服务器不处理。 它返回HTTP / 1.0 200 OK和数据。 然而,媒体播放器不喜欢这一点,抛出一个异常:
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规范,如果服务器与HTTP响应/ 1.0 1.1代替,客户端必须不火的范围内请求(1.0不支持该反正),
此外,如果服务器不支持范围请求,它应该被罚款,如果它与200 OK响应(这是我在做什么),但在Nexus 7在MediaPlayer执行不喜欢这一点。
我看了看这个线程: HTTP:我该如何应对“范围:字节=”范围时,不支持?
,他们声称有200 OK响应必须足够好,但遗憾的是它并不能帮助。
我不知道这是否是Jelly Bean系统出了问题,或者使用Nexus 7的实施问题具体,但它仍然是我的问题,我必须解决的问题。
同样,也有在大量的其他Android装置NO范围请求,使用相同的应用程序。 出于某种原因,这些范围请求上的Nexus 7现在发生的事情(这可能发生在其他Android设备一样好,但再一次,从来没有发生在我身上至今)。
任何可能的方式来禁用MediaPlayer的范围请求?
如果没有,任何人可以提出我的代理服务器逻辑速战速决(正是它必须返回,如果收到此范围的要求吗?),而不会改变我的其他逻辑,如果可能的话?
好像或许我要回到类似“HTTP / 1.0 206 OK \ r \ nPartial内容\ r \ n \ r \ n”,但可能应该有部分内容的结尾一定的价值 - 不知道什么是应该是这一个。
您的帮助将不胜感激。
谢谢..
我们终于在一个干净的方式解决了这个。 在我们的情况下,我们在流媒体服务器的完全控制,但我想你可以与当地的代理也这么做。 由于Build.VERSION_CODES.ICE_CREAM_SANDWICH
它可以设置标题为MediaPlayer
对象。 随着我们的应用程序使用户能够寻求音频流里面,我们已经实现了这个Range
的客户端头。 如果服务器用适当的标题响应时, MediaPlayer
不会尝试multimple次请求流。
这就是我们的服务器头的样子,现在的Android客户端:
Content-Type: audio/mpeg
Accept-Ranges: bytes
Content-Length: XXXX
Content-Range: bytes XXX-XXX/XXX
Status: 206
的重要的部分是206
状态代码(局部内容)。 如果不发送这个头,Android客户端将尝试重新请求的来源,不管是什么。
如果您的播放器不允许流中求,你可以简单地总是设定Range
头0-some arbitrary large number
。
我大规模音频流应用程序的工作(使用本地主机的HTTP代理流音频到的MediaPlayer),我马上就遇到了这个问题,我在我的手在谷歌I / O 2012得到了豆形软糖设备。
当质量测试我们不同设备上的应用程序(从我们的自动崩溃日志以及用户提交的日志接收到的信息),我们注意到,在我所说的不稳定(有时简直是精神病)的方式表现一定的MediaPlayer实现。
没有考虑太多细节,这是我所看到的:一些实现将使对同一URL的多个请求(有时5+)。 这些请求都彼此略有不同,每个是一个用于一个不同的字节范围(通常为第一个或最后128个字节)。 得出的结论是,在MediaPlayer正在试图找到嵌入的元数据,然后将经过一定的时候,就会放弃,只是做一个常规的非范围请求。
这不是什么股票豆形软糖MediaPlayer的实施是干什么的,只是它的怪诞的烦躁和Android上的媒体框架的一般不成的例子。 然而,解决了上述情况也是解决问题的Jellybean,那就是:
与你的本地代理响应分块编码
这取代了枢纽换乘编码的Content-Length头:分块标头。 这意味着请求的客户端将不知道该资源的总长度,从而不能做出一系列请求,它只是因为他们收到要处理的数据块。
就像我说的,这是一个黑客,但它的作品。 这不是没有它的副作用:媒体播放器的缓冲进度将是不正确的,因为它不知道音频的长度(就是其中之一),要解决这个问题,你将不得不使用自己的缓冲计算(你是流从某处通过您的代理MediaPlayer的,对不对?所以,你会知道总长度)。
当你寻求或跳过或连接丢失和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";
文章来源: android media player - how to disable range request? (broken audio streaming on Nexus 7)