/* 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 #include #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 #endif /* __ANDROID__ */ static JavaVM *jvm = NULL; static const char* LogDomain = "Linphone"; static jmethodID loghandler_id; static jobject handler_obj=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; } static void SetObjectNativePtr(JNIEnv *env, jobject object, jlong ptr) { jclass objClass = env->GetObjectClass(object); jfieldID nativePtrId = env->GetFieldID(objClass, "nativePtr", "J"); env->SetLongField(object, nativePtrId, ptr); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void linphone_android_log_handler(int prio, char *str) { char *current; char *next; if (strlen(str) < 512) { __android_log_write(prio, LogDomain, str); } else { current = str; while ((next = strchr(current, '\n')) != NULL) { *next = '\0'; if (next != str && next[-1] == '\r') next[-1] = '\0'; __android_log_write(prio, LogDomain, current); current = next + 1; } __android_log_write(prio, LogDomain, current); } } static void linphone_android_ortp_log_handler(const char *domain, OrtpLogLevel lev, const char *fmt, va_list args) { char* str = bctbx_strdup_vprintf(fmt, args); const char *levname = "undef"; if (str == NULL) return; int prio; switch(lev) { case ORTP_DEBUG: prio = ANDROID_LOG_DEBUG; levname="debug"; break; case ORTP_MESSAGE: prio = ANDROID_LOG_INFO; levname="message"; break; case ORTP_WARNING: prio = ANDROID_LOG_WARN; levname="warning"; break; case ORTP_ERROR: prio = ANDROID_LOG_ERROR; levname="error"; break; case ORTP_FATAL: prio = ANDROID_LOG_FATAL; levname="fatal"; break; default: prio = ANDROID_LOG_DEFAULT; break; } if (handler_obj) { JNIEnv *env = ms_get_jni_env(); jstring jdomain = env->NewStringUTF(LogDomain); jstring jlevname = env->NewStringUTF(levname); jstring jstr = env->NewStringUTF(str); env->CallVoidMethod(handler_obj, loghandler_id, jdomain, (jint)lev, jlevname, jstr, NULL); if (jdomain) env->DeleteLocalRef(jdomain); if (jlevname) env->DeleteLocalRef(jlevname); if (jstr) env->DeleteLocalRef(jstr); } else { linphone_android_log_handler(prio, str); } bctbx_free(str); } extern "C" void Java_org_linphone_core_FactoryImpl_setDebugMode(JNIEnv* env, jobject thiz, jboolean isDebug, jstring jdebugTag) { if (isDebug) { LogDomain = GetStringUTFChars(env, jdebugTag); linphone_core_enable_logs_with_cb(linphone_android_ortp_log_handler); } else { linphone_core_disable_logs(); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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, "", "(J)V"); {{#objects}} {{cPrefix}}_class = (jclass)env->NewGlobalRef(env->FindClass("{{jniPath}}{{classImplName}}")); {{cPrefix}}_class_constructor = env->GetMethodID({{cPrefix}}_class, "", "(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}} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus extern "C" { #endif {{#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}} {{#hasReturn}}{{jniUpcallType}} jni_upcall_result = {{/hasReturn}}env->{{jniUpcallMethod}}(jlistener, jcallback, {{params_impl}}); {{#hasReturn}} {{#isJniUpcallObject}} {{return}} c_upcall_result = NULL; if (jni_upcall_result) c_upcall_result = ({{return}})GetObjectNativePtr(env, jni_upcall_result); {{/isJniUpcallObject}} {{#isJniUpcallBasicType}} {{return}} c_upcall_result = ({{return}}) jni_upcall_result; {{/isJniUpcallBasicType}} {{/hasReturn}} {{#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 c_upcall_result; {{/hasReturn}} } {{/callbacks}} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {{#interfaces}} {{#isSingleListener}} void Java_{{jniPackage}}{{className}}Impl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { {{/isSingleListener}} {{#isMultiListener}} void Java_{{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 Java_{{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 Java_{{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); } jobject Java_{{jni_package}}FactoryImpl_createCore(JNIEnv *env, jobject thiz, jobject jfactory, jobject jlistener, jstring jconfig_path, jstring jfactory_config_path, jobject jcontext) { LinphoneFactory *cptr = linphone_factory_get(); SetObjectNativePtr(env, jfactory, (jlong)cptr); // Set the C factory ptr as Factory.nativePtr for next factory calls LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(cptr); jobject listener = env->NewGlobalRef(jlistener); const char *config_path = GetStringUTFChars(env, jconfig_path); const char *factory_config_path = GetStringUTFChars(env, jfactory_config_path); LinphoneCore *core = NULL; linphone_core_cbs_set_user_data(cbs, listener); linphone_core_cbs_set_transfer_state_changed(cbs, linphone_core_on_transfer_state_changed); linphone_core_cbs_set_chat_room_instantiated(cbs, linphone_core_on_chat_room_instantiated); linphone_core_cbs_set_friend_list_created(cbs, linphone_core_on_friend_list_created); linphone_core_cbs_set_subscription_state_changed(cbs, linphone_core_on_subscription_state_changed); linphone_core_cbs_set_call_log_updated(cbs, linphone_core_on_call_log_updated); linphone_core_cbs_set_call_state_changed(cbs, linphone_core_on_call_state_changed); linphone_core_cbs_set_authentication_requested(cbs, linphone_core_on_authentication_requested); linphone_core_cbs_set_notify_presence_received_for_uri_or_tel(cbs, linphone_core_on_notify_presence_received_for_uri_or_tel); linphone_core_cbs_set_buddy_info_updated(cbs, linphone_core_on_buddy_info_updated); linphone_core_cbs_set_network_reachable(cbs, linphone_core_on_network_reachable); linphone_core_cbs_set_notify_received(cbs, linphone_core_on_notify_received); linphone_core_cbs_set_new_subscription_requested(cbs, linphone_core_on_new_subscription_requested); linphone_core_cbs_set_registration_state_changed(cbs, linphone_core_on_registration_state_changed); linphone_core_cbs_set_notify_presence_received(cbs, linphone_core_on_notify_presence_received); linphone_core_cbs_set_ec_calibration_audio_init(cbs, linphone_core_on_ec_calibration_audio_init); linphone_core_cbs_set_message_received(cbs, linphone_core_on_message_received); linphone_core_cbs_set_ec_calibration_result(cbs, linphone_core_on_ec_calibration_result); linphone_core_cbs_set_info_received(cbs, linphone_core_on_info_received); linphone_core_cbs_set_call_stats_updated(cbs, linphone_core_on_call_stats_updated); linphone_core_cbs_set_friend_list_removed(cbs, linphone_core_on_friend_list_removed); linphone_core_cbs_set_refer_received(cbs, linphone_core_on_refer_received); linphone_core_cbs_set_configuring_status(cbs, linphone_core_on_configuring_status); linphone_core_cbs_set_call_created(cbs, linphone_core_on_call_created); linphone_core_cbs_set_publish_state_changed(cbs, linphone_core_on_publish_state_changed); linphone_core_cbs_set_call_encryption_changed(cbs, linphone_core_on_call_encryption_changed); linphone_core_cbs_set_is_composing_received(cbs, linphone_core_on_is_composing_received); linphone_core_cbs_set_message_received_unable_decrypt(cbs, linphone_core_on_message_received_unable_decrypt); linphone_core_cbs_set_log_collection_upload_progress_indication(cbs, linphone_core_on_log_collection_upload_progress_indication); linphone_core_cbs_set_version_update_check_result_received(cbs, linphone_core_on_version_update_check_result_received); linphone_core_cbs_set_ec_calibration_audio_uninit(cbs, linphone_core_on_ec_calibration_audio_uninit); linphone_core_cbs_set_global_state_changed(cbs, linphone_core_on_global_state_changed); linphone_core_cbs_set_log_collection_upload_state_changed(cbs, linphone_core_on_log_collection_upload_state_changed); linphone_core_cbs_set_dtmf_received(cbs, linphone_core_on_dtmf_received); core = linphone_factory_create_core_2(linphone_factory_get(), cbs, config_path, factory_config_path, NULL, (void *)jcontext); ReleaseStringUTFChars(env, jconfig_path, config_path); ReleaseStringUTFChars(env, jfactory_config_path, factory_config_path); return getCore(env, core); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {{#methods}} {{#notEmpty}} {{return}} {{name}}({{params}}) { {{#notStatic}}{{classCName}} *cptr = ({{classCName}}*)ptr;{{/notStatic}}{{#strings}} const char* c_{{string}} = GetStringUTFChars(env, {{string}}); {{/strings}}{{#bytes}} {{bytesargtype}} c_{{bytesargname}} = ({{bytesargtype}})env->GetByteArrayElements({{bytesargname}}, NULL); {{/bytes}}{{#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}}{{#hasByteArrayReturn}} {{c_type_return}} jni_result = {{c_name}}({{#notStatic}}cptr{{/notStatic}}{{params_impl}}); if (!jni_result) return NULL; size_t jni_result_length = strlen((const char *)jni_result); jbyteArray array = env->NewByteArray((int)jni_result_length); env->SetByteArrayRegion(array, 0, (int)jni_result_length, (const jbyte*)jni_result); return array; {{/hasByteArrayReturn}}{{#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}}{{#bytes}} env->ReleaseByteArrayElements({{bytesargname}}, (jbyte*)c_{{bytesargname}}, JNI_ABORT); {{/bytes}}{{#hasReturn}}return jni_result;{{/hasReturn}}{{#hasListReturn}}return jni_list_result;{{/hasListReturn}} } {{/notEmpty}} {{/methods}} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Manually wrapped ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Java_org_linphone_core_CallImpl_setNativeVideoWindowId(JNIEnv *env, jobject thiz, jlong ptr, jobject id) { LinphoneCall *cptr = (LinphoneCall*)ptr; jobject oldWindow = (jobject) linphone_call_get_native_video_window_id(cptr); if (oldWindow == id) { ms_warning("Java_org_linphone_core_CallImpl_setNativeVideoWindowId(): new id (%p) is the same as the current one, skipping...", id); return; } if (id != NULL) { id = env->NewGlobalRef(id); ms_message("Java_org_linphone_core_CallImpl_setNativeVideoWindowId(): NewGlobalRef(%p)", id); } else ms_message("Java_org_linphone_core_CallImpl_setNativeVideoWindowId(): setting to NULL"); linphone_call_set_native_video_window_id(cptr, (void *)id); if (oldWindow != NULL) { ms_message("Java_org_linphone_core_CallImpl_setNativeVideoWindowId(): DeleteGlobalRef(%p)", oldWindow); env->DeleteGlobalRef(oldWindow); } } void Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(JNIEnv *env, jobject thiz, jlong ptr, jobject id) { LinphoneCore *cptr = (LinphoneCore*)ptr; jobject oldWindow = (jobject) linphone_core_get_native_video_window_id(cptr); if (oldWindow == id) { ms_warning("Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(): new id (%p) is the same as the current one, skipping...", id); return; } if (id != NULL) { id = env->NewGlobalRef(id); ms_message("Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(): NewGlobalRef(%p)", id); } else ms_message("Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(): setting to NULL"); linphone_core_set_native_preview_window_id(cptr, (void *)id); if (oldWindow != NULL) { ms_message("Java_org_linphone_core_CoreImpl_setNativePreviewWindowId(): DeleteGlobalRef(%p)", oldWindow); env->DeleteGlobalRef(oldWindow); } } void Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(JNIEnv *env, jobject thiz, jlong ptr, jobject id) { LinphoneCore *cptr = (LinphoneCore*)ptr; jobject oldWindow = (jobject) linphone_core_get_native_preview_window_id(cptr); if (oldWindow == id) { ms_warning("Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(): new id (%p) is the same as the current one, skipping...", id); return; } if (id != NULL) { id = env->NewGlobalRef(id); ms_message("Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(): NewGlobalRef(%p)", id); } else ms_message("Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(): setting to NULL"); linphone_core_set_native_video_window_id(cptr, (void *)id); if (oldWindow != NULL) { ms_message("Java_org_linphone_core_CoreImpl_setNativeVideoWindowId(): DeleteGlobalRef(%p)", oldWindow); env->DeleteGlobalRef(oldWindow); } } #ifdef __cplusplus } #endif