2011-01-12 4 views
3

잠시 동안 유효한 url에서 audiostream을 재생하고 싶습니다. 이 기능은 버퍼링 메커니즘 (버퍼가 두 번째로 채워질 때까지 URL이 죽을 것임)로 인해 스테이지 플라이 (streamfright) 스트리밍 기능을 사용하여 매우 잘 작동하지 않으므로 비슷한 프록시 스트림을 구현했습니다. NPR의 응용 프로그램프록시 스트림 및 무대 재생기로 안드로이드를 검색 할 때

http://code.google.com/p/npr-android-app/source/browse/trunk/Npr/src/org/npr/android/news/StreamProxy.java

에서 수행 무슨이 실제로 통화 효과적으로 프록시 스트림을 나누기 추구 한 가지 예외, 매우 잘 작동합니다. 나는 찾는 사람이 무대에서 제대로 작동하는지 정확하게 판단하기가 힘듭니다. 매번 내가 같은 URL에 연결을 시도 thafter 스테이지 프라이트 그런

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) 

의 메시지가 몇 초 동안 일시 중지를 얻을 추구, 일반적으로 오류가 발생합니다 프록시 스트림이되지 않았기 때문에 (나는 상상 재설정되었습니다.)

while (isRunning && (readBytes = data.read(buff, 0, buff.length)) != -1) 

그리고 난 단지 추측하고 있지만, 내가 추구를 지원하기 위해, 프록시가해야한다고 생각 : 또 다른 잠재적 인 문제는 프록시 스트림은 항상 선형 데이터 소스를 읽 것처럼 보이는 것입니다 버퍼로부터 판독 할 때 오프셋을 제공 할 수있다. 요청 된 오프셋 (offset)을 소켓 클라이언트 (의도 한 탐색 위치)에서 확인하는 방법이 있습니까?

소켓 사용 경험이 제한적입니다. 아무도 여기 구현에 대한 제안을 가지고 있습니까?

답변

1

MediaPlayer는 플레이어가 예상하는 바이트 오프셋을 지정하는 HTTP 범위 요청을 실행 중입니다. 프록시 서버에 제출 된 요청의 헤더에서이 범위 값을 읽을 수 있습니다. 그런 다음이 범위 만 MediaPlayer로 다시 열 수 있습니다.

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; 
} 

... 

}

2

당신이 찾거나 건너 뛰거나 연결이 끊어지고 MediaPlayer가 프록시 서버에 계속 연결을 유지하면 요청을받은 후에 Status 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"; 

그리고 당신은 HTTP 헤더에 범위를 포함하지 않는 MediaPlayer를의 요청을받을 때, 당신의 응답 헤더는 다음과 같이한다이 경우, 새로운 스트림 파일을 요청 :

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"; 

즐기십시오!

0

@Roberto가 언급 한 것처럼 HTTP 요청 헤더를 우회하기 위해 downloadprocessRequest 메서드를 수정해야합니다. 그러나 실제로 그것을 끝내기 위해서, 또는 최소한 나의 경우에는 아래에 보이는 것처럼 소켓에서 헤더를 파싱하기 위해 private HttpRequest readRequest(Socket client) 메소드를 추가로 수정해야한다.

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; 
    } 
관련 문제