Android media player – как отключить запрос диапазона? (Сломанная аудиопотоковая передача на Nexus 7)

У меня есть приложение для потоковой передачи аудио, которое запускает локальный прокси-сервер. Локальный прокси-сервер делает http-соединение с источником потоковой передачи в Интернете, получает и буферизирует локальные потоковые данные. Затем, внутри приложения, я использую MediaPlayer для подключения к локальному прокси-серверу, используя метод

mediaPlayer.setDataSource(...); // the url of the local proxy server 

Все было в порядке (с большим количеством устройств Android и разных версий ОС – 1,5 … 4.0), пока Nexus 7 не выпустит.

В Nexus 7 медиаплеер отказывается воспроизводить исходный код с локального прокси-сервера.

Когда я просмотрел журналы, похоже, что MediaPlayer использует внутренние запросы. Мой локальный прокси-сервер не справляется с этим. Он возвращает HTTP / 1.0 200 OK и данные. Однако медиаплеер не любит этого и выдает исключение:

 Caused by: libcore.io.ErrnoException ?:??: W/?(?): [ 07-18 00:08:35.333 4962: 5149 E/radiobee ] ?:??: W/?(?): : sendto failed: ECONNRESET (Connection reset by peer) ?:??: W/?(?): at libcore.io.Posix.sendtoBytes(Native Method) ?:??: W/?(?): at libcore.io.Posix.sendto(Posix.java:146) ?:??: W/?(?): at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java: ?:??: W/?(?): at libcore.io.IoBridge.sendto(IoBridge.java:473) We requested a content range, but server didn't support that. (responded with 200) 

Согласно спецификациям http, если сервер отвечает HTTP / 1.0 вместо 1.1, клиент не должен запускать запрос диапазона (1.0 не поддерживает это в любом случае),

Также, если сервер не поддерживает запрос диапазона, это должно быть хорошо, если он отвечает 200 OK (и это то, что я делаю), но реализация MediaPlayer на Nexus 7 не нравится.

Я просмотрел этот поток: HTTP: Как мне ответить на «Range: bytes =», когда Range не поддерживается?

, Где они утверждают, что ответ с 200 OK должен быть достаточно хорошим, но, к сожалению, это не помогает.

Я не уверен, что это проблема с Jelly Bean или проблема с реализацией Nexus 7, но это все еще проблема для меня, которую я должен решить.

Опять же, нет никаких запросов диапазона на многих других устройствах Android, используя одно и то же приложение. По какой-то причине эти запросы диапазона теперь выполняются на Nexus 7. (Это может случиться и на других устройствах Android, но до сих пор так и не дошло до меня).

Любой возможный способ отключить запросы диапазона для MediaPlayer?

Если их нет, может ли кто-нибудь предложить быстрое исправление для моей логики прокси-сервера (что именно он должен вернуть, если он получит этот запрос диапазона?), Если не поменять мою другую логику?

Похоже, что, может быть, мне нужно вернуть что-то вроде «HTTP / 1.0 206 OK \ r \ nPartial Content \ r \ n \ r \ n», но, вероятно, в конце частичного контента должно быть некоторое значение – не уверен, что должно Быть этим.

Ваша помощь будет оценена по достоинству.

Благодаря..

Solutions Collecting From Web of "Android media player – как отключить запрос диапазона? (Сломанная аудиопотоковая передача на Nexus 7)"

Мы окончательно решили это чистым способом. В нашем случае у нас есть полный контроль над потоковым сервером, но я думаю, вы могли бы сделать это и с локальным прокси. С Build.VERSION_CODES.ICE_CREAM_SANDWICH можно установить заголовки для объекта MediaPlayer . Поскольку наше приложение позволяет пользователю искать внутри аудиопотока, мы внедрили этот заголовок Range на клиенте. Если сервер отвечает соответствующими заголовками, MediaPlayer не будет пытаться многопрофильное время запросить поток.

Вот как выглядят наши заголовки серверов для клиента android:

 Content-Type: audio/mpeg Accept-Ranges: bytes Content-Length: XXXX Content-Range: bytes XXX-XXX/XXX Status: 206 

Важной частью является код состояния 206 (частичный контент). Если вы не отправляете этот заголовок, клиент android попытается повторно запросить источник, несмотря ни на что.

Если ваш плеер не разрешает поиск в потоке, вы можете просто установить заголовок Range на 0-some arbitrary large number .

Я работаю над широкомасштабным потоковым аудиоприложением (который использует прокси-сервер локального хоста для потоковой передачи звука в MediaPlayer), и я столкнулся с этой проблемой, как только у меня появилось устройство JellyBean в моих руках в Google I / O 2012.

При тестировании качества нашего приложения на разных устройствах (и с информацией, полученной из наших автоматических журналов сбоев и журналов, отправленных пользователем), мы заметили, что некоторые реализации MediaPlayer вели себя в том, что я бы назвал беспорядочным (а иногда и просто психотическим) способом.

Не вдаваясь в подробности, это то, что я видел: некоторые реализации будут делать несколько запросов (иногда 5+) для одного и того же URL-адреса. Эти запросы были немного отличны друг от друга, поскольку каждый из них был для другого байтового диапазона (обычно для первого или последнего 128 байтов). Вывод состоял в том, что MediaPlayer пытался найти внедренные метаданные, а затем после некоторого момента отказался бы и просто сделал бы регулярный запрос без диапазона.

Это не то, что делает реализация JellyBean MediaPlayer, это всего лишь пример дурной и общей фрагментации медиа-среды на Android. Однако решение вышеуказанной ситуации было также решением проблемы JellyBean, а именно:

Попросите вашего местного прокси-сервера выполнить обмен закодированным кодированием

Это заменяет заголовок Content-Length заголовком Tranfer-Encoding: chunked. Это означает, что запрашивающий клиент не будет знать общую длину ресурса и, следовательно, не может сделать запрос диапазона, ему просто нужно иметь дело с кусками по мере их получения.

Как я уже сказал, это хак, но он работает. Это не без побочных эффектов: прогресс буфера медиаплеера будет неправильным, так как он не знает длину звука (является одним из них), чтобы обойти это, вам придется использовать собственные вычисления буферизации (вы потоки Откуда-нибудь через ваш прокси-сервер в MediaPlayer, правильно? Значит, вы будете знать общую длину).

Когда вы ищете или пропускаете или соединение потеряно, и MediaPlayer продолжает переподключиться к прокси-серверу, вы должны отправить этот ответ с Status 206 после того, как вы получите запрос и диапазон (int) от клиента.

 String headers += "HTTP/1.0 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";