我想从网址播放一个只有一段时间才有效的音频流。由于缓冲机制(在第二次填充缓冲区时url将会死亡),因此使用内置的stagefright流功能不能很好地发挥作用,所以我实现了一个代理流,类似于在npr app中做了什么
这实际上非常好用,但有一个例外,任何搜索调用都会有效地破坏代理流。我很难确定搜寻在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)
我只是猜测,但我认为为了支持搜索,代理必须能够在从缓冲区读取时提供偏移量。有没有办法找出套接字客户端请求的偏移量(预期的搜索位置)?
我对套接字的体验有限。有没有人对此有实施建议?
答案 0 :(得分:2)
当您寻找或跳过或连接丢失且MediaPlayer不断重新连接到代理服务器时,您必须在从客户端获取请求和范围(int)后将此响应发送到状态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";
享受!
答案 1 :(得分:1)
MediaPlayer正在发出HTTP范围请求,指定播放器期望的字节偏移量。您可以从提交给代理服务器的请求的标头中读取这些范围值。然后,您可以打开将这些范围发送回MediaPlayer。
答案 2 :(得分:1)
不确定你是否想过这个,但我需要做的就是将原始请求中的标题传递给代理请求:
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;
}
...
}
答案 3 :(得分:0)
如@Roberto所述,您必须修改方法download
和processRequest
才能绕过HTTP请求标头。但实际上要完成它,或者至少在我的情况下,我必须进一步修改方法private HttpRequest readRequest(Socket client)
来解析socket中的标题,如下所示。
private HttpRequest readRequest(Socket client) {
HttpRequest request = null;
InputStream is;
String firstLine;
List<Header> headers = new ArrayList<Header>();
try {
is = client.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(is), 8192);
firstLine = reader.readLine();
/**
* read HTTP request headers from socket
* */
String line;
while (((line = reader.readLine()) != null) && !(line.equals(""))) { // HTTP header ends at ""
try {
StringTokenizer st = new StringTokenizer(line, ":");
String h = st.nextToken();
String v = st.nextToken();
Header header = new BasicHeader(h, v);
headers.add(header);
} catch (NoSuchElementException e) {
}
}
} catch (IOException e) {
Log.e(LOG_TAG, "Error parsing request", e);
return request;
}
if (firstLine == null) {
Log.i(LOG_TAG, "Proxy client closed connection without a request.");
return request;
}
/**
* retrieve REAL url
* */
StringTokenizer st = new StringTokenizer(firstLine);
String method = st.nextToken();
String uri = st.nextToken();
Log.d(LOG_TAG, uri);
String realUri = uri.substring(1);
Log.d(LOG_TAG, realUri);
request = new BasicHttpRequest(method, realUri);
/**
* add headers back to HTTP request
* */
for (Header header : headers) {
request.addHeader(header);
}
return request;
}