2011-01-12 2 views
3

Я хочу воспроизвести аудиопоток с URL-адреса, который действителен только для временного промежутка времени. Это не очень хорошо работает, используя встроенную функциональность потоковой передачи в реальном времени из-за механизма буферизации (URL будет мертв к тому времени, когда буфер будет заполнен во второй раз), поэтому я реализовал прокси-поток, аналогичный что делается в приложении NPRandroid seek problem with proxy stream и stagefright player

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

Это на самом деле работает очень хорошо, но с одним исключением, любой искать вызов эффективно разбивает поток прокси. Мне трудно определить, как именно поиски работают в стадии. Everytime Я ищу Я ​​получаю сообщение о

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) 

затем пауза в течение нескольких секунд, thafter который stagefright повторных попыток подключения к тому же URL, и обычно выдает ошибку (я бы себе представить, потому что поток прокси не имеет был сброшен). Еще одна потенциальная проблема заключается в том, что он, кажется, как будто поток прокси всегда будет читать источник данных линейно:

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

И я только гадать, но я думаю, что для того, чтобы поддержать искание, прокси должен быть способный обеспечить смещение при чтении из буфера. Есть ли способ вычислить запрошенное смещение от клиента сокета (предполагаемая позиция поиска)?

Мой опыт работы с розетками ограничен. Кто-нибудь есть предложения по реализации здесь?

ответ

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 продолжает переподключение к прокси-серверу, вы должны отправить этот ответ с статусом 206 после получения запроса и диапазона (int) из клиент.

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, то он запрашивает новый файл потока, в этом случае ваш заголовок ответа должен выглядеть следующим образом:

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, вы должны изменить методы download и processRequest, чтобы обойти заголовки HTTP-запросов. Но для того, чтобы это сделать, или, по крайней мере, в моем случае, мне нужно дополнительно модифицировать метод 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; 
    } 
Смежные вопросы