Android Audio代码分析25 - JNI callback
今天来说说 native 中的代码是如何调用 java 侧代码的。
在看 setEnabled 代码的时候,我们了解到,最终在函数 EffectHandle::setEnabled 中会调用 java 侧的函数,
将状态改变的事件通知到 java 侧。
今天就以 AudioEffect 中的 native 侧调用 java 函数作为例子,来说明 JNI 中的 callback 函数。
#######################说明################################
1、首先,在 JNI 中会有一个 init 函数,java 侧会首先调用该 init 函数来完成初始化。
对于 AudioEffect 来说,该函数就是 android_media_AudioEffect_native_init 函数。
++++++++++++++++++++++++++++++android_media_AudioEffect_native_init++++++++++++++++++++++++++++++++++
// This function gets some field IDs, which in turn causes class initialization.
// It is called from a static block in AudioEffect, which won't run until the
// first time an instance of this class is used.
static void
android_media_AudioEffect_native_init(JNIEnv *env)
{
LOGV("android_media_AudioEffect_native_init");
fields.clazzEffect = NULL;
fields.clazzDesc = NULL;
// Get the AudioEffect class
// 获取 java 侧的类
// static const char* const kClassPathName = "android/media/audiofx/AudioEffect";
// 此处的 path name 其实是 java 侧类所在的包。
// java 侧, AudioEffect 类所在地包为 package android.media.audiofx;
jclass clazz = env->FindClass(kClassPathName);
if (clazz == NULL) {
LOGE("Can't find %s", kClassPathName);
return;
}
// 创建 java 侧 AudioEffect 对象的一个全局引用
fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
// Get the postEvent method
// 根据函数名称及参数类型从 AudioEffect 对象中获取函数
fields.midPostNativeEvent = env->GetStaticMethodID(
fields.clazzEffect,
"postEventFromNative", // 函数名
"(Ljava/lang/Object;IIILjava/lang/Object;)V"); // 参数类型(object, int, int, int, object)
if (fields.midPostNativeEvent == NULL) {
LOGE("Can't find AudioEffect.%s", "postEventFromNative");
return;
}
// Get the variables fields
// nativeTrackInJavaObj
fields.fidNativeAudioEffect = env->GetFieldID(
fields.clazzEffect,
"mNativeAudioEffect", "I");
if (fields.fidNativeAudioEffect == NULL) {
LOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
return;
}
// fidJniData;
fields.fidJniData = env->GetFieldID(
fields.clazzEffect,
"mJniData", "I");
if (fields.fidJniData == NULL) {
LOGE("Can't find AudioEffect.%s", "mJniData");
return;
}
// 查找类 Descriptor
clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor");
if (clazz == NULL) {
LOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class");
return;
}
fields.clazzDesc = (jclass)env->NewGlobalRef(clazz);
// 得到 Descriptor 的 init 函数
fields.midDescCstor
= env->GetMethodID(
fields.clazzDesc,
"<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
if (fields.midDescCstor == NULL) {
LOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class constructor");
return;
}
}
------------------------------android_media_AudioEffect_native_init----------------------------------
2、 java 侧会调用 native_setup 函数, 该函数中会创建 native 侧对象。
对应 AudioEffect 来说, native_setup 函数就是 android_media_AudioEffect_native_setup 函数。
++++++++++++++++++++++++++++android_media_AudioEffect_native_setup++++++++++++++++++++++++++++++++++++
static jint
android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)
{
LOGV("android_media_AudioEffect_native_setup");
AudioEffectJniStorage* lpJniStorage = NULL;
int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
AudioEffect* lpAudioEffect = NULL;
jint* nId = NULL;
const char *typeStr = NULL;
const char *uuidStr = NULL;
effect_descriptor_t desc;
jobject jdesc;
char str[EFFECT_STRING_LEN_MAX];
jstring jdescType;
jstring jdescUuid;
jstring jdescConnect;
jstring jdescName;
jstring jdescImplementor;
if (type != NULL) {
typeStr = env->GetStringUTFChars(type, NULL);
if (typeStr == NULL) { // Out of memory
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
goto setup_failure;
}
}
if (uuid != NULL) {
&nb
补充:移动开发 , Android ,