我想播放来自url的音频流,该url仅在一段时间内有效。由于缓冲机制的原因,仅仅使用内置的stagefright流功能并不能很好地发挥作用(当第二次填充缓冲区时,url将是死的),因此我实现了一个代理流,类似于npr应用程序中的操作。
http://code.google.com/p/npr-android-app/source/browse/trunk/Npr/src/org/npr/android/news/StreamProxy.java
这实际上工作得非常好,除了一个例外,任何seek调用都会有效地破坏代理流。我很难确定在stagefright中寻找到底是如何工作的。每次我寻找的时候我都会得到一条信息
01-12 13:35:57.201: ERROR/(4870): Connection reset by peer
01-12 13:35:57.201: ERROR/(4870): java.net.SocketException: Connection reset by peer
01-12 13:35:57.201: ERROR/(4870): at org.apache.harmony.luni.platform.OSNetworkSystem.writeSocketImpl(Native Method)
01-12 13:35:57.201: ERROR/(4870): at org.apache.harmony.luni.platform.OSNetworkSystem.write(OSNetworkSystem.java:723)
01-12 13:35:57.201: ERROR/(4870): at org.apache.harmony.luni.net.PlainSocketImpl.write(PlainSocketImpl.java:578)
01-12 13:35:57.201: ERROR/(4870): at org.apache.harmony.luni.net.SocketOutputStream.write(SocketOutputStream.java:59)
01-12 13:35:57.201: ERROR/(4870): at com.soundcloud.utils.StreamProxy.processRequest(StreamProxy.java:209)然后暂停几秒钟,然后stagefright重试连接到相同的url,通常会抛出一个错误(我可以想象,因为代理流还没有被重置)。另一个潜在的问题是,代理流似乎总是线性地读取数据源:
while (isRunning && (readBytes = data.read(buff, 0, buff.length)) != -1) 我只是猜测,但我认为为了支持查找,代理必须能够在从缓冲区读取时提供偏移量。有没有办法计算出从套接字客户端请求的偏移量(预期的寻道位置)?
我在套接字方面的经验有限。有人对这里的实现有什么建议吗?
发布于 2011-03-13 08:45:24
MediaPlayer发出HTTP range请求,指定播放器期望的字节偏移量。您可以从提交给代理服务器的请求标头中读取这些范围值。然后,您可以打开“仅将这些范围发送回MediaPlayer”。
发布于 2013-01-21 10:46:43
当您查找或跳过或连接丢失而MediaPlayer不断重新连接到代理服务器时,您必须在收到客户端的请求和范围(整型)后发送状态为206的响应。
String headers += "HTTP/1.1 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";当你收到一个来自MediaPlayer的请求,该请求不包含HTTP头中的Range,那么它就是在请求一个新的流文件,在这种情况下,你的响应头应该是这样的:
String headers = "HTTP/1.1 200 OK\r\n";
headers += "Content-Type: audio/mpeg\r\n";
headers += "Accept-Ranges: bytes\r\n";
headers += "Content-Length: " + fileSize + "\r\n";
headers += "\r\n";享受吧!
发布于 2012-05-31 13:34:23
我不确定你是否弄明白了这一点,但我所需要做的就是把头从原始请求传递到代理请求:
private HttpResponse download(String url, Header[] headers) {
DefaultHttpClient seed = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
SingleClientConnManager mgr = new MyClientConnManager(seed.getParams(),
registry);
DefaultHttpClient http = new DefaultHttpClient(mgr, seed.getParams());
HttpGet method = new HttpGet(url);
for (Header header : headers) {
method.addHeader(header);
}
HttpResponse response = null;
try {
Log.d(getClass().getName(), "starting download");
response = http.execute(method);
Log.d(getClass().getName(), "downloaded");
}catch(java.net.UnknownHostException e)
{
Intent i=new Intent("org.prx.errorInStream");
mContext.sendBroadcast(i);
}
catch (ClientProtocolException e) {
Log.e(getClass().getName(), "Error downloading", e);
} catch (IOException e) {
Log.e(getClass().getName(), "Error downloading", e);
}
return response;}
private void processRequest(HttpRequest request, Socket client)
throws IllegalStateException, IOException {
if (request == null) {
return;
}
Log.d(getClass().getName(), "processing");
String url = request.getRequestLine().getUri();
HttpResponse realResponse = download(url, request.getAllHeaders());
if (realResponse == null) {
return;
}
...}
https://stackoverflow.com/questions/4673362
复制相似问题