2015년 11월 25일 수요일

android JNI 를 이용한 c/c++ -> java 메소드 호출 - call method from c/c++ to java with android jni

1. java 에서 호출 메소드 정의
package com.kimdh.dxmediaplayer;
... 
public class DXMediaPlayer {  
   static {  
     System.loadLibrary("DXMediaPlayer");  
   }  
    
   private native void createPlayer();  
   private native void destroyPlayer();  
    
   protected void onDXEvent(int event_type, String strEvent) {  
     ...  
   }  
   ...  
   protected int writeAudioOut(byte[] buffer) {  
     ...  
   }  
 }  

2. java -> c/c++ 함수 호출에서 JavaVM 등 확보
 static JavaVM*  m_pJVM = NULL;  
 jobject    m_object;  
 ...  
 jmethodID    m_method_onDXEvent;  
 ...  
 jmethodID    m_method_writeAudioOut;  
   
 JNIEXPORT void JNICALL Java_com_kimdh_dxmediaplayer_DXMediaPlayer_createPlayer(JNIEnv *env, jobject obj)  
 {  
   m_object = env->NewGlobalRef(obj);  
   
   jclass cls = env->GetObjectClass(m_object);  
   if (cls == NULL) DXPRINTF("Failed to find class\n");  
   
   m_method_onDXEvent = env->GetMethodID(cls, "onDXEvent", "(ILjava/lang/String;)V");  
   if (m_method_onDXEvent == NULL) DXPRINTF("Unable to get method ref : onDXEvent\n");  
   
   m_method_writeAudioOut = env->GetMethodID(cls, "writeAudioOut", "([B)I");
   if (m_method_writeAudioOut == NULL) DXPRINTF("Unable to get method ref : writeAudioOut\n"); 

   if (m_pJVM == NULL)  
     env->GetJavaVM(&m_pJVM);  
 }  
   

3. 호출 함수 정의
 int OnDXEvent(WPARAM wParam, LPARAM lParam)  
 {  
   ...  
   int type = 123;  
   char strEvent[512] = {0};  
   jstring jstrEvent;  
   
   JNIEnv *env;  
    
   int getEnvStat = m_pJVM->GetEnv((void **)&env, JNI_VERSION_1_6);  
   if (getEnvStat == JNI_EDETACHED) {  
     //DXPRINTF("GetEnv: not attached\n");  
     if (m_pJVM->AttachCurrentThread(&env, NULL) != 0) {  
       DXPRINTF("Failed to attach\n");  
       return -1;  
     }  
   } else if (getEnvStat == JNI_OK) {  
     //  
   } else if (getEnvStat == JNI_EVERSION) {  
     DXPRINTF("GetEnv: version not supported\n");  
     return -1;  
   }  
   
   sprintf(strEvent, "event string");  
   
   jstrEvent = env->NewStringUTF(strEvent);  
   
   if (m_method_onDXEvent)  
     env->CallVoidMethod(m_object, m_method_onDXEvent, type, jstrEvent);  
   
   if (env->ExceptionCheck()) {  
     env->ExceptionDescribe();  
   }  
   
   if (getEnvStat == JNI_EDETACHED)  
     m_pJVM->DetachCurrentThread();  
   
   return 0;  
 }  
   
 int WriteAudioOut(unsigned char *buffer, int size)  
 {  
     JNIEnv *env;  
   
     int getEnvStat = m_pJVM->GetEnv((void **)&env, JNI_VERSION_1_6);  
     if (getEnvStat == JNI_EDETACHED) {  
        //DXPRINTF("GetEnv: not attached\n");  
        if (m_pJVM->AttachCurrentThread(&env, NULL) != 0) {  
            DXPRINTF("Failed to attach\n");  
            return -1;  
        }  
     } else if (getEnvStat == JNI_OK) {  
       //  
     } else if (getEnvStat == JNI_EVERSION) {  
        DXPRINTF("GetEnv: version not supported\n");  
        return -1;  
     }  
   
     int ret = -1;  
     if (m_method_writeAudioOut) {  
         jbyteArray jarr = env->NewByteArray(size);  
         jbyte* jbytes = env->GetByteArrayElements(jarr, NULL);  
   
         memcpy(jbytes, buffer, size);  
         env->SetByteArrayRegion(jarr, 0, size, jbytes);  
    
         ret = env->CallIntMethod(m_object, m_method_writeAudioOut, jarr);  
   
         env->ReleaseByteArrayElements(jarr, jbytes, JNI_ABORT);  
     }  
   
     if (env->ExceptionCheck())  
         env->ExceptionDescribe();  
   
     if (getEnvStat == JNI_EDETACHED)  
         m_pJVM->DetachCurrentThread();  
    
     return ret;  
 }  

4. 함수 호출
...
OnDXEvent(NULL, NULL);
...
WriteAudioOut(buf, size);
...

5. JNI 변수 해제
 JNIEXPORT void JNICALL Java_com_kimdh_dxmediaplayer_DXMediaPlayer_destroyPlayer(JNIEnv *env, jobject obj)  
 {  
   env->DeleteGlobalRef(m_object);  
 }  

댓글 없음:

댓글 쓰기