В настоящее время я пытаюсь внедрить libmp3lame в свое приложение для Android, чтобы декодировать данные MP3 в PCM.
Чтобы использовать libmp3lame, мне нужно использовать реализацию JNI/NDK, а для декодирования MP3 в PCM мне нужно использовать функцию hip_decode() из libmp3lame.
Эта функция создается в виде файла "lame.h":
int CDECL hip_decode( hip_t gfp
, unsigned char * mp3buf
, size_t len
, short pcm_l[]
, short pcm_r[]
);
Мое приложение работает следующим образом: я получаю один образец монофонического MP3 из WebSocket. Мне нужно декодировать этот образец из MP3 в PCM, а затем записать его в свой AudioTrack, чтобы воспроизвести. Это прямая трансляция, поэтому мне нужна минимально возможная задержка. Я использовал JLayer, и я мог прекрасно понять, что говорил говорящий, но у меня была проблема с «хэшем» / роботизированным голосом. Казалось, что в начале каждого сэмпла у меня было какое-то значение 0, и это вызывало какой-то странный эффект. Теперь мне нужно сделать то же самое с libmp3lame. Итак, что я хочу сделать, это следующее. Каждый раз, когда вызывается мой даже прием WebSocket, мне нужно взять полученный массив байтов (содержащий аудиоданные) и декодировать его в PCM. Мне нужно иметь byte[] или short[] в формате PCM, а затем воспроизвести его в звуковой дорожке. Проблема в том, что я не уверен, как использовать hip_decode для этого. Я действительно не знаком с программированием на C, поэтому может быть очень простой способ сделать это, но я просто не могу этого сделать. Прямо сейчас в моем wrapper.c у меня есть это:
JNIEXPORT void JNICALL Java_com_example_jneb_myapplication_MainActivity_decoderInit(JNIEnv *env, jobject jobj,
) {
hip = hip_decode_init();
}
Я не уверен, какие pcm_l и pcm_r необходимы для использования функции hip_decode. Вот еще немного информации о функции:
/*********************************************************************
* 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
*
*********************************************************************/
РЕДАКТИРОВАТЬ: благодаря ответу bukkojot я смог понять, для чего использовались pcm_l и pcm_r.
Вот обновление моего кода:
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;
}
Прямо сейчас pcmBuffer возвращает только значение 0, и hip_decode тоже возвращает только значение 0. В документе говорится, что если hip_decode возвращает 0, то функция hip_decode «требует больше данных, прежде чем мы сможем завершить декодирование». Я уже передаю функции все данные, которые у меня есть. Что я делаю неправильно с функцией hip_decode?