1

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.

jineb92
  • 189
  • 1
  • 4
  • 13
  • @rckrd I've stumbled across this post in my research, but it only says that JLayer could be a solution. My problem right now is that I can't make JLayer work – jineb92 Nov 15 '17 at 14:54

1 Answers1

0

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();
webo80
  • 3,365
  • 5
  • 35
  • 52
  • Thanks a lot ! I'm kinda lost because I thought I was using JLayer to decode my MP3 into PCM in this sample. Unless the "buff = (SampleBuffer) decoder.decodeFrame(frameHeader, bits);" is not really decoding my MP3 – jineb92 Nov 15 '17 at 14:53
  • Glad you noticed it, please try it to see if helps. If you need more help on JLayer, feel free to update your question – webo80 Nov 15 '17 at 15:01
  • just updated as you suggested it. Seems like i'm not using JLayer correctly – jineb92 Nov 15 '17 at 15:13
  • First of all, thanks a lot for your help, I finally made it using another instanciation of AudioTrack, mine was deprecated. I finally receive & play sounds. Problem is now it's completly hashed. Everything is high pitched and not continuous – jineb92 Nov 15 '17 at 17:15
  • @jineb92 glad you made it work. no idea on that high-pitched voice, srry – webo80 Nov 16 '17 at 08:53
  • It was a SampleRate problem, now I can hear my voice with the correct frequency. I'm still having a problem though, which is that JLayer seems to decode my mono MP3 as stereo PCM. I'm pretty sure JLayer is behaving weirdly if the input is mono MP3. Do you know anything about this? – jineb92 Nov 17 '17 at 13:50
  • @jineb92 what do you mean exactly? – webo80 Nov 17 '17 at 14:00
  • Well the MP3 i'm receiving is a mono mp3 (1 channel) and not stereo (2 channels). Thing is I'm pretty sure there is a problem regarding mono mp3 decoding with JLayer. This post explains it better than me : https://stackoverflow.com/questions/13959599/jlayer-mono-mp3-to-pcm-decoding – jineb92 Nov 17 '17 at 14:06
  • @jineb92 that answers stands to have found the current solution, don't they? – webo80 Nov 20 '17 at 08:21
  • apparently yes, but I tried everything they did to fix the problem and I still have it. – jineb92 Nov 20 '17 at 08:46
  • I just tried something else to understand the problem, I'll edit the post as the results are interesting. – jineb92 Nov 20 '17 at 09:20
  • @jineb92 a) jlayer is not playing good with mono channels or b) your info obtained as mono refers that only one of the two have information – webo80 Nov 20 '17 at 11:14
  • Well the other post said the JLayer had some problem with mono MP3 decoding. What about your "b" statement? Do you think there is a solution apart from using another decoder? – jineb92 Nov 20 '17 at 11:16
  • If they told that there are some problems regarding JLayer and mono audio, probably is. And, regarding to your experience, certainly is. About using an alternative, you can use libmp3lame with JNI / NDK, what is a more low-level approach, but will probably work better than a Java lib. You have some info [here](http://developer.samsung.com/technical-doc/view.do?v=T000000090). The info is regarding on encoding, but at least you can use the "how to integrate in my project" part. Hope it helps you ;) – webo80 Nov 20 '17 at 12:09
  • I'll probably go for that :). Thanks a lot for your precious help !! – jineb92 Nov 20 '17 at 12:17
  • @jineb92 you're welcome ;) Please accept and/or upvote my answer if it helped – webo80 Nov 20 '17 at 12:55
  • I'm currently trying to implement libmp3lame into my existent project, following the link you gave me. I'm sadly having a little problem concerning the "wrapper" they talk about. I've never used any JNI in my android applications and I don't know how to build it. – jineb92 Nov 20 '17 at 15:55
  • YOu can get some guidance [here](https://developer.android.com/ndk/guides/index.html) – webo80 Nov 21 '17 at 08:11