JNI native多线程调用Java静态方法

前言:

最近在做音视频实时通信,因为回声问题要解决,而播放和音视频采集是异步处理,所以需要java在中间做音频流桥接;播放端的音视频播放和拉流是在子线程处理的,因此有了这个应用场景。


1.因为env不能多线程共享,而JavaVM可以,所以要通过在JNI入口c文件下把JavaVM保存起来,提供给其他线程使用,然后就可以在其他线程中通过JavaVM来拿到env;同时我也将java类设置为全局变量,供给其他线程使用。

native  C 主线程代码:

JNIEnv *e = NULL;

jint jni_version = NULL;

jclass cls = NULL;

static void
IjkMediaPlayer_setAudioCallBack(JNIEnv *env, jobject thiz)
{
    cls =(*env)->FindClass(env,"com/hongdameng/AudioBridge");
    cls = (*env)->NewGlobalRef(env,cls);

     (*env)->GetJavaVM(env,&gs_jvm);

       jni_version =(*env)-> GetVersion(env);
}

2.在其他子线程中,先拿到JavaVM,然后通过它调用AttachCurrentThread拿到env,这样就可以在子线程调用java方法了。

static JNIEnv *env = NULL;
 static jmethodID mid = NULL;
 static jclass cls = NULL;
static void provide_pcm_data_to_java(uint8_t * audio_buf,int audio_size)
 {
     JavaVM *gs_jvm = get_global_jvm();
     if(gs_jvm != NULL)
     {
         JavaVMAttachArgs thread_args;
         thread_args.name = "audio data callback";
         thread_args.version = get_jni_version();
         thread_args.group = NULL;
         (*gs_jvm)->AttachCurrentThread(gs_jvm,&env, &thread_args);
     }
     if(mid == NULL)
     {
         cls = get_jni_class();
         mid =(*env)->GetStaticMethodID(env,cls,"doAEC","(ILjava/lang/String;[B)Ljava/lang/String;");
     }

     jbyteArray audio_jbyteArray = (*env)->NewByteArray(env,audio_size);
     (*env)->SetByteArrayRegion(env,audio_jbyteArray, 0, audio_size, (jbyte *) audio_buf);


     jstring param =(*env)->NewStringUTF(env,"have buffer");
     jstring result =(*env)->CallStaticObjectMethod(env,cls,mid,audio_size,param,audio_jbyteArray);
     (*env)->DeleteLocalRef(env,param);
     (*env)->DeleteLocalRef(env,result);
     (*env)->DeleteLocalRef(env,audio_jbyteArray);
 }

以下是java端的部分代码:

public final class AudioBridge {

    public static final String doAEC(int dataLen,String s,byte[] audioData){
    }
}


你可能感兴趣的:(Android,JNI,C/C++)