diff --git a/libopus-android/src/main/cpp/OpusJNI.cpp b/libopus-android/src/main/cpp/OpusJNI.cpp index 0a244a6..bc0a08c 100644 --- a/libopus-android/src/main/cpp/OpusJNI.cpp +++ b/libopus-android/src/main/cpp/OpusJNI.cpp @@ -3,10 +3,103 @@ #include "opus.h" namespace Java_com_radio_opus_Opus { -} -static JNINativeMethod method_table[] = { -}; + struct Context { + OpusEncoder* encoder; + OpusDecoder* decoder; + }; + + static Context *getContext(jlong jp) { + auto p = (unsigned long) jp; + Context *con; + con = (Context *) p; + return con; + } + + static jlong create(JNIEnv *env, jclass clazz, jint sampleRate, jint numChannels, jint application, jint bitrate, jint complexity) { + struct Context *con; + con = (struct Context *) malloc(sizeof(struct Context)); + + int encoderError; + OpusEncoder* encoder = opus_encoder_create(sampleRate, 1, application, &encoderError); + if (!encoderError) { + encoderError = opus_encoder_init(encoder, sampleRate, numChannels, application); + + opus_encoder_ctl(encoder, OPUS_SET_BITRATE(bitrate)); + opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(complexity)); + } + + int decoderError; + OpusDecoder* decoder = opus_decoder_create(sampleRate, 1, &decoderError); + if (!decoderError) { + decoderError = opus_decoder_init(decoder, sampleRate, numChannels); + } + + if (encoderError || decoderError) { + free(encoder); + free(decoder); + free(con); + return 0; + } + + con->decoder = decoder; + con->encoder = encoder; + + auto pv = (unsigned long) con; + return pv; + } + + static jint destroy(JNIEnv *env, jclass clazz, jlong n) { + Context *con = getContext(n); + free(con->encoder); + free(con->decoder); + free(con); + return 0; + } + + static jint decode(JNIEnv *env, jclass clazz, jlong n, jbyteArray in, jshortArray out, jint frames) + { + Context *con = getContext(n); + OpusDecoder *decoder = con->decoder; + + jint inputArraySize = env->GetArrayLength(in); + + jbyte* encodedData = env->GetByteArrayElements(in, 0); + jshort* decodedData = env->GetShortArrayElements(out, 0); + + int samples = opus_decode(decoder, (const unsigned char *)encodedData, inputArraySize, decodedData, frames, 0); + + env->ReleaseByteArrayElements(in, encodedData, JNI_ABORT); + env->ReleaseShortArrayElements(out, decodedData, 0); + + return samples; + } + + static jint encode(JNIEnv *env, jclass clazz, jlong n, jshortArray in, jint frames, jbyteArray out) + { + Context *con = getContext(n); + OpusEncoder *encoder = con->encoder; + + jint outputArraySize = env->GetArrayLength(out); + + jshort* audioSignal = env->GetShortArrayElements(in, 0); + jbyte* encodedSignal = env->GetByteArrayElements(out, 0); + + int dataArraySize = opus_encode(encoder, audioSignal, frames, (unsigned char *)encodedSignal, outputArraySize); + + env->ReleaseShortArrayElements(in, audioSignal, JNI_ABORT); + env->ReleaseByteArrayElements(out, encodedSignal, 0); + + return dataArraySize; + } + + static JNINativeMethod method_table[] = { + {"create", "(IIIII)J", (void *) create }, + {"destroy", "(J)I", (void *) destroy }, + {"decode", "(J[B[SI)J", (void *) decode }, + {"encode", "(J[SI[B)J", (void *) encode } + }; +} using namespace Java_com_radio_opus_Opus;