codec2_talkie/libopus-android/src/main/cpp/OpusJNI.cpp

122 wiersze
3.9 KiB
C++

#include <jni.h>
#include <cstdlib>
#include "opus.h"
namespace Java_com_radio_opus_Opus {
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, numChannels, 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, numChannels, &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, jcharArray out)
{
Context *con = getContext(n);
OpusEncoder *encoder = con->encoder;
jint outputArraySize = env->GetArrayLength(out);
jshort* audioSignal = env->GetShortArrayElements(in, 0);
jchar* encodedSignal = env->GetCharArrayElements(out, 0);
int dataArraySize = opus_encode(encoder, audioSignal, frames, (unsigned char *)encodedSignal, outputArraySize);
env->ReleaseShortArrayElements(in, audioSignal, JNI_ABORT);
env->ReleaseCharArrayElements(out, encodedSignal, 0);
return dataArraySize;
}
static JNINativeMethod method_table[] = {
{"create", "(IIIII)J", (void *) create },
{"destroy", "(J)I", (void *) destroy },
{"decode", "(J[B[SI)I", (void *) decode },
{"encode", "(J[SI[C)I", (void *) encode }
};
}
using namespace Java_com_radio_opus_Opus;
extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
} else {
jclass clazz = env->FindClass("com/radio/opus/Opus");
if (clazz) {
jint ret = env->RegisterNatives(clazz, method_table,
sizeof(method_table) / sizeof(method_table[0]));
env->DeleteLocalRef(clazz);
return ret == 0 ? JNI_VERSION_1_6 : JNI_ERR;
} else {
return JNI_ERR;
}
}
}