这段时间很忙,一直没有机会来记录和总结一下。
在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();
}
}