I'm trying to use short[] and jshortArray between C/JAVA as follows in Eclipse:
JNIEXPORT void JNICALL Java_com_testingForFun_testFunc
(JNIEnv *env, jclass clazz, jshort num, jshortArray data) {
jshort outCArray[] = {100, 200};
jshortArray outJNIArray = (*env)->NewShortArray(env, 2); // allocate
if (NULL == outJNIArray) return;
(*env)->SetShortArrayRegion(env, outJNIArray, 0 , 2, outCArray); // copy
//return outJNIArray;
}
I've created the header file using javah and included it. However, Eclipse says NewShortArray and SetShortArrayRegion are unresolved and I can't build the apk. However, not using arrays (jshort and short) works fine. I looked in jni.h and it seems that NewShortArray other related functions are defined if __cplusplus is defined, but I'm using C. I also built the apk on the command line using ndk-build and ant and I read outJNIArray[0] or [1] = 0 in the calling function, so it's not working there either. How do I resolve this issue?
Additionally, Eclipse can't resolve ANDROID_LOG_DEBUG in:
__android_log_print(ANDROID_LOG_DEBUG, "FibLib.c", "fibNI(%lld)", n);
even though
#include <android/log.h>
is at the beginning of the file.
I used Eclipse restart and seems to have cleared up these issues. But every time I edit my .c file, the unresolved errors pop up, and I need to restart. It's very annoying. Any fix for this?
The issue of outJNIArray[] not being set is a separate topic, so I will ask another question on the forum in the future if necessary.
Related
I'm trying to add MP3 read and write capabilities to my Android app. I'm using the lame4android app as a starting point. Encoding a file works for me, but I'm having a problem with the decode functions -- I'm getting undefined references to the decode functions.
Here are excerpts from my wrapper.c:
#include "libmp3lame/lame.h"
#include "jni.h"
lame_t lame;
jint Java_com_intonia_dandy_WavStream_initEncoder(JNIEnv *env,
jobject jobj,
jint in_num_channels,
jint in_samplerate)
{
lame = lame_init();
...
return lame_init_params(lame);
}
hip_t hip;
jint Java_com_intonia_dandy_WavStream_initDecoder(JNIEnv *env, jobject jobj)
{
hip = hip_decode_init();
return hip != 0;
}
And here are the declarations from lame.h:
lame_global_flags * CDECL lame_init(void);
typedef hip_global_flags *hip_t;
hip_t CDECL hip_decode_init(void);
I'm getting an error message:
C:/ACode/dandy/src/main/jni/./wrapper.c:62: undefined reference to `hip_decode_init`
I'm also getting undefined references to hip_decode and and hip_decode_exit. But lame_init, lame_init_params, lame_encode_buffer, and lame_encode_flush do not generate any errors. I get these errors using the command line to run ndk-build, and I get the same errors when I let Android Studio manage the compilation.
How are the lame_* functions different from the hip_decode_* functions? Should I be using the deprecated lame_decode_*?
EDIT: I'm looking at the output of the ndk-build command. The .c files are listed on the console as they are compiled. hip_decode_init is defined in jni/libmp3lame/mpglib_interface.c, but mpglib_interface is not getting compiled, even though it's listed in jni/Android.mk. Why not???
It turns out that the LAME library as distributed does not have decoding enabled. To get it working, I had to do the following:
Add #define HAVE_MPGLIB 1 to mpglib_interface.c
Copy all .c and .h files from the mpglib directory of the LAME distribution.
Edit Android.mk to include the .c files from mpglib.
EDIT: instead of modifying mpglib_interface.c to define HAVE_MPGLIB,
it's better to set compilation flags.
Working with Android Studio 2+, build.gradle should contain
android {
defaultConfig {
ndk {
moduleName "libmp3lame"
cFlags "-DSTDC_HEADERS -DHAVE_MPGLIB"
}
}
}
Or in Android.mk:
LOCAL_CFLAGS = -DSTDC_HEADERS -DHAVE_MPGLIB
I searched online and on this site and found this link which asks the same question I am about to, but the reply does not seem address the question. Plus one of the referenced links are missing. Basically the question is how do you efficiently and intelligently decide when to use a jni-compatible function to what you have in your C source file. I am familiar with what javah command does, but that command converts JAVA methods into a C header file to be used. What about the methods that are already implemented in a C source file? How can you know if you have to convert them to a JNI version of the method? I am using Android Studio and put in the following code in the .c source file that is in my jni folder of the project:
#include "com_example_sansari_usetbt_MainActivity.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <android/log.h>
#define TAG "native-log-tag"
#define LOGI(LOG_TAG, ...) __android_log_print (ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGV(LOG_TAG, ...) __android_log_print (ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
#define LOGE(LOG_TAG, ...) __android_log_print (ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
/*
* Class: com_example_sansari_usetbt_MainActivity
* Method: usetbt
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_sansari_useqsee_MainActivity_Usetbt
(JNIEnv *env, jobject obj)
{
int fd;
int rc = 0;
char *rd_buf[16];
//(*env)->printf("<1>%s: entered\n", argv[0]);
printf("<1>: entered\n");
fd = open("/dev/tbt", O_RDWR);
LOGI(LOG_TAG,"This is a log test");
LOGV(LOG_TAG,"This is a log test");
LOGE(LOG_TAG,"This is a log test");
//(*env)->fd;
//return;
if ( fd == -1 ) {
perror("<1>open failed");
rc = fd;
}
printf("<1>: open: successful\n");
/* Issue a read */
rc = read(fd, rd_buf, 0);
//I need to find what fd is and then use command completion to pick a jni finction. rd-buf seems to be jstring, and 0 seems to be int
rc = (*env)->GetString
if ( rc == -1 ) {
perror("<1>read failed");
close(fd);
}
printf("<1>: read: returning %d bytes!\n",rc);
close(fd);
(*env)->NewStringUTF(env,"Hi From Usetbt version 2");
}
And ndk-build compiles the project, but I do not get the result I am looking for. That is, the normal C version of the code which I compiled with NDK opens the driver and is able to interface with it, but this does not do the same. I do not see the result of the print statement in the kernel logs that is. I am not asking for someone to convert the above code; rather show me the way to know which of the above lines need to be converted, and what is the best way to do it please. I have read a number of items about this, and I am quickly coming up to speed, but if you can describe at a high level how
this conversion is done, please advise. I do have a copy of Java Native Interface and a number of Android texts and am going through them as fast as possible.
Thanks
I believe you need to call fflush(stdout); after your printf. As per this answer.
I'm writing an Adroid app with some C++ code behind the UI using Eclipse + NDK (r8d). I have some code that I thought was fool proof but the compiler just gives me weird errors like "Invalid arguments" without specifics. Here is what my C++ code looks like:
#include <jni.h>
#include <string>
using namespace std;
#include "../../Evaluator.Engine/Evaluator.Engine.h"
Evaluator evaluator;
extern "C" {
JNIEXPORT jstring JNICALL Java_haskellevaluator_android_MainActivity_evaluateNative(JNIEnv *env, jobject, jstring jInput)
{
...
string sInput(L"Hello world");
string sResult = evaluator.evaluate(sInput);
jstring jResult = env->NewStringUTF(sResult.data());
return jResult;
}
}
Evaluator.Engine.h is nothing fancy, but just a declaration of the class Evaluator.
#include <string>
using namespace std;
class Evaluator
{
public:
string evaluate(string input);
};
However, the compiler complains:
Invalid arguments '
Candidates are:
? evaluate(?)
'
as if string is not defined. But if I put a copy of the header file under the same folder, the error goes away. This is a Windows box. I have tried using \ and escaped \\ as path separators and it didn't work.
Does this sound like a NDK (or whatever the preprocessor it uses) bug? I don't want to move the header file because it'll be shared by other projects. I also hate to keep 2 copies of the same file.
Any ideas? Thanks.
Sorry I don't have windows OS, but I've tried you code on a MacOS, but it doesn't work because of:
string sInput(L"Hello world");
Saying that wchar_t cannot be put on std::string. Is it possible to be the same problem ?
I am getting this message which is not allowing my apps to run which contain some native C/C++ files, which I build using NDK. Apps is closing and opening again and crashing in a loop. I am getting below compilation warning after making some awk related changes in android.mk
C:/android-ndk-r8/build/core/add-application.mk 128:Android NDK : Warning: APP-PLATFORM android-14 is larger than android:minsdkVersion 8 in ./AndroidManifest.xml
I have checked relevant threads associated with it, but couldn't find anything which can help me. Can anyone please help me, what I am missing here.
Logcat Output:
15:44:15.815: E/Trace(3026): error opening trace file: No such file or directory (2)
05-28 15:44:16.007: D/dalvikvm(3026): Trying to load lib /data/app-lib/com.example.raptorjni-2/libraptorq-test.so 0x40ce6428
05-28 15:44:16.035: D/dalvikvm(3026): Added shared lib /data/app-lib/com.example.raptorjni-2/libraptorq-test.so 0x40ce6428
05-28 15:44:16.035: D/dalvikvm(3026): No JNI_OnLoad found in /data/app-lib/com.example.raptorjni-2/libraptorq-test.so 0x40ce6428, skipping init
05-28 15:44:16.255: D/RaptorQ(3026): Entering the main function
Java main file snippet from where the C function is called :
Log.d(TAG,"isteps Ecoded" + isteps);
/* Call the JNI-ized version of DFRQEncPerfTest */
String res =
resultRQEncPerfString(nSrcSymbols, symbolSize, loss, niter,
mode, 0, header);
.C file function Snippet:
jstring
Java_com_example_raptorjni_RaptorJni_resultRQEncPerfString
(JNIEnv *env, jobject thiz,
jint nSrcSymbols, jint symbolSize, jint lossrate, jint nLoop,
jint mode, jint nRepair, jint header)
{
Implementation ....
JNI_Onload is optional initialization function introduced since JNI 1.4 (more or less), that allows developers to do some init jobs while library is loaded (for example, register native methods to jvm).
So we really don't need javah or something stupid to implement native java methods in c/c++, just call JNIEnv::registerNatives inside JNI_Onload .
For this issue, I think something else was wrong.
I've spent my last two days on an JNI issue and it's driving me crazy...
I just try to do:
SWIGEXPORT void JNICALL Java_com_my_package_CM_1CoreJNI_CM_1Property_1name_1set(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jstring jarg2) {
const char *arg2 = (*jenv)->GetStringUTFChars(jenv, jarg2, 0);
....
}
I'm calling this function through a JAR and it keeps crashing.
All that I can read from my LogCat is:
03-27 12:44:29.162: E/dalvikvm(1599): JNI ERROR (app bug): accessed stale weak global reference 0x4080f657 (index 15765 in a table of size 0)
03-27 12:44:29.172: W/dalvikvm(1599): JNI WARNING: jstring is an invalid weak global reference (0x4080f657)
03-27 12:44:29.172: W/dalvikvm(1599): in Lcom/my/package/CM_CoreJNI;.CM_Property_name_set:(JLjava/lang/String;)V (GetStringUTFChars)
After long investigations, I've tried to call that function directly from my activity (by adding native void set...) and worked fine!
I'm blocked and don't know how to do...
Did any one managed to call JNI from JAR successful?
EDIT: fixed by removing the jar and and adding the .java files...