我使用StreamProxy类来传输来自互联网的视频,但是当我寻找视频播放器时,我会收到一个"连接由同行重置"错误,视频停止。
你知道我该怎么办呢?
我找到了libMedia(http://libeasy.alwaysdata.net/)的解决方案,但我想实现自己的解决方案。
public class StreamProxy implements Runnable {
private static final String LOG_TAG = StreamProxy.class.getName();
private int port = 12012;
public int getPort() {
return port;
}
private boolean isRunning = true;
private ServerSocket socket;
private Thread thread;
public void init() {
try {
socket = new ServerSocket(port, 0, InetAddress.getByAddress(new byte[] {127, 0, 0, 1}));
socket.setSoTimeout(5000);
port = socket.getLocalPort();
Log.d(LOG_TAG, "port " + port + " obtained");
} catch (UnknownHostException e) {
Log.e(LOG_TAG, "Error initializing server", e);
} catch (IOException e) {
Log.e(LOG_TAG, "Error initializing server", e);
}
}
public void start() {
if (socket == null) {
throw new IllegalStateException("Cannot start proxy; it has not been initialized.");
}
thread = new Thread(this);
thread.start();
}
public void stop() {
isRunning = false;
if (thread == null) {
throw new IllegalStateException("Cannot stop proxy; it has not been started.");
}
thread.interrupt();
try {
thread.join(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
Log.d(LOG_TAG, "running");
while (isRunning) {
try {
Socket client = socket.accept();
if (client == null) {
continue;
}
Log.d(LOG_TAG, "client connected");
HttpRequest request = readRequest(client);
processRequest(request, client);
} catch (SocketTimeoutException e) {
// Do nothing
} catch (IOException e) {
Log.e(LOG_TAG, "Error connecting to client", e);
}
}
Log.d(LOG_TAG, "Proxy interrupted. Shutting down.");
}
private HttpRequest readRequest(Socket client) {
HttpRequest request = null;
InputStream is;
String firstLine;
try {
is = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8192);
firstLine = reader.readLine();
} 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;
}
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);
return request;
}
private HttpResponse download(String url) {
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);
HttpResponse response = null;
try {
Log.d(LOG_TAG, "starting download");
response = http.execute(method);
Log.d(LOG_TAG, "downloaded");
} catch (ClientProtocolException e) {
Log.e(LOG_TAG, "Error downloading", e);
} catch (IOException e) {
Log.e(LOG_TAG, "Error downloading", e);
}
return response;
}
private void processRequest(HttpRequest request, Socket client) throws IllegalStateException, IOException {
if (request == null) {
return;
}
Log.d(LOG_TAG, "processing");
String url = request.getRequestLine().getUri();
HttpResponse realResponse = download(url);
if (realResponse == null) {
return;
}
Log.d(LOG_TAG, "downloading...");
InputStream data = realResponse.getEntity().getContent();
StatusLine line = realResponse.getStatusLine();
HttpResponse response = new BasicHttpResponse(line);
response.setHeaders(realResponse.getAllHeaders());
Log.d(LOG_TAG, "reading headers");
StringBuilder httpString = new StringBuilder();
httpString.append(response.getStatusLine().toString());
httpString.append("\n");
for (Header h : response.getAllHeaders()) {
httpString.append(h.getName()).append(": ").append(h.getValue()).append("\n");
}
httpString.append("\n");
Log.d(LOG_TAG, "headers done");
try {
byte[] buffer = httpString.toString().getBytes();
int readBytes;
Log.d(LOG_TAG, "writing to client");
client.getOutputStream().write(buffer, 0, buffer.length);
// Start streaming content.
byte[] buff = new byte[1024 * 50];
while (isRunning && (readBytes = data.read(buff, 0, buff.length)) != -1) {
client.getOutputStream().write(buff, 0, readBytes);
}
} catch (Exception e) {
Log.e("", e.getMessage(), e);
} finally {
if (data != null) {
data.close();
}
client.close();
}
}
private class IcyLineParser extends BasicLineParser {
private static final String ICY_PROTOCOL_NAME = "ICY";
private IcyLineParser() {
super();
}
@Override
public boolean hasProtocolVersion(CharArrayBuffer buffer, ParserCursor cursor) {
boolean superFound = super.hasProtocolVersion(buffer, cursor);
if (superFound) {
return true;
}
int index = cursor.getPos();
final int protolength = ICY_PROTOCOL_NAME.length();
if (buffer.length() < protolength)
return false; // not long enough for "HTTP/1.1"
if (index < 0) {
// end of line, no tolerance for trailing whitespace
// this works only for single-digit major and minor version
index = buffer.length() - protolength;
} else if (index == 0) {
// beginning of line, tolerate leading whitespace
while ((index < buffer.length()) && HTTP.isWhitespace(buffer.charAt(index))) {
index++;
}
} // else within line, don't tolerate whitespace
return index + protolength <= buffer.length() && buffer.substring(index, index + protolength).equals(ICY_PROTOCOL_NAME);
}
@Override
public ProtocolVersion parseProtocolVersion(CharArrayBuffer buffer, ParserCursor cursor) throws ParseException {
if (buffer == null) {
throw new IllegalArgumentException("Char array buffer may not be null");
}
if (cursor == null) {
throw new IllegalArgumentException("Parser cursor may not be null");
}
final int protolength = ICY_PROTOCOL_NAME.length();
int indexFrom = cursor.getPos();
int indexTo = cursor.getUpperBound();
skipWhitespace(buffer, cursor);
int i = cursor.getPos();
// long enough for "HTTP/1.1"?
if (i + protolength + 4 > indexTo) {
throw new ParseException("Not a valid protocol version: " + buffer.substring(indexFrom, indexTo));
}
// check the protocol name and slash
if (!buffer.substring(i, i + protolength).equals(ICY_PROTOCOL_NAME)) {
return super.parseProtocolVersion(buffer, cursor);
}
cursor.updatePos(i + protolength);
return createProtocolVersion(1, 0);
}
@Override
public StatusLine parseStatusLine(CharArrayBuffer buffer, ParserCursor cursor) throws ParseException {
return super.parseStatusLine(buffer, cursor);
}
}
class MyClientConnection extends DefaultClientConnection {
@Override
protected HttpMessageParser createResponseParser(final SessionInputBuffer buffer, final HttpResponseFactory responseFactory, final HttpParams params) {
return new DefaultResponseParser(buffer, new IcyLineParser(), responseFactory, params);
}
}
class MyClientConnectionOperator extends DefaultClientConnectionOperator {
public MyClientConnectionOperator(final SchemeRegistry sr) {
super(sr);
}
@Override
public OperatedClientConnection createConnection() {
return new MyClientConnection();
}
}
class MyClientConnManager extends SingleClientConnManager {
private MyClientConnManager(HttpParams params, SchemeRegistry schreg) {
super(params, schreg);
}
@Override
protected ClientConnectionOperator createConnectionOperator(final SchemeRegistry sr) {
return new MyClientConnectionOperator(sr);
}
}
}