Hello! The problem with finding PjCamera class is solved. PjClass is searched in "pjproject-2.5.5\pjmedia\src\pjmedia-videodev\android_dev.c" file in jni_init_ids() function. This function is normally called in thread which loaded this lib, so this function have access to class loader and everything is working fine, But when you starting use Qt for GUI, QApplication is started in its own thread and the system class loader is available from this context, so jni_init_ids() can't find PjCamera with FindClass. The simplest solution is find PjCamera in JNI_OnLoad() function, defined in "pjproject-2.5.5\pjlib\src\pj\os_core_unix.c" and cache the results. This function is called when library is loaded and class loader is available. To do so the two things should be done: 1. Move some code from jni_init_ids() to JNI_OnLoad(). 2. use __android_log_print instead of PJ_LOG macro (because log facility is not inited at this point). I've made a patch (git diff), hope it will be usefull. 15.08.2016, 14:26, "Анцев Александр" <a.antsev@xxxxxxxxx>: > Hello! > > I'm trying to build an app for android with GUI written on Qt. Now I'm working on video preview. What i've done already: > 1. Build OpenH264 lib. > 2. Build pjsip with video support. > 3. Copy PjCamera.java and PjCameraInfo.java into my app folder (src\org\pjsip\). > > The problem is that pjsip unable to find class name PjCamera from JVM. I have this debug log: > ............. > I/pjsua (16412): 22:52:38.159 android_jni_de ..Android JNI sound library initialized > I/pjsua (16412): 22:52:38.162 pjlib ..select() I/O Queue created (0xb861b48c) > I/pjsua (16412): 22:52:38.182 pjsua_vid.c ..Initializing video subsystem.. > I/pjsua (16412): 22:52:38.183 openh264.cpp ...OpenH264 codec initialized > I/pjsua (16412): 22:52:38.183 opengl_dev.c ...OpenGL device initialized > I/pjsua (16412): 22:52:38.184 android_dev.c ...[JNI] Unable to find class 'PjCamera' > ............. > > And when I'm trying to create preview video program crashes. (I'm not sure that I'm creating video preview with correct device and maybe this is another error). > My code: > vidPrev = new VideoPreview(PJMEDIA_VID_DEFAULT_RENDER_DEV); > VideoPreviewOpParam param; > vidPrev->start(param); // <-- crash here > VideoWindow prev = vidPrev->getVideoWindow(); > > Crash log: > I/pjsua (16412): 22:52:39.511 pjsua_vid.c !Starting preview for cap_dev=-2, show=1 > I/pjsua (16412): 22:52:39.511 pjsua_vid.c .Creating video window: type=preview, cap_id=-2, rend_id=-2 > I/pjsua (16412): 22:52:39.511 pjsua_vid.c ..Window 0: destroying.. > I/pjsua (16412): 22:52:39.511 media.cpp pjsua_vid_preview_start(devId, &prm) error: Invalid video device (PJMEDIA_EVID_INVDEV) (status=520004) [../src/pjsua2/media.cpp:1185] > F/libc (16412): Fatal signal 6 (SIGABRT), code -6 in tid 16638 (QtThread) > I/DEBUG ( 288): pid: 16412, tid: 16638, name: QtThread >>> org.qtproject.example <<< > D/InputDispatcher( 984): Focus left window: 16412 > E/lowmemorykiller( 255): Error writing /proc/16412/oom_score_adj; errno=22 > I/Zygote ( 317): Process 16412 exited due to signal (6) > I/ActivityManager( 984): Process org.qtproject.example (pid 16412)(adj 1) has died.(63,298) > > Does anybody faced with such error before? > > -- > С уважением, > Александр Анцев > > _______________________________________________ > Visit our blog: http://blog.pjsip.org > > pjsip mailing list > pjsip@xxxxxxxxxxxxxxx > http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org -- С уважением, Александр Анцев
diff --git a/3rd part/pjproject-2.5.5/pjlib/src/pj/os_core_unix.c b/3rd part/pjproject-2.5.5/pjlib/src/pj/os_core_unix.c index 0fe05eb..bf2ddf8 100644 --- a/3rd part/pjproject-2.5.5/pjlib/src/pj/os_core_unix.c +++ b/3rd part/pjproject-2.5.5/pjlib/src/pj/os_core_unix.c @@ -56,13 +56,161 @@ #if defined(PJ_JNI_HAS_JNI_ONLOAD) && PJ_JNI_HAS_JNI_ONLOAD != 0 #include <jni.h> +#include <android/log.h> JavaVM *pj_jni_jvm = NULL; +#define PJ_CAMERA_CLASS_PATH "org/pjsip/PjCamera" +#define PJ_CAMERA_INFO_CLASS_PATH "org/pjsip/PjCameraInfo" + +struct jni_objs_t +{ + struct { + jclass cls; + jmethodID m_init; + jmethodID m_start; + jmethodID m_stop; + jmethodID m_switch; + } cam; + + struct { + jclass cls; + jmethodID m_get_cnt; + jmethodID m_get_info; + jfieldID f_facing; + jfieldID f_orient; + jfieldID f_sup_size; + jfieldID f_sup_fmt; + jfieldID f_sup_fps; + } cam_info; + +}; + +struct jni_objs_t jobjs; + +static pj_bool_t jni_get_env(JNIEnv **jni_env) +{ + pj_bool_t with_attach = PJ_FALSE; + if ((*pj_jni_jvm)->GetEnv(pj_jni_jvm, (void **)jni_env, + JNI_VERSION_1_4) < 0) + { + if ((*pj_jni_jvm)->AttachCurrentThread(pj_jni_jvm, jni_env, NULL) < 0) + { + *jni_env = NULL; + } else { + with_attach = PJ_TRUE; + } + } + + return with_attach; +} + +static void jni_detach_env(pj_bool_t need_detach) +{ + if (need_detach) + (*pj_jni_jvm)->DetachCurrentThread(pj_jni_jvm); +} + + +/* Get Java object IDs (via FindClass, GetMethodID, GetFieldID, etc). + * Note that this function should be called from library-loader thread, + * otherwise FindClass, etc, may fail, see: + * http://developer.android.com/training/articles/perf-jni.html#faq_FindClass + */ + +static pj_status_t jni_init_ids() +{ + JNIEnv *jni_env; + pj_status_t status = PJ_SUCCESS; + pj_bool_t with_attach = jni_get_env(&jni_env); + +#define GET_CLASS(class_path, class_name, cls) \ + cls = (*jni_env)->FindClass(jni_env, class_path); \ + if (cls == NULL || (*jni_env)->ExceptionCheck(jni_env)) { \ + (*jni_env)->ExceptionClear(jni_env); \ + __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to find class '" class_name "'"); \ + status = PJ_EINVAL; \ + goto on_return; \ + } else { \ + jclass tmp = cls; \ + cls = (jclass)(*jni_env)->NewGlobalRef(jni_env, tmp); \ + (*jni_env)->DeleteLocalRef(jni_env, tmp); \ + if (cls == NULL) { \ + __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to get global ref for class '" class_name "'"); \ + status = PJ_EINVAL; \ + goto on_return; \ + } \ + } +#define GET_METHOD_ID(cls, class_name, method_name, signature, id) \ + id = (*jni_env)->GetMethodID(jni_env, cls, method_name, signature); \ + if (id == 0) { \ + __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to find method '" method_name "' in class '" class_name "'"); \ + status = PJ_EINVAL; \ + goto on_return; \ + } +#define GET_SMETHOD_ID(cls, class_name, method_name, signature, id) \ + id = (*jni_env)->GetStaticMethodID(jni_env, cls, method_name, signature); \ + if (id == 0) { \ + __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to find static method '" method_name "' in class '" class_name "'"); \ + status = PJ_EINVAL; \ + goto on_return; \ + } +#define GET_FIELD_ID(cls, class_name, field_name, signature, id) \ + id = (*jni_env)->GetFieldID(jni_env, cls, field_name, signature); \ + if (id == 0) { \ + __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to find field '" field_name "' in class '" class_name "'"); \ + status = PJ_EINVAL; \ + goto on_return; \ + } + + /* PjCamera class info */ + GET_CLASS(PJ_CAMERA_CLASS_PATH, "PjCamera", jobjs.cam.cls); + GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "<init>", + "(IIIIIJLandroid/view/SurfaceView;)V", + jobjs.cam.m_init); + GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "Start", "()I", + jobjs.cam.m_start); + GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "Stop", "()V", + jobjs.cam.m_stop); + GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "SwitchDevice", "(I)I", + jobjs.cam.m_switch); + + /* PjCameraInfo class info */ + GET_CLASS(PJ_CAMERA_INFO_CLASS_PATH, "PjCameraInfo", jobjs.cam_info.cls); + GET_SMETHOD_ID(jobjs.cam_info.cls, "PjCameraInfo", "GetCameraCount", "()I", + jobjs.cam_info.m_get_cnt); + GET_SMETHOD_ID(jobjs.cam_info.cls, "PjCameraInfo", "GetCameraInfo", + "(I)L" PJ_CAMERA_INFO_CLASS_PATH ";", + jobjs.cam_info.m_get_info); + GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "facing", "I", + jobjs.cam_info.f_facing); + GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "orient", "I", + jobjs.cam_info.f_orient); + GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedSize", "[I", + jobjs.cam_info.f_sup_size); + GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedFormat", "[I", + jobjs.cam_info.f_sup_fmt); + GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedFps1000", "[I", + jobjs.cam_info.f_sup_fps); + +#undef GET_CLASS_ID +#undef GET_METHOD_ID +#undef GET_SMETHOD_ID +#undef GET_FIELD_ID + +on_return: + jni_detach_env(with_attach); + return status; +} + JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { + __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "JNI_OnLoad started"); pj_jni_jvm = vm; - + + if (jni_init_ids() != PJ_SUCCESS) + __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "Classes caching failed"); + return JNI_VERSION_1_4; } #endif diff --git a/3rd part/pjproject-2.5.5/pjmedia/src/pjmedia-videodev/android_dev.c b/3rd part/pjproject-2.5.5/pjmedia/src/pjmedia-videodev/android_dev.c index 358c532..9f01a4a 100644 --- a/3rd part/pjproject-2.5.5/pjmedia/src/pjmedia-videodev/android_dev.c +++ b/3rd part/pjproject-2.5.5/pjmedia/src/pjmedia-videodev/android_dev.c @@ -197,10 +197,8 @@ static pjmedia_vid_dev_stream_op stream_op = * JNI stuff */ extern JavaVM *pj_jni_jvm; -#define PJ_CAMERA_CLASS_PATH "org/pjsip/PjCamera" -#define PJ_CAMERA_INFO_CLASS_PATH "org/pjsip/PjCameraInfo" -static struct jni_objs_t +struct jni_objs_t { struct { jclass cls; @@ -221,8 +219,9 @@ static struct jni_objs_t jfieldID f_sup_fps; } cam_info; -} jobjs; +}; +extern struct jni_objs_t jobjs; static void JNICALL OnGetFrame(JNIEnv *env, jobject obj, jbyteArray data, jint length, @@ -265,85 +264,6 @@ static pj_status_t jni_init_ids() pj_status_t status = PJ_SUCCESS; pj_bool_t with_attach = jni_get_env(&jni_env); -#define GET_CLASS(class_path, class_name, cls) \ - cls = (*jni_env)->FindClass(jni_env, class_path); \ - if (cls == NULL || (*jni_env)->ExceptionCheck(jni_env)) { \ - (*jni_env)->ExceptionClear(jni_env); \ - PJ_LOG(3, (THIS_FILE, "[JNI] Unable to find class '" \ - class_name "'")); \ - status = PJMEDIA_EVID_SYSERR; \ - goto on_return; \ - } else { \ - jclass tmp = cls; \ - cls = (jclass)(*jni_env)->NewGlobalRef(jni_env, tmp); \ - (*jni_env)->DeleteLocalRef(jni_env, tmp); \ - if (cls == NULL) { \ - PJ_LOG(3, (THIS_FILE, "[JNI] Unable to get global ref for " \ - "class '" class_name "'")); \ - status = PJMEDIA_EVID_SYSERR; \ - goto on_return; \ - } \ - } -#define GET_METHOD_ID(cls, class_name, method_name, signature, id) \ - id = (*jni_env)->GetMethodID(jni_env, cls, method_name, signature); \ - if (id == 0) { \ - PJ_LOG(3, (THIS_FILE, "[JNI] Unable to find method '" method_name \ - "' in class '" class_name "'")); \ - status = PJMEDIA_EVID_SYSERR; \ - goto on_return; \ - } -#define GET_SMETHOD_ID(cls, class_name, method_name, signature, id) \ - id = (*jni_env)->GetStaticMethodID(jni_env, cls, method_name, signature); \ - if (id == 0) { \ - PJ_LOG(3, (THIS_FILE, "[JNI] Unable to find static method '" \ - method_name "' in class '" class_name "'")); \ - status = PJMEDIA_EVID_SYSERR; \ - goto on_return; \ - } -#define GET_FIELD_ID(cls, class_name, field_name, signature, id) \ - id = (*jni_env)->GetFieldID(jni_env, cls, field_name, signature); \ - if (id == 0) { \ - PJ_LOG(3, (THIS_FILE, "[JNI] Unable to find field '" field_name \ - "' in class '" class_name "'")); \ - status = PJMEDIA_EVID_SYSERR; \ - goto on_return; \ - } - - /* PjCamera class info */ - GET_CLASS(PJ_CAMERA_CLASS_PATH, "PjCamera", jobjs.cam.cls); - GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "<init>", - "(IIIIIJLandroid/view/SurfaceView;)V", - jobjs.cam.m_init); - GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "Start", "()I", - jobjs.cam.m_start); - GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "Stop", "()V", - jobjs.cam.m_stop); - GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "SwitchDevice", "(I)I", - jobjs.cam.m_switch); - - /* PjCameraInfo class info */ - GET_CLASS(PJ_CAMERA_INFO_CLASS_PATH, "PjCameraInfo", jobjs.cam_info.cls); - GET_SMETHOD_ID(jobjs.cam_info.cls, "PjCameraInfo", "GetCameraCount", "()I", - jobjs.cam_info.m_get_cnt); - GET_SMETHOD_ID(jobjs.cam_info.cls, "PjCameraInfo", "GetCameraInfo", - "(I)L" PJ_CAMERA_INFO_CLASS_PATH ";", - jobjs.cam_info.m_get_info); - GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "facing", "I", - jobjs.cam_info.f_facing); - GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "orient", "I", - jobjs.cam_info.f_orient); - GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedSize", "[I", - jobjs.cam_info.f_sup_size); - GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedFormat", "[I", - jobjs.cam_info.f_sup_fmt); - GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedFps1000", "[I", - jobjs.cam_info.f_sup_fps); - -#undef GET_CLASS_ID -#undef GET_METHOD_ID -#undef GET_SMETHOD_ID -#undef GET_FIELD_ID - /* Register native function */ { JNINativeMethod m = { "PushFrame", "([BIJ)V", (void*)&OnGetFrame };
_______________________________________________ Visit our blog: http://blog.pjsip.org pjsip mailing list pjsip@xxxxxxxxxxxxxxx http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org