Android ищет проблему с прокси-потоком и игроком на сцене - PullRequest
3 голосов
/ 12 января 2011

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

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

На самом деле это работает очень хорошо, за одним исключением, любой запрос поиска эффективно прерывает поток прокси. Мне трудно определить, как именно работает поиск в сцене. Каждый раз, когда я ищу, я получаю сообщение

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) 

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

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

Ответы [ 4 ]

2 голосов
/ 21 января 2013

Когда вы ищете или пропускаете, или соединение потеряно, и 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, который не содержит Range в заголовке 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";

Наслаждайтесь!

1 голос
/ 31 мая 2012

Не уверен, что вы когда-нибудь поняли это, но все, что мне нужно было сделать, это передать заголовки из исходного запроса в прокси-запрос:

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

...

}

1 голос
/ 13 марта 2011

MediaPlayer выдает запросы диапазона HTTP, которые определяют смещения байтов, которые ожидает проигрыватель.Вы можете прочитать эти значения диапазона из заголовков запроса, отправленного на ваш прокси-сервер.Затем вы можете открыть и отправить только эти диапазоны обратно в MediaPlayer.

0 голосов
/ 20 июня 2014

Как уже упоминалось @Roberto, вам нужно изменить методы download и processRequest, чтобы обойти заголовки HTTP-запроса.Но чтобы на самом деле это сделать, или, по крайней мере, в моем случае, мне нужно еще изменить метод private HttpRequest readRequest(Socket client) для анализа заголовков из сокета, как показано ниже.

...