How to send a char array from JNI to android

android, android-ndk, arrays, java-native-interface

Solution

Following is some code that is similar to what you are working with. In this example, a jobjectArray is returned to Java where the objects in the Array are UTF Strings.

Native code: ExampleNativeJni.c

#include <jni.h>
#include <android/log.h>

#define LOG_TAG "AndroidJniExample"
#define LOG(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define AUDIO_TRACK_BUFFER_SIZE (48)

/*
*  Method used to get the audio track language codes from a video file
*/

JNIEXPORT jobjectArray JNICALL Java_com_example_nativeGetAudioTracks (JNIEnv * env, jobject obj, jstring filePath) {

    // Convert filePath from jstring to null terminated UTF8 string
    const char *path = (*env)->GetStringUTFChars(env, filePath, 0);
    if (!path ) {
            LOGE ("ERROR : pathToFile Conversion error in nativeGetAudioTracks");
            (*env)->ReleaseStringUTFChars(env, filePath, path);
            return NULL;
    }

    // Each track is 3 chars + a null terminator.
    // Allows for up to 12 languages.
    char langCodeHolder[AUDIO_TRACK_BUFFER_SIZE] = {0};
    int numTracks = 0;
    int fd = open(path, O_RDONLY);
    if (fd > 0) {
        // get audio track magic through custom FUSE IOCTL handler
        numTracks = ioctl(fd, GET_AUDIO_TRACKS, &(langCodeHolder[0]));
        close(fd);
    } else {
        LOGE ("ERROR: open(%s) failed in nativeGetAudioTracks", path);
        (*env)->ReleaseStringUTFChars(env, filePath, path);
        close(fd);
        return NULL;
    }

    if (numTracks < 0) {
        LOG("ERROR: Invalid value returned from GET_AUDIO_TRACKS");
        (*env)->ReleaseStringUTFChars(env, filePath, path);
        return NULL;
    }

    if (numTracks == 0) {
        LOG("ERROR: No audio tracks returned");
        (*env)->ReleaseStringUTFChars(env, filePath, path);
        return NULL;
    }

    // Instantiate array to hold language codes.
    jobjectArray langs;
    const jint langArraySize = numTracks;
    jclass stringObject = (*env)->FindClass(env, "java/lang/String");
    if (stringObject == NULL) {
        (*env)->ReleaseStringUTFChars(env, filePath, path);
        return NULL;
    }
    langs = (*env)->NewObjectArray(env, langArraySize, stringObject, (*env)->NewStringUTF(env, NULL));

    // Extract each 3-letter language code and stuff them into the array.
    jstring langCode;
    char* temp = &(langCodeHolder[0]);
    jint i;
    for (i = 0; i < langArraySize; i++) {
        langCode = temp;
        (*env)->SetObjectArrayElement(env, langs, i, (*env)->NewStringUTF(env, langCode));
        temp += 4;
    }

    (*env)->ReleaseStringUTFChars(env, filePath, path);
    return langs;
}

Android JNI code : ExampleAndroidJni.java

public class ExampleAndroidJni {

    private static ExampleAndroidJni sInstance;
    private static final String TAG = "ExampleAndroidJni";

    public static String[] getAudioTracks(final String filePath) {
        if (sInstance == null) {
            sInstance = new ExampleJniClient();
        }

        if (filePath == null) {
            Log.e(TAG, "file path is null");
            return null;
        }

        final String[] auduioTracks = sInstance.nativeGetAudioTracks(filePath);
        if (auduioTracks == null || auduioTracks.length == 0) {
            Log.i(TAG, "No audio tracks returned for : " + filePath);
        }

        return auduioTracks;
    }

    native String[] nativeGetAudioTracks(String filePath);

    static {
        System.loadLibrary("ExampleNativeJni");
    }
}

Problem

I want to send a block of data from JNI to android. I have created a `jchar*` in JNI and filled it with my data, and returned it to android as `jcharArray`. But while displaying the data in android, it results in junk values. This is my JNI code: ``` JNIEXPORT jcharArray JNICALL Java_com_android_test_dsp_Vread( JNIEnv *env, jobject thiz, jint length) { jchar* datatosend; jcharArray ret;    ret= (*env)->NewCharArray(env, length);    memset(datatosend,1,length);    (*env)->SetCharArrayRegion(env, ret, 0, length, datatosend);    return ret; } ``` My Java code: ``` char[] rxvddata = new rxvddata[length]; rxvddata =Vread(length); textview.setText("Data1:"+Integer.tostring(rxvddata[0]) + "Data2:"+Integer.tostring(rxvddata[1])); ``` Can anyone point out the mistake? struggling for long time..

Original source