2017-09-25 5 views
0

Je développe une bibliothèque Android de bas niveau qui doit traiter les signaux audio dans le JNI pour économiser le coût de traitement. Puisqu'il me faudra peut-être faire plusieurs fois référence au même tampon audio, je décide donc de garder un pointeur de structure pour envelopper ces tampons audio dans C (afin que plusieurs fonctions C puissent accéder au même tampon audio). J'utilise principalement l'idée empruntée de here et here.Passer le pointeur comme jlong ​​dans JNI/Android-NDK ne fonctionne pas()

Cependant, les choses ne fonctionnent pas comme prévu. Mon programme plante après une autre fonction essaie d'accéder à la mémoire allouée par les précédents appels jni.

Voici l'exemple JNI pour montrer ce problème:

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

Dans Android, j'appelle les fonctions JNI comme ceci:

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

Résultats:

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 

Je sais le problème est la conversion de type entre l'adresse mémoire et jlong ​​puisque les sorties d'adresse mémoire ne sont pas identiques. Cependant, je ne sais pas comment cela se passe, si la conversion n'est pas autorisée/légale, je devrais obtenir l'erreur quand je jette (trivialement) la variable "temp", non?

+0

Peut-être un problème de taille. Les pointeurs sont 64 bits, mais long a tendance à être seulement 32 bits - généralement, vous devez utiliser un long long pour stocker un pointeur. –

+0

Salut Gabe, je suppose que c'est aussi le problème de taille, mais j'ai fait imprimer le sizeof jlong ​​(= 8 octets) et je suis certain que java long est> 8-byte aussi (par exemple, long testLong = 547383410656L sera ok). –

Répondre

0

J'ai trouvé le problème. Ma signature de la fonction native est mal ....

Mauvais:

public native int addAudioSamples(byte[] audioToAdd); 

Correct:

public native long addAudioSamples(byte[] audioToAdd); 

Sentez-vous tellement surpris que Java semble assez intelligent pour me aider à faire une sorte de surcharge de fonction automatiquement .

+0

En fait, Java ne vous interceptera pas si vous déclarez 'native int addAudioSamples (String audioToAdd)' pour le même 'extern" C jlong ​​Java_XXX_XXX_addAudioSamples (JNIEnv * env, jobject obj, jbyteArray audioToAdd) '. Il existe cependant un moyen de déclarer des méthodes natives surchargées: https://stackoverflow.com/a/45024076/192373. –