I have a problem with NDK.
In my JNI_OnLoad method, I cache the JavaVm pointer, the class that called the method, and the method identifier that I use later:
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved){ JNIEnv *env; cachedJVM = jvm; if((*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_6)){ LOG_ERROR("Could not get JNIEnv*"); return JNI_ERR; } javaClass = (*env)->FindClass(env, "org/test/opensl/AudioProcessor"); if(javaClass == NULL){ LOG_ERROR("Could not get java class"); return JNI_ERR; } javaCallbackMID = (*env)->GetMethodID(env, javaClass, "enqueueAudio", "([B)V"); if(javaCallbackMID == NULL){ LOG_ERROR("Could not get method identifier"); return JNI_ERR; } return JNI_VERSION_1_6; }
I have a little utility method defined as follows, which should get me a pointer to JNIEnv:
JNIEnv* JNU_GetEnv(){ JNIEnv* env; (*cachedJVM)->GetEnv(cachedJVM, (void**)&env, JNI_VERSION_1_6); return env; }
And finally, I have a callback from OpenSL ES SLAndroidSimpleBufferQueueItf that I want to handle the recorded sound from SLRecordItf :
void recorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context){ SLresult result; JNIEnv* env; recorderContext* thisContext = (recorderContext*)context; env = JNU_GetEnv(); if(env == NULL){ LOG_ERROR("Could not get JNIEnv*"); return; } jbyteArray data = (*env)->NewByteArray(env, MAX_PACKET_SIZE); if(data == NULL){ LOG_ERROR("No memory could be allocated for buffer"); return; } (*env)->SetByteArrayRegion(env, data, 0, MAX_PACKET_SIZE, recorderBuffer); (*env)->CallByteMethodA(env, thisContext->caller, javaCallbackMID, data); (*env)->DeleteLocalRef(env, data); result = (*bq)->Enqueue(bq, recorderBuffer, RECORDER_FRAMES * sizeof(jbyte)); checkError(result, "Unable to enqueue new buffer"); }
If the context parameter for the callback method contains only a reference to the object that called its own method. This is a self-defined structure:
typedef struct recorderContext{ jobject caller; } recorderContext;
However, every time I try to run this, I get the error "Could not get JNIEnv*" from the callback method.
My question basically boils down to the following: why can I get a pointer to JNIEnv in the JNI_OnLoad method, but not in recorderCallback, since both use the same Java VM pointer to get JNIEnv?
I need this callback to transfer the recorded audio back to my Java level for further processing ...