Search code examples
androidmp3pcmaudiotrack

Android - Audio Track noises


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.


Solution

  • 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();