I'm receiving some bytes[] through a WebSocketClient on my Android App. Those bytes are MP3 bytes : Layer III frame Single channel MPEG-1 no checksums 48 kHz, 32 kbit/s What I am trying to do is to write each bytes[] into an AudioTrack as soon as I receive one. Problem is, those bytes[] are MP3, which is a compressed format not accepted by the AudioTrack class. I'm trying to decode them into PCM. And here is how I create my Audio Track :
final AudioTrack player = new AudioTrack.Builder()
.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.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();
Finally here is what the server is sending me. I don't know how I should be building my Audio Track to match this format. The sample rate is set to 48000 Hz, I tried CHANNEL_OUT_STEREO and MONO. I tried all of the ENCODING parameters but I still have a very poor quality and a high pitched voice. Don't know what I'm doing wrong.
Stream #0:0: Audio: mp3 (libmp3lame), 48000 Hz, mono, s16p, 32 kb/s
EDIT: As I said in the comment, I tried something I found on a related post regarding the JLayer decoding, here is the new code:
public void addSample(byte[] data) throws BitstreamException, DecoderException {
Decoder decoder = new Decoder();
InputStream bis = new ByteArrayInputStream(data);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Bitstream bits = new Bitstream(bis);
SampleBuffer pcmBuffer = (SampleBuffer) decoder.decodeFrame(bits.readFrame(), bits);
for (int i = 0; i < pcmBuffer.getBufferLength(); i++) {
if (pcmBuffer.getBuffer()[i] != 0) {
outStream.write(pcmBuffer.getBuffer()[i] & 0xff);
outStream.write((pcmBuffer.getBuffer()[i] >> 8) & 0xff);
}
}
System.out.println("--------");
for (int j = 0; j < outStream.toByteArray().length; j++) {
System.out.println(outStream.toByteArray()[j]);
}
System.out.println("--------");
mTrack.write(outStream.toByteArray(), 0, outStream.toByteArray().length);
bits.closeFrame();
}
Instead of directly writing the short[] data contained in the pcmBuffer, I decoded them in byte[] thanks to an outStream and some mask operation. I get the exact same result (robotic voice). But then as you can see I tried to loop inside the byteArray I'm writing into my AudioTrack, and I tried to print each data. Here is a sample of results :
11-20 10:18:42.331 1749-2268/? I/System.out: 0
11-20 10:18:42.331 1749-2268/? I/System.out: 48
11-20 10:18:42.331 1749-2268/? I/System.out: 0
11-20 10:18:42.331 1749-2268/? I/System.out: 46
11-20 10:18:42.331 1749-2268/? I/System.out: 0
11-20 10:18:42.331 1749-2268/? I/System.out: 44
11-20 10:18:42.331 1749-2268/? I/System.out: 0
11-20 10:18:42.331 1749-2268/? I/System.out: 44
11-20 10:18:42.331 1749-2268/? I/System.out: 0
11-20 10:18:42.331 1749-2268/? I/System.out: 45
11-20 10:18:42.331 1749-2268/? I/System.out: 0
11-20 10:18:42.331 1749-2268/? I/System.out: 48
11-20 10:18:42.331 1749-2268/? I/System.out: 0
So as I suspected, the data are actually written as (LEFT, RIGHT, LEFT, RIGHT)... I don't know how to get a real mono MP3 signal from those.
AFAIK, your code would work if the input is PCM already, so you need some sort of 3rd party code.
If you don't want to mess around with native code (C/C++) and JNI bridges, I suggest you to use JLayer
EDIT: Your edit seems OK. HAve you been tried to play directly the MP3 samples (using JLayer), instead of using AudioTrack?
Code sample:
Player player;
/* create your input stream, bis in your code */
player = new Player(bis);
player.play();