linphone-ios/wrappers/java/jni.mustache
2017-10-16 15:56:17 +02:00

339 lines
No EOL
12 KiB
Text

/*
linphone_jni.cc
Copyright (C) 2017 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <jni.h>
#include <cpu-features.h>
#include "belle-sip/object.h"
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/mscommon.h"
#include "mediastreamer2/msmediaplayer.h"
#include "mediastreamer2/msutils.h"
#include "mediastreamer2/devices.h"
#include "mediastreamer2/msjava.h"
#include "linphone/core_utils.h"
#include "linphone/core.h"
#include "linphone/tunnel.h"
#include "linphone/account_creator.h"
#include "linphone/wrapper_utils.h"
#include "linphone/lpconfig.h"
#ifdef __ANDROID__
#include <android/log.h>
#include <belle-sip/wakelock.h>
#endif /* __ANDROID__ */
static JavaVM *jvm = NULL;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *ajvm, void *reserved) {
#ifdef __ANDROID__
ms_set_jvm(ajvm);
#endif /* __ANDROID__ */
jvm = ajvm;
return JNI_VERSION_1_2;
}
#define belle_sip_java_user_data_key "java_object"
static const char* GetStringUTFChars(JNIEnv* env, jstring string) {
const char *cstring = string ? env->GetStringUTFChars(string, NULL) : NULL;
return cstring;
}
static void ReleaseStringUTFChars(JNIEnv* env, jstring string, const char *cstring) {
if (string) env->ReleaseStringUTFChars(string, cstring);
}
static jlong GetObjectNativePtr(JNIEnv *env, jobject object) {
jclass objClass = env->GetObjectClass(object);
jfieldID nativePtrId = env->GetFieldID(objClass, "nativePtr", "J");
jlong nativePtr = env->GetLongField(object, nativePtrId);
return nativePtr;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class LinphoneJavaBindings {
public:
LinphoneJavaBindings(JNIEnv *env) {
ms_factory_class = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/mediastream/Factory"));
ms_factory_class_constructor = env->GetMethodID(ms_factory_class, "<init>", "(J)V");
{{#objects}}
{{cPrefix}}_class = (jclass)env->NewGlobalRef(env->FindClass("{{jniPath}}{{classImplName}}"));
{{cPrefix}}_class_constructor = env->GetMethodID({{cPrefix}}_class, "<init>", "(J)V");
{{/objects}}
{{#enums}}
{{cPrefix}}_class = (jclass)env->NewGlobalRef(env->FindClass("{{jniPath}}{{jniName}}"));
{{cPrefix}}_class_constructor_from_int = env->GetStaticMethodID({{cPrefix}}_class, "fromInt", "(I)L{{jniPath}}{{jniName}};");
{{/enums}}
}
~LinphoneJavaBindings() {
JNIEnv *env = 0;
jvm->AttachCurrentThread(&env,NULL);
env->DeleteGlobalRef(ms_factory_class);
{{#objects}}
env->DeleteGlobalRef({{cPrefix}}_class);
{{/objects}}
{{#enums}}
env->DeleteGlobalRef({{cPrefix}}_class);
{{/enums}}
}
jclass ms_factory_class;
jmethodID ms_factory_class_constructor;
{{#objects}}
jclass {{cPrefix}}_class;
jmethodID {{cPrefix}}_class_constructor;
{{/objects}}
{{#enums}}
jclass {{cPrefix}}_class;
jmethodID {{cPrefix}}_class_constructor_from_int;
{{/enums}}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{{#objects}}
jobject get{{className}}(JNIEnv *env, {{classCName}} *cptr) {
jobject jobj = 0;
if (cptr != NULL) {
void *up = belle_sip_object_data_get((belle_sip_object_t *)cptr, belle_sip_java_user_data_key);
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());
if (!ljb) {
ljb = new LinphoneJavaBindings(env);
linphone_factory_set_user_data(linphone_factory_get(), ljb);
}
jclass {{cPrefix}}_class = ljb->{{cPrefix}}_class;
jmethodID {{cPrefix}}_constructor = ljb->{{cPrefix}}_class_constructor;
if (up == NULL) {
jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)cptr);
belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), NULL);
{{cPrefix}}_ref(cptr);
} else {
jobj = env->NewLocalRef((jobject)up);
if (jobj == NULL) {
// Delete weak ref ?
env->DeleteWeakGlobalRef((jobject)up);
// takes implicit local ref
jobj = env->NewObject({{cPrefix}}_class, {{cPrefix}}_constructor, (jlong)cptr);
belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, (void*)env->NewWeakGlobalRef(jobj), NULL);
{{cPrefix}}_ref(cptr);
}
}
}
return jobj;
}
void Java_{{jniPrefix}}{{classImplName}}_unref(JNIEnv* env, jobject thiz, jlong ptr) {
{{classCName}} *cptr = ({{classCName}}*)ptr;
jobject wref = (jobject)belle_sip_object_data_get((belle_sip_object_t *)cptr, belle_sip_java_user_data_key);
belle_sip_object_data_set((belle_sip_object_t *)cptr, belle_sip_java_user_data_key, NULL, NULL);
if (wref) {
env->DeleteWeakGlobalRef(wref);
}
{{cPrefix}}_unref(cptr);
}
{{/objects}}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static inline void handle_possible_java_exception(JNIEnv *env, jobject listener)
{
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
ms_error("Listener %p raised an exception",listener);
}
}
{{#callbacks}}
static {{return}} {{callbackName}}({{params}}) {
JNIEnv *env = 0;
jint jvmResult = jvm->AttachCurrentThread(&env,NULL);
if (jvmResult != 0) {
ms_error("cannot attach VM");
return{{returnIfFail}};
}
{{#isSingleListener}}
{{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks({{firstParam}});
{{/isSingleListener}}
{{#isMultiListener}}
{{classCName}}Cbs *cbs = {{cPrefix}}_get_current_callbacks({{firstParam}});
{{/isMultiListener}}
jobject jlistener = (jobject) {{cPrefix}}_cbs_get_user_data(cbs);
if (jlistener == NULL) {
ms_warning("{{name}}() notification without listener");
return{{returnIfFail}};
}
jclass jlistenerClass = (jclass) env->GetObjectClass(jlistener);
jmethodID jcallback = env->GetMethodID(jlistenerClass, "{{jname}}", "{{jparams}}");
env->DeleteLocalRef(jlistenerClass);
{{#jobjects}}
jobject j_{{objectName}} = get{{className}}(env, (Linphone{{className}} *){{objectName}});
{{/jobjects}}
{{#jenums}}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());
jobject j_{{enumName}} = env->CallStaticObjectMethod(ljb->{{cEnumPrefix}}_class, ljb->{{cEnumPrefix}}_class_constructor_from_int, (jint){{enumName}});
{{/jenums}}
{{#jstrings}}
jstring j_{{stringName}} = {{stringName}} ? env->NewStringUTF({{stringName}}) : NULL;
{{/jstrings}}
env->CallVoidMethod(jlistener, jcallback, {{params_impl}});
{{#jobjects}}
if (j_{{objectName}}) {
env->DeleteLocalRef(j_{{objectName}});
}
{{/jobjects}}
{{#jstrings}}
if (j_{{stringName}}) {
env->DeleteLocalRef(j_{{stringName}});
}
{{/jstrings}}
handle_possible_java_exception(env, jlistener);
{{#hasReturn}}
return 0;
{{/hasReturn}}
}
{{/callbacks}}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{{#interfaces}}
{{#isSingleListener}}
void {{jniPackage}}{{className}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) {
{{/isSingleListener}}
{{#isMultiListener}}
void {{jniPackage}}{{className}}Impl_addListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) {
{{/isMultiListener}}
{{classCName}} *cptr = ({{classCName}}*)ptr;
jobject listener = env->NewGlobalRef(jlistener);
{{#isSingleListener}}
{{classCName}}Cbs *cbs = {{cPrefix}}_get_callbacks(cptr);
{{/isSingleListener}}
{{#isMultiListener}}
{{classCName}}Cbs *cbs = linphone_factory_create_{{factoryName}}_cbs(NULL);
{{/isMultiListener}}
{{cPrefix}}_cbs_set_user_data(cbs, listener);
{{#callbacksList}}
{{cPrefix}}_cbs_set_{{callback}}(cbs, {{callbackName}});
{{/callbacksList}}
{{#isMultiListener}}
{{cPrefix}}_add_callbacks(cptr, cbs);
{{/isMultiListener}}
}
{{#isMultiListener}}
void {{jniPackage}}{{className}}Impl_removeListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) {
{{classCName}} *cptr = ({{classCName}}*)ptr;
const bctbx_list_t *cbs_list = {{cPrefix}}_get_callbacks_list(cptr);
bctbx_list_t *it;
for (it = (bctbx_list_t *)cbs_list; it != NULL; it = it->next) {
{{classCName}}Cbs *cbs = ({{classCName}}Cbs *)it->data;
if ({{cPrefix}}_cbs_get_user_data(cbs) == jlistener) {
{{cPrefix}}_remove_callbacks(cptr, cbs);
break;
}
}
}
{{/isMultiListener}}
{{/interfaces}}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
jobject {{jni_package}}CoreImpl_getMediastreamerFactory(JNIEnv *env, jobject thiz, jlong ptr) {
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());
MSFactory *factory = linphone_core_get_ms_factory((LinphoneCore*)ptr);
return env->NewObject(ljb->ms_factory_class, ljb->ms_factory_class_constructor, (jlong)factory);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{{#methods}}
{{return}} {{name}}({{params}}) {
{{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}}{{#strings}}
const char* c_{{string}} = GetStringUTFChars(env, {{string}});
{{/strings}}{{#objects}}
{{objectClassCName}}* c_{{object}} = NULL;
if ({{object}}) c_{{object}} = ({{objectClassCName}}*)GetObjectNativePtr(env, {{object}});
{{/objects}}{{#lists}}
bctbx_list_t *bctbx_list_{{list}} = NULL;
int {{list}}_count = env->GetArrayLength({{list}});
for (int i=0; i < {{list}}_count; i++) {
{{#isStringList}}
jstring obj = (jstring) env->GetObjectArrayElement({{list}}, i);
const char *str = GetStringUTFChars(env, obj);
if (str) {
bctbx_list_{{list}} = bctbx_list_append(bctbx_list_{{list}}, ms_strdup(str));
ReleaseStringUTFChars(env, obj, str);
}
{{/isStringList}}
{{#isObjList}}
jobject obj = env->GetObjectArrayElement({{list}}, i);
bctbx_list_{{list}} = bctbx_list_append(bctbx_list_{{list}}, ({{objectClassCName}} *)GetObjectNativePtr(env, obj));
{{/isObjList}}
}
{{/lists}}{{#hasListReturn}}
const bctbx_list_t *list = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}});
size_t count = bctbx_list_size(list);
{{#isRealObjectArray}}
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *)linphone_factory_get_user_data(linphone_factory_get());
jobjectArray jni_list_result = env->NewObjectArray((int)count, ljb->{{objectCPrefix}}_class, NULL);{{/isRealObjectArray}}
{{#isStringObjectArray}}jobjectArray jni_list_result = env->NewObjectArray((int)count, env->FindClass("java/lang/String"), env->NewStringUTF(""));{{/isStringObjectArray}}
for (size_t i = 0; i < count; i++) {
{{#isRealObjectArray}}
{{objectClassCName}}* c_object = ({{objectClassCName}}*)list->data;
jobject object = get{{objectClassName}}(env, c_object);
{{/isRealObjectArray}}
{{#isStringObjectArray}}const char *cstring = (const char *)list->data;
jstring object = cstring ? env->NewStringUTF(cstring) : 0;{{/isStringObjectArray}}
if (object != 0) {
env->SetObjectArrayElement(jni_list_result, (int)i, object);
{{#isRealObjectArray}}env->DeleteLocalRef(object);{{/isRealObjectArray}}
}
list = bctbx_list_next(list);
}
{{/hasListReturn}}{{#hasStringReturn}}
const char *c_string = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}};
jstring jni_result = (c_string != NULL) ? env->NewStringUTF(c_string) : NULL;
{{/hasStringReturn}}{{#hasNormalReturn}}
{{#hasReturn}}{{return}} jni_result = ({{return}}){{#returnObject}}get{{returnClassName}}(env, (Linphone{{returnClassName}} *){{/returnObject}}{{/hasReturn}}{{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}){{#returnObject}}){{/returnObject}};
{{/hasNormalReturn}}{{#strings}}
ReleaseStringUTFChars(env, {{string}}, c_{{string}});
{{/strings}}{{#hasReturn}}return jni_result;{{/hasReturn}}{{#hasListReturn}}return jni_list_result;{{/hasListReturn}}
}
{{/methods}}