2017-09-25 3 views
0

Ich entwickle eine Low-Level-Android-Bibliothek, die Audiosignale in der JNI verarbeiten muss, um Verarbeitungskosten zu sparen. Da ich möglicherweise mehrmals auf den gleichen Audiopuffer verweisen muss, entscheide ich mich, einen Zeiger einer Struktur beizubehalten, um diesen Audiopuffer in C zu verpacken (so können mehrere C-Funktionen auf denselben Audiopuffer zugreifen). Ich verwende hauptsächlich die von here und here geliehene Idee.Pass-Zeiger als jlong ​​in JNI/Android-NDK funktioniert nicht()

Die Dinge funktionieren jedoch nicht wie erwartet. Mein Programm stürzt nach einer anderen Funktion ab, um auf den Speicher zuzugreifen, der von den vorherigen jni-Aufrufen zugewiesen wurde.

Hier ist das JNI Beispiel, dieses Problem zu zeigen:

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); 
} 

In Android, ich die JNI-Funktionen wie folgt aufrufen:

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

Ergebnisse:

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 

Ich weiß, Das Problem ist die Typumwandlung zwischen der Speicheradresse und jlong, da die Speicheradressausgaben nicht identisch sind. Allerdings weiß ich nicht, wie es passiert, wenn die Konvertierung nicht erlaubt/legal ist, sollte ich den Fehler bekommen, wenn ich (trivialerweise) die "temp" -Variable ablege, oder?

+0

Möglicherweise ein Größenproblem. Zeiger sind 64 Bit, aber lange sind meist nur 32 Bit. Im Allgemeinen müssen Sie einen langen Long verwenden, um einen Zeiger zu speichern. –

+0

Hallo Gabe, ich denke, es ist auch das Größenproblem, aber ich habe die Größe von jlong ​​(= 8 Bytes) gedruckt und ich bin mir sicher, dass Java lang auch> 8 Byte ist (zB lang testLong = 547383410656L wird in Ordnung sein). –

Antwort

0

Ich habe das Problem gefunden. Meine Mutter Funktion Unterschrift ist falsch ....

Falsch:

public native int addAudioSamples(byte[] audioToAdd); 

Richtig:

public native long addAudioSamples(byte[] audioToAdd); 

Fühlen Sie sich so überrascht, dass Java ziemlich schlau scheint mir eine Art von Funktion zu helfen, zu tun Überlastung automatisch .

+0

Tatsächlich wird Java Sie nicht abfangen, wenn Sie 'native int addAudioSamples (String audioToAdd)' für dasselbe 'externe' C 'jlong ​​Java_XXX_XXX_addAudioSamples (JNIEnv * env, jobject obj, jbyteArray audioToAdd) 'deklarieren. Es gibt jedoch eine Möglichkeit, überladene native Methoden zu deklarieren: https://stackoverflow.com/a/45024076/192373. –

Verwandte Themen