Подтвердить что ты не робот

Проблема с сетевым носителем JellyBean для Android

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

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

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

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

То, что я пытался сделать, - реализовать псевдо-потоковое на стороне клиента:

  • Откройте входной поток в MP3.
  • Декодирование входящих байтов с помощью JLayer. Я нашел декодирование в эту ссылку.
  • Отправьте декодированные байты массива в уже воспроизводимый 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 приводит к неаккуратным воспроизведением).

Завершить:

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

Спасибо!

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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