Android JellyBean проблема с сетевым медиа

У меня есть приложение, которое воспроизводит файлы MP3, доступные по общедоступному URL. К сожалению, сервер не поддерживает потоковую передачу, но Android делает работу с пользователем вполне приемлемой.

Все работает нормально для всех платформ, кроме JellyBean. При запросе MP3 JB запрашивает Range-Header 10 раз. Только после 10-й попытки он, похоже, возвращается к старому поведению. Похоже, это уже сообщенная проблема.

Я нашел другой поток SO, где рекомендовано решение использовать Tranfer-Encoding: chunked header. Но чуть ниже есть комментарий, что это не работает.

На данный момент я не имею никакого контроля над предоставлением вышеуказанных заголовков ответа, но до тех пор, пока я не смогу это сделать, я подумал о поиске альтернативы на стороне клиента. (даже в этом случае я могу вернуть только Content-Range, который содержит индексы от 0 до Content-Length - 1. Например. Content-Range: байты 0-3123456/3123457).

Я попытался реализовать псевдопоток на стороне клиента:

  1. Откройте входной поток в MP3.
  2. Декодируйте входящие байты, используя JLayer. Я нашел расшифровку по этой ссылке.
  3. Отправьте декодированные байты массива в уже воспроизводимую stream_mode AudioTrack.

Кусок кода, который выполняет декодирование, можно найти там, я только изменил его, чтобы он получал InputStream:

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

Я запрашиваю декодированные байты во временных блоках: начиная с (0, 5000), поэтому сначала у меня будет больший массив для воспроизведения, затем я запрашиваю следующие байтовые массивы, которые охватывают секунду: (5000, 1000), (6000, 1000), (7000, 1000) и т. Д.

Декодирование достаточно быстрое и выполняется в другом потоке, и как только массив декодированных байтов становится доступным, я использую очередь блокировки, чтобы записать ее в AudioTrack, который воспроизводится в другом потоке.

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

Упаковать:

  1. Если вы столкнулись с этой проблемой JellyBean, как вы ее решили?
  2. Если кто-то из вас попробовал мой подход, что я делаю не так в приведенном выше коде? Если это решение, которое вы использовали, я могу опубликовать остальную часть кода.

Спасибо!

2 ответа

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

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

Если вы хотите продолжить идти по этому пути, то вам стоит обратить внимание на реализацию скользящего окна. По сути, это абстрактная техника, позволяющая поддерживать постоянную и плавную сетевую связь. Вы должны быть в состоянии найти несколько примеров через Google, вот с чего начать: http://en.wikipedia.org/wiki/Sliding_window_protocol

Изменить: один из обходных путей, который может помочь вам, пока это не будет исправлено, будет включать в себя исходный код для MediaPlayer.java а также AudioManager.java из SDK <16 в ваш проект и посмотрите, решит ли это проблему. Если у вас нет исходного кода, вы можете загрузить его с помощью SDK Manager.

AudioTrack от природы блокирует документы (Will block until all data has been written to the audio mixer.). Я не уверен, что вы читаете из файла и пишете в AudioTrack в той же теме; если так, то я бы посоветовал вам раскрутить тему для AudioTrack.

Другие вопросы по тегам