这段时间很忙,一直没有机会来记录和总结一下。
在dmr这端,需要的本地方法有nativesetup,来通知java层建立环境。主要代码在dmrJNI.cpp中实现。
c++层,则使用notify()函数将事件通知给java层。这里用到了回调函数。
dmrJNI.cpp文件中的全局变量:
NPT_SET_LOCAL_LOGGER("platinum.media.renderer") static PLT_UPnP upnp; static PLT_DeviceHostReference device; static bool upnprun = false; static bool deviceAdded = false; static NPT_String rendererName; static NPT_String uuid; // 设置全局对象,规定在一个apk里只能有一个renderer。否则就会引起混乱 static jobject player = NULL; static JavaVM* gJavaVM = NULL; static jclass clazz = NULL; static jmethodID postEventMethodID = NULL; extern DataBuffer g_DataBuf;
本地方法:
extern "C" { JNIEXPORT void JNICALL Java_com_hoperun_renderer_PlayerDNRControl_nativesetup(JNIEnv *env, jobject obj, jobject param); JNIEXPORT jint JNICALL Java_com_hoperun_renderer_PlayerDNRControl_deviceStart(JNIEnv *env, jobject obj,jstring name); JNIEXPORT jint JNICALL Java_com_hoperun_renderer_PlayerDNRControl_modifyName(JNIEnv *env, jobject obj,jstring newName); JNIEXPORT jint JNICALL Java_com_hoperun_renderer_PlayerDNRControl_deviceStop(JNIEnv *env, jobject obj); JNIEXPORT jstring JNICALL Java_com_hoperun_renderer_PlayerDNRControl_getDeviceName(JNIEnv *env, jobject obj); JNIEXPORT jstring JNICALL Java_com_hoperun_renderer_PlayerDNRControl_getDeviceUUID(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_com_hoperun_renderer_PlayerDNRControl_writeData(JNIEnv *env, jobject obj, jint position, jint duration); };
// 其实这个函数主要就是为了保存对象(媒体播放器实例),留其他地方调用 JNIEXPORT void JNICALL Java_com_hoperun_renderer_PlayerDNRControl_nativesetup(JNIEnv *env, jobject obj, jobject param) { NPT_LogManager::GetDefault().Configure("plist:.level=INFO;.handlers=ConsoleHandler;.ConsoleHandler.colors=off;.ConsoleHandler.filter=42"); NPT_LOG_INFO("baojinyu .-----nativesetup-----1"); //获取全局引用对象,这里不能用player=param player = env->NewGlobalRef(param); //JavaVM只有一个,在这里获取并保存。由于可能有以外发生,添加了第二次获取的代码。 env->GetJavaVM(&gJavaVM); if (env->ExceptionOccurred()) { NPT_LOG_INFO("baojinyu .-----nativesetup-2----GetJavaVM fail."); return; } if(gJavaVM == NULL) { NPT_LOG_INFO("baojinyu .------gJavaVM == NULL, assignment value again."); env->GetJavaVM(&gJavaVM); if (env->ExceptionOccurred()) { NPT_LOG_INFO("baojinyu .-----nativesetup-2----GetJavaVM fail."); return; } } NPT_LOG_INFO("baojinyu .-----nativesetup-3----GetJavaVM success."); //clazzID,cannot get it through "FindClass",会提示找不到这个类。这是觉得比较奇怪的地方。 clazz = env->GetObjectClass(param); if (env->ExceptionOccurred()) { NPT_LOG_INFO("baojinyu .-----nativesetup-3----GetObjectClass fail."); return; } NPT_LOG_INFO("baojinyu .-----nativesetup-3----GetObjectClass success."); //MethodID。通过clazzID获取方法ID,参数依次为:类名,方法名,方法的参数和返回值。 postEventMethodID = env->GetStaticMethodID(clazz, "postEvent", "(Ljava/lang/Object;ILjava/lang/String;Ljava/lang/String;)V"); if (env->ExceptionOccurred()) { NPT_LOG_INFO("baojinyu .-----nativesetup-4----GetStaticMethodID fail."); return; } NPT_LOG_INFO("baojinyu .-----nativesetup-4----GetStaticMethodID..success=====>nativesetup success!"); }
//该方法在需要通知上层的事件中,有多处调用。这段代码还与上层java的代码相关。如果java代码中nativesetup中传过来的param为弱引用,则程序出错,会提示 //找不到相应的类。改为直接引用之后,问题就解决了。 void notify(int listenerType,const char* arg1,const char* arg2) { //NPT_LOG_INFO("baojinyu .-----notify-1"); if(player == NULL) { NPT_LOG_INFO("baojinyu-----player==NULL! notify fail.\n "); return; } //Get myEnv。JavaVM全局是惟一的,JNIEnv则是每个线程都有一个,因此它只能在自己的线程中获取。 JNIEnv* myEnv = NULL; //NPT_LOG_INFO("baojinyu .-----notify-2"); gJavaVM->AttachCurrentThread(&myEnv,NULL); //NPT_LOG_INFO("baojinyu .-----notify-3 getenv success."); if(myEnv && clazz && postEventMethodID) { //将uri转换后传给java jstring jarg1 = myEnv->NewStringUTF((const char*)arg1); NPT_LOG_INFO_1("baojinyu notify : arg1--->\n%s|\n",(const char*)arg1); jstring jarg2 = myEnv->NewStringUTF((const char*)arg2); NPT_LOG_INFO_1("baojinyu notify: arg2--->\n%s|\n",(const char*)arg2); myEnv->CallStaticVoidMethod(clazz, postEventMethodID,player,listenerType,jarg1,jarg2); if (myEnv->ExceptionOccurred()) { NPT_LOG_INFO("baojinyu .-----notify --CallStaticVoidMethod fail."); gJavaVM->DetachCurrentThread(); return; } //使用完毕,要释放。 NPT_LOG_INFO("baojinyu .---------notify-success."); gJavaVM->DetachCurrentThread(); } }