jineb92
jineb92

Reputation: 309

Android Studio - libmp3lame NDK

I am currently trying to implement libmp3lame into my Android Application in order to decode MP3 data into PCM.

To use libmp3lame, I need to use JNI/NDK implementation, and to decode MP3 into PCM I need to use the hip_decode() function from libmp3lame.

This function is instantiated like this the "lame.h" file:

int CDECL hip_decode( hip_t           gfp
                , unsigned char * mp3buf
                , size_t          len
                , short           pcm_l[]
                , short           pcm_r[]
                );

My application works like this: I receive one mono MP3 sample from a WebSocket. I need to decode this sample from MP3 to PCM and then write it into my AudioTrack to play it. It is live stream so I need the lowest latency possible. I was using JLayer and I could understand perfectly what was the speaker saying but I had a "hash" problem / robotic voice. It seemed like I had some 0 value at the beginning of each sample and it caused some weird effect. Now I need to do the same with libmp3lame. So what I want to do is the following. Everytime my WebSocket even reception is called, I need to take the byte array received (containing the audio data) and decode it into PCM. I need to have byte[] or short[] in PCM and then play it in audio track. Problem is I'm not sure how to use the hip_decode to do so. I'm really not familiar with C programming so there might be a very simple way to do it but I just can't do it. Right now in my wrapper.c I have this :

JNIEXPORT void JNICALL Java_com_example_jneb_myapplication_MainActivity_decoderInit(JNIEnv *env, jobject jobj,
    ) {
    hip = hip_decode_init();

}

I'm not sure what are the pcm_l and pcm_r needed to use the hip_decode function. Here is some more information regarding the function :

/*********************************************************************
* input 1 mp3 frame, output (maybe) pcm data.
*
*  nout = hip_decode(hip, mp3buf,len,pcm_l,pcm_r);
*
* input:
*    len          :  number of bytes of mp3 data in mp3buf
*    mp3buf[len]  :  mp3 data to be decoded
*
* output:
*    nout:  -1    : decoding error
*           0    : need more data before we can complete the decode
*           >0    : returned 'nout' samples worth of data in pcm_l,pcm_r
*    pcm_l[nout]  : left channel data
*    pcm_r[nout]  : right channel data
*
*********************************************************************/

EDIT: Thanks to bukkojot answer I've been able to understand what were pcm_l & pcm_r used for.

Here is an update of my code :

JNIEXPORT jshortArray JNICALL Java_com_example_jneb_myapplication_AudioTrackClass_decoderInit(JNIEnv *env, jobject jobj,
                                                                                     jbyteArray data, jint size) {
jsize mp3Len =  (*env)->GetArrayLength(env, data);
// Print the data.length = 96
LOGI("JNI integer: %d", mp3Len);
// mp3 contains all 96 values
jbyte *mp3 = (*env)->GetByteArrayElements(env, data, 0);

// Trying to decode mp3 into PCM
int x = hip_decode(hip, (unsigned char*) mp3, (size_t) mp3Len, pcm_l, pcm_r);

jshortArray pcmBuffer;
pcmBuffer = (*env)->NewShortArray(env, mp3Len);
(*env)->SetShortArrayRegion(env, pcmBuffer, 0, mp3Len, pcm_l);
// Releasing byte array
(*env)->ReleaseByteArrayElements(env, data, mp3, 0);

// Returning
return pcmBuffer;

}

Right now pcmBuffer only return 0 value, and the hip_decode only returns 0 value too. The doc says that if hip_decode return 0 then the hip_decode function "need more data before we can complete the decode". I'm already giving the function all the data I have. What am I doing wrong with the hip_decode function ?

Upvotes: 0

Views: 439

Answers (1)

bukkojot
bukkojot

Reputation: 1530

'm not sure what are the pcm_l and pcm_r needed to use the hip_decode function.

This is the pointers to buffers, where decoded PCM will be written.

Alloc somewhere enough memory for uncompressed sound like:

signed short *pcm_l=malloc(1000000); // make sure it's enough
signed short *pcm_r=malloc(1000000);

And then just pass them to decoding function. Function will return number of useful samples. Pass this data to Java part and write to AudioTrack.

Upvotes: 2

Related Questions