Problem z mediami sieciowymi Android JellyBean
Mam aplikację, która odtwarza pliki MP3 dostępne pod publicznym adresem URL. Niestety serwer nie obsługuje przesyłania strumieniowego, ale Android sprawia, że korzystanie z niego jest całkiem akceptowalne.
Wszystko działa dobrze dla wszystkich platform z wyjątkiem JellyBean. Podczas żądania MP3 JB żąda 10-krotnego zasięgu. Dopiero po dziesiątej próbie wydaje się, że powraca do starego zachowania.Wygląda na to, że ten już zgłoszony problem.
Znalazłem innySO wątek gdzie zalecanym rozwiązaniem jest użycieTranfer-Encoding: chunked nagłówek. Ale tuż poniżej jest komentarz, że to nie działa.
Na razie nie mam żadnej kontroli nad dostarczaniem nagłówków odpowiedzi, ale dopóki nie będę w stanie tego zrobić, pomyślałem, że będę szukał alternatywy po stronie klienta. (mimo to mogę zwrócić tylko zakres zawartości, który zawiera indeksy od 0 do długości treści - 1. Przykładowy zakres zawartości: bajty 0-3123456 / 3123457).
To, co próbowałem zrobić, to zaimplementować pseudo-streaming po stronie klienta:
Otwórz strumień wejściowy do MP3.Dekoduj przychodzące bajty za pomocą JLayer. Znalazłem dekodowanie naten link.Wyślij zdekodowane bajty tablicowe do już odtwarzalnego stream_mode AudioTrack.Fragment kodu, który zawiera dekodowanie, został zmodyfikowany, więc otrzyma strumień wejściowy:
public byte[] decode(InputStream inputStream, int startMs, int maxMs) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
float totalMs = 0;
boolean seeking = true;
try {
Bitstream bitstream = new Bitstream(inputStream);
Decoder decoder = new Decoder();
boolean done = false;
while (!done) {
Header frameHeader = bitstream.readFrame();
if (frameHeader == null) {
done = true;
} else {
totalMs += frameHeader.ms_per_frame();
if (totalMs >= startMs) {
seeking = false;
}
if (!seeking) {
// logger.debug("Handling header: " + frameHeader.layer_string());
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);
if (output.getSampleFrequency() != 44100 || output.getChannelCount() != 2) {
throw new IllegalArgumentException("mono or non-44100 MP3 not supported");
}
short[] pcm = output.getBuffer();
for (short s : pcm) {
outStream.write(s & 0xff);
outStream.write((s >> 8) & 0xff);
}
}
if (totalMs >= (startMs + maxMs)) {
done = true;
}
}
bitstream.closeFrame();
}
return outStream.toByteArray();
} catch (BitstreamException e) {
throw new IOException("Bitstream error: " + e);
} catch (DecoderException e) {
throw new IOException("Decoder error: " + e);
}
}
Żądam zdekodowanych bajtów w kawałkach czasu: począwszy od (0, 5000), więc najpierw będę miał większą tablicę do gry, a następnie żądam następnych tablic bajtów, które rozciągają się na sekundę: (5000, 1000), ( 6000, 1000), (7000, 1000) itd.
Dekodowanie jest wystarczająco szybkie i odbywa się w innym wątku, a gdy dostępna jest dekodowana tablica bajtów, używam kolejki blokującej, aby zapisać ją w AudioTrack, który gra w innym wątku.
Problem polega na tym, że odtwarzanie nie jest płynne, ponieważ kawałki nie są ciągłe na ścieżce (każdy fragment jest ciągły, ale dodany w ścieżce AudioTrack powoduje niechlujne odtwarzanie).
Zapakować:
Jeśli natknąłeś się na ten problem JellyBean, jak go rozwiązałeś?Jeśli któryś z was próbował mojego podejścia, co robię źle w powyższym kodzie? Jeśli jest to rozwiązanie, którego użyłeś, mogę opublikować resztę kodu.Dzięki!