forked from mirrors/linphone-iphone
339 lines
No EOL
12 KiB
Text
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}} |