Android - MP3 JLayer отсутствует данные
У меня есть сервер, который кодирует голос в реальном времени в моно или стерео mp3 благодаря libmp3lame и отправляет его порциями через порцию через WebSocket.
Я пытаюсь создать приложение для Android, которое получает эти фрагменты mp3 и воспроизводит их с помощью наиболее подходящего аудиоплеера для Android. Я пошел с AudioTrack, так как кажется довольно простым добавлять куски к плееру, а также ориентироваться на "поток". (Поскольку то, что я делаю, это отправка на трек некоторого байтового массива, а не полной песни, которая локально хранится в телефоне Android).
Поскольку AudioTrack не поддерживает сжатый аудиоформат (например, MP3), я должен декодировать эти фрагменты в PCM, чтобы потом воспроизвести их. Я использую знаменитый JLayer для декодирования в реальном времени. Благодаря этому я могу воспроизводить каждый семпл в моем AudioTrack и слышать, что отправляет сервер.
Моя проблема в том, что полученное / проигрываемое аудио плохо хешируется. (Я могу понять, что говорит говорящий отлично, но качество плохое, как если бы у говорящего был "роботизированный голос").
Вот код, который я использую для получения / декодирования / воспроизведения этих байтов [].
public void addSample(byte[] data) throws BitstreamException, DecoderException, IOException {
// JLayer decoder
Decoder decoder = new Decoder();
// Input Stream with the byte[] voice data
InputStream bis = new ByteArrayInputStream(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Bitstream bits = new Bitstream(bis);
// Decoding MP3 data into PCM in a PCM BUFFER
SampleBuffer pcmBuffer = (SampleBuffer) decoder.decodeFrame(bits.readFrame(), bits);
// Sending the PCMBuffer data into Audio Track to play it
mTrack.write(pcmBuffer.getBuffer(), 0, pcmBuffer.getBufferLength());
bits.closeFrame();
}
И вот моя инициализация AudioTrack
mTrack= new AudioTrack.Builder()
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build())
.setAudioFormat(new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(48000)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.build())
.setBufferSizeInBytes(AudioTrack.getMinBufferSize(48000, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT))
.build();
mTrack.play();
Чтобы понять, что происходит, я попытался отстать от всех данных, содержащихся в pcmBuffer. Кажется, что это огромная часть тех данных, где 0 в самом начале буфера (я бы сказал, что 1/5 буфера равно 0, все они расположены в начале). Тогда я взял осциллограф и попытался получить сигнал, который получал мой телефон на Android. Вот результат:
Как видите, каждый кадр присутствует, но в виде каких-то "пустых" или нулевых значений данных. Эти 0 в начале каждого кадра делают сигнал хэшированным и довольно раздражающим для прослушивания.
Я понятия не имею, исходит ли это от самого сигнала MP3, способа, которым я играю, AudioTrack, JLayer, или способа, которым я декодирую его. Так что, если у кого-то есть идея, это будет действительно здорово.
РЕДАКТИРОВАТЬ:
Выяснил что-то интересное. Декодируя каждый заголовок кадра, я могу получить доступ к большому количеству информации, такой как время в мс для каждого кадра. Я зарегистрировал это:
System.out.println(bits.readFrame().ms_per_frame());
Я обнаружил, что каждый из моих кадров составляет 24 мс. Когда я оглядываюсь назад на осциллограф, я вижу, что каждый кадр фактически занимает 24 мс, но начало / конец каждого кадра заполнен 0. Итак, в первую очередь, это проблема декодирования? Если это не так, как я могу получить четкий сигнал без небольшого разрыва в каждом кадре? Я печатаю все данные, которые мне посылает каждый кадр, каждый кадр начинается с нуля. Как получить четкий сигнал, если в каждом кадре есть какая-то звуковая пустота?
Если я распечатываю данные MP3, которые я получаю каждый кадр (96 бит), у меня есть первые четыре байта (возможно, заголовок?), Которые всегда имеют одинаковое значение: "-1, -5, 20, -60" Затем У меня есть пятый бит, который всегда равен 0, а иногда и шестой бит, который также равен 0. Должен ли я удалить их?