2017-09-25 41 views
0

我正在開發一個低級Android庫,它需要在JNI中處理音頻信號以節省處理成本。因爲我可能需要多次引用同一個音頻緩衝區,所以我決定保留一個結構的指針來將這些音頻緩衝區包含在C中(因此多個C函數可以訪問相同的音頻緩衝區)。我主要使用從herehere借來的想法。在JNI/Android-NDK中傳遞指針爲jlong​​不起作用()

但是,事情並不按預期工作。我的程序在另一個函數試圖訪問先前的jni調用分配的內存後崩潰。

下面是JNI例子來說明這個問題:

struct AddAudioRet{ 
    int chCnt; 
    int traceCnt; 
    int sampleCnt; 
    float ***data; // data[chIdx][traceIdx][sampleIdx]; -> reverse order of the Matlab data structure 
}; 
extern "C" jlong Java_XXX_XXX_addAudioSamples(JNIEnv *env, jobject obj, jbyteArray audioToAdd) { 
    // some processing codes 
    AddAudioRet *ret; 
    ret = (AddAudioRet *)malloc(sizeof(AddAudioRet)); 
    ret->chCnt = ps->recordChCnt; // 2 
    ret->traceCnt = repeatToProcess; // 3 
    ret->sampleCnt = as->signalSize; // 2400 
    jlong retLong = (jlong)ret; 
    mylog("retLong (jlong) = %ld", retLong); 
    AddAudioRet *temp = (AddAudioRet *)retLong; 
    mylog("temp's chCnt %d, traceCnt %d, sampleCnt = %d", temp->chCnt, temp->traceCnt, temp->sampleCnt); 
    return retLong; // return the memory address of the ret structure 
} 

extern "C" void Java_XXX_XXX_debugDumpAddAudioRet(JNIEnv *env, jobject obj, jlong addAudioRet) { 
    debug("addAudioRetLong = %ld", addAudioRet); 
    debug("ret's chCnt %d, traceCnt %d, sampleCnt = %d", r->chCnt, r->traceCnt, r->sampleCnt); 
} 

在Android中,我稱之爲JNI函數是這樣的:

public native int addAudioSamples(byte[] audioToAdd); 
public native void debugDumpAddAudioRet(long addAudioRet); 
int testJNI(byte[] data) { 
    long ret = addAudioSamples(data); 
    debugDumpAddAudioRet(ret); 
} 

結果:

retLong (jlong) = 547383410656 
temp's chCnt 2, traceCnt 3, sampleCnt = 2400 
// *** dumped by the debug check *** 
addAudioRetLong = 1922564064 
ret's chCnt 55646750, traceCnt 82374663, sampleCnt = 1831675530 

我知道問題是內存地址和jlong​​之間的類型轉換,因爲內存地址輸出不相同。但是,我不知道它是如何發生的,如果轉換不被允許/合法,當我(平凡地)轉儲「temp」變量時,我會得到錯誤,對嗎?

+0

可能是尺寸問題。指針是64位的,但是長度往往只有32位 - 通常你需要用很長的時間來存儲一個指針。 –

+0

嗨Gabe,我想這也是大小問題,但我確實打印了sizeof jlong​​(= 8字節),我確信java long也是> 8個字節(例如,long testLong = 547383410656L就可以了)。 –

回答

0

我發現了這個問題。我的本地函數簽名是錯誤的....

錯誤:

public native int addAudioSamples(byte[] audioToAdd); 

正確:

public native long addAudioSamples(byte[] audioToAdd); 

感到驚訝的是Java的似乎是相當聰明的幫我做某種功能自動重載。

+0

實際上,如果爲同樣的'extern「C」jlong​​ Java_XXX_XXX_addAudioSamples(JNIEnv * env,jobject obj,jbyteArray audioToAdd)'聲明'native int addAudioSamples(String audioToAdd)',Java將無法捕捉到你。有一種方法可以聲明重載的本地方法,但是:https://stackoverflow.com/a/45024076/192373。 –