作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用基于 WebRTC 的 C++ 代码库为 Android 开发实时通信应用程序(视频和音频)。我使用 SWIG 生成了一个 JNI 桥,以从 Java 访问 native 代码。调用的行为是通过在应用程序层中定义并在结构中传递给库代码的许多回调函数确定的。传递这些回调的函数如下所示:void registerCallbacks(CALL_CALLBACKS* callbacks);
在哪里 CALL_CALLBACKS
是一个包含许多回调函数的结构,如下所示:
struct CALL_CALLBACKS {
// CALL_STATE is an Enum
// Called whenever the state of the call changes
void (*statusCallback)(CALL_STATE);
// FRAME is a struct representing a video frame
// Called whenever the other participant sends a video frame, typically at 30 fps
void (*frameCallback)(const FRAME*);
// ...
}
问题是当我让 SWIG 默认做它的事情时,结果是不可用的。它生成一个java类型
CALL_CALLBACKS
其中包含每个回调的 setter 和 getter,它们也是 SWIG 生成的类型。但是,这些类型的命名方式为
SWIGTYPE_p_f_ENUM_CALL_STATUS__void
。并且只是 C 指针的包装器。
最佳答案
我认为 SWIG 自己无法做到这一点。以下是我在普通 JNI 中的做法:
首先,创建一个可以在 Java 端实现的 Java 接口(interface)。
interface Callbacks {
void statusCallback(int status);
void frameCallback(Frame frame);
static native void registerCallbacks(Callbacks cb);
}
接下来,创建将 C++ 参数转发到
jobject g_receiver
的函数。实现接口(interface):
jobject g_receiver;
void my_statusCallback(CALL_STATE s) {
if (!g_receiver) {
// Print a warning?
return;
}
JNIEnv *env = getEnv();
env->PushLocalFrame(10);
jclass cls_Callbacks = env->GetObjectClass(g_receiver);
jmethodID mid_Callbacks_statusCallback = env->GetMethodID(cls_Callbacks, "statusCallback", "(I)V");
env->CallVoidMethod(g_receiver, mid_Callbacks_statusCallback, s);
env->PopLocalFrame(nullptr);
}
void my_frameCallback(const FRAME* frame) {
if (!g_receiver) {
// Print a warning?
return;
}
JNIEnv *env = getEnv();
env->PushLocalFrame(10);
// Create a Frame object from the C++ pointer.
// See Proxy classes at http://swig.org/Doc4.0/Java.html#Java_imclass
jclass cls_Frame = env->FindClass("Frame");
jmethodID ctr_Frame = env->GetMethodID(cls_Frame, "<init>", "(JZ)V");
jobject jFrame = env->NewObject(cls_Frame, ctr_Frame, (jlong) frame, (jboolean)false);
jmethodID mid_Frame_delete = env->GetMethodID(cls_Frame, "delete", "(LFrame;)V");
jclass cls_Callbacks = env->GetObjectClass(g_receiver);
jmethodID mid_Callbacks_frameCallback = env->GetMethodID(cls_Callbacks, "frameCallback", "(LFrame;)V");
env->CallVoidMethod(g_receiver, mid_Callbacks_frameCallback, jFrame);
env->CallVoidMethod(jFrame, mid_Frame_delete); // Disconnect the Java Frame object from the C++ FRAME object.
env->PopLocalFrame(nullptr);
}
CALL_CALLBACKS global_callbacks = { my_statusCallback, my_frameCallback };
最后可以实现
Callbacks#registerCallbacks
如下。这有点棘手,因为您必须确保 g_receiver 是 nullptr 或有效的全局引用:
JNIEXPORT void Java_Callbacks_registerCallbacks(JNIEnv *env, jclass cls_Callbacks, jobject receiver) {
if (g_receiver) {
env->DeleteGlobalRef(g_receiver);
}
g_receiver = receiver ? env->NewGlobalRef(receiver) : nullptr;
registerCallbacks(global_callbacks);
}
我做了一些假设:
getEnv
函数应该使用 JNI 调用 API 来附加当前线程 as a daemon thread .您可以将指针存储在另一个全局变量中。 FindClass
从主线程。您可以通过在 JNI_Onload
中创建对类的全局引用来解决此问题。方法或通过添加 Class<Frame> getFrameClass()
来绕过它Callbacks
的方法界面。或者您可以通过执行 g_receiver.getClass().getClassLoader().findClass("Frame")
. frameCallback
需要释放 FRAME 对象本身。我的代码假定它没有并断开 Java 对象,因此您不会在回调结束后意外使用它。 registerCallbacks
可以多次调用,所以我认为确实如此。您也可以调用registerCallbacks
作为JNI_Onload
的一部分. 关于java - SWIG (Java) : How do I pass a struct with callback functions to C++ from an Android application?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63581654/
我是一名优秀的程序员,十分优秀!