Android - размер буфера MediaPlayer в ICS 4.0
Я использую сокет в качестве прокси-сервера для MediaPlayer, чтобы я мог загружать и дешифровать аудиофайл в формате MP3 перед записью его в сокет. Это похоже на пример, показанный в новостном приложении NPR, однако я использую его для всех версий Android 2.1 - 4 атм.
Код NPR StreamProxy -http://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java
Моя проблема заключается в быстром воспроизведении для 2.1 - 2.3, но в Android 4.0 ICS MediaPlayer буферизует слишком много данных перед тем, как запустить прослушиватель onPrepared.
Пример объема данных, записанных в Socket OutputStream перед onPrepared ():
На SGS2 с 2.3.4 - onPrepared () после ~ 133920 байт
На Nexus S с 4.0.4 - onPrepared () после ~ 961930 байт
Это также происходит на Галактике Нексус.
Как ни странно, эмулятор 4.0 не буферизует столько данных, сколько устройства 4.0. Кто-нибудь испытывает подобную проблему с MediaPlayer на ICS?
РЕДАКТИРОВАТЬ
Вот как прокси пишет в сокет. В этом примере оно происходит из CipherInputStream, загруженного из файла, но то же самое происходит, когда оно загружается из HttpResponse.
<code>final Socket client = (setup above) // encrypted file input stream final CipherInputStream inputStream = getInputStream(file); // setup the socket output stream final OutputStream output = client.getOutputStream(); // Writing the header final String httpHeader = buildHttpHeader(file.length()); final byte[] buffer = httpHeader.getBytes("UTF-8"); output.write(buffer, 0, buffer.length); int writtenBytes = 0; int readBytes; final byte[] buff = new byte[1024 * 12]; // 12 KB while (mIsRunning && (readBytes = inputStream.read(buff)) != -1) { output.write(buff, 0, readBytes); writtenBytes += readBytes; } output.flush(); output.close(); </code>
Заголовки HTTP, которые записываются в MediaPlayer перед аудио
<code>private String buildHttpHeader(final int contentLength) { final StringBuilder sb = new StringBuilder(); sb.append("HTTP/1.1 200 OK\r\n"); sb.append("Content-Length: ").append(contentLength).append("\r\n"); sb.append("Accept-Ranges: bytes\r\n" ); sb.append("Content-Type: audio/mpeg\r\n"); sb.append("Connection: close\r\n" ); sb.append("\r\n"); return sb.toString(); } </code>
Я искал альтернативные реализации, но поскольку я зашифровал аудио, а MediaPlayer не поддерживает InputStreams в качестве источника данных, моя единственная возможность (я думаю ...) - использовать такой прокси-сервер, как этот.
Опять же, это работает довольно хорошо для Android 2.1 - 2.3, но в ICS MediaPlayer буферизует огромное количество этих данных перед воспроизведением.
РЕДАКТИРОВАТЬ 2:
Дальнейшее тестирование показывает, что это также проблема на SGS2 после обновления до Android 4.0.3. Таким образом, похоже, что реализация буферизации MediaPlayer значительно изменилась в 4.0. Это разочаровывает, так как API не предоставляет никакого способа изменить поведение.
РЕДАКТИРОВАТЬ 3:
Ошибка Android создана. Пожалуйста, добавьте комментарии и пометьте там также http://code.google.com/p/android/issues/detail?id=29870
РЕДАКТИРОВАТЬ 4:
Мой код воспроизведения довольно стандартный. У меня есть вызов start () для MediaPlayer в моем методе onPrepared ().
<code>mCurrentPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mCurrentPlayer.setDataSource(url); mCurrentPlayer.prepareAsync(); </code>
Опробовал его, используя только prepare (), а также рекомендованный ajacian81 способ, но безрезультатно.
Я должен добавить, что недавно сотрудник Google ответил мне на мой вопрос и подтвердил, что размер буфера намеренно был увеличен в ICS (для HD-контента). Разработчикам API было предложено добавить возможность устанавливать размер буфера в MediaPlayer.
Хотя я думаю, что этот запрос на изменение API был еще до того, как я пришел, поэтому я не советую никому задерживать дыхание.