In my c++ code I do more less sth like the following (i don't want to
go to specyfic into details):
MyCppClass cppObject; //this is an object that contains many methods
and buffer inside
for ( i = 0 ; i <smpleLenght; i++)
{
//here I read next parts of a wav file and put them into a float array
which is passed to the function belove
//I want to handle this part of the code in JAVA not JNI using android
interface of reading wav files
cppObject.function(arrayoffloats,size); //here i a void function that
takes a float *. The results of the function are appended to a buffer
inside the cppObject (a field of MyCppClass)
}
int size1;
float * results = cppObject.returnResultsBuffer(size1); //after all
loop steps are done I return the results from the cppObject to a float
*. The size of the buffer is written inside the size variable.
So after all operations I have a float array named 'result' which has
the size of 'size1'
Now my question Is how to transport this functionality to Android
using NDK. MY ideas are:
1. Because I can't make the cppObject in Java application and it must
'remember' the results of each loop iteration I guess the only
solution is to declare cppObject as a global in the JNI .cpp file - is
this the right approach and how to do this?
2. I am not sure but I guess I have finally discovered how to pass an
array of floats from JAVA to C++. Is this correct?
void Java_my_package_android_first_Hello_fun( JNIEnv* env, jobject
jobj, jint i ,jfloatArray arr )
{
jfloat *samp = (env)->GetFloatArrayElements( arr, 0);
//jfloat *samp = (float*)(env)->GetDirectBufferAddress(arr); //don't
know if this way is also sufficient
if (samp == NULL)
return;
cppObject.function(samp,i); //I assume the cppObject will be a
global and can be accessed like this, although I can't figure out how
to do this
}
3. How to create a proper JNI funcion for this part:
int size1;
float * results = cppObject.returnResultsBuffer(size1);
So after I run the native method in Java I will have the same array as
'results' with size of 'size1'.
I am spending hours after hours looking for a solution in the Internet
so please can somebody help me?
On 04/12/2010 12:45 PM, Serdel wrote:
> for ( i = 0 ; i<smpleLenght; i++)
> {
> //here I read next parts of a wav file and put them into a float array
> which is passed to the function belove
> //I want to handle this part of the code in JAVA not JNI using android
> interface of reading wav files
>
just a note: you might want to create the float array in Java and only
populate it using JNI.
> cppObject.function(arrayoffloats,size); //here i a void function that
> takes a float *. The results of the function are appended to a buffer
> inside the cppObject (a field of MyCppClass)
> }
>
> int size1;
> float * results = cppObject.returnResultsBuffer(size1); //after all
> loop steps are done I return the results from the cppObject to a float
> *. The size of the buffer is written inside the size variable.
>
> So after all operations I have a float array named 'result' which has
> the size of 'size1'
>
Consider changing that code to write into an existing array.
> Now my question Is how to transport this functionality to Android
> using NDK. MY ideas are:
>
> 1. Because I can't make the cppObject in Java application and it must
> 'remember' the results of each loop iteration I guess the only
> solution is to declare cppObject as a global in the JNI .cpp file - is
> this the right approach and how to do this?
>
This is just one possible approach, and you will be limited to one
instance or use it via a static class when using this mechanism. But
note that you have the jobject (you can do some lookups via e.g.
hashtables), and you can also give back pointers to Java (well not as C
pointers, but as jint/jlong numerics) and thus manage your data on the
heap, keeping track of it in your Java code.
> 2. I am not sure but I guess I have finally discovered how to pass an
> array of floats from JAVA to C++. Is this correct?
>
> 3. How to create a proper JNI funcion for this part:
>
Sorry, but this is just basic JNI. Did you really read up on JNI?
Read this, it has lots of example code:
http://java.sun.com/docs/books/jni/html/jniTOC.html
For your problems 2 and 3, be sure to read section 3.3.
Additional note: the JNI 1.2 additions are not covered very good by this
book. For that, also take a look at
http://java.sun.com/j2se/1.4.2/docs/guide/jni/jni-12.html
Just a short note: Your example for 2 did not make much sense. Yes, you
seem to have gotten around to access _one_ array _element_ in there. But
not yet the full array. Note that you cannot depend on a certain memory
organization for Java types, i.e. the jfloatarray might not be stored in
a sequential piece of memory. Also you only managed to get that data for
reading it, do not compare that to getting a reliable pointer to the
"real" memory - i.e. you cannot write to the array by this approach.
The answer for q3 is basically my note above for your q1.
> I am spending hours after hours looking for a solution in the Internet
> so please can somebody help me?
>
Please don't take this as unwillingness to help, but: You definitely
need to understand how the JNI really works. And really, there are lots
of examples out there. Just take any JNI-using open source project and
take a look at how they do it.
-hwh
For now, I have decided to focus on points 2 and 3 so I just create a
single instance of my object inside of the JNI method. The code I use
is the following:
#include "MyCppClass.h"
#include <jni.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
extern "C"{
jfloatArray
Java_my_package_Hello_fun( JNIEnv* env,
jobject jobj,
jint size,
jfloatArray arr
)
{
MyCppClass cppObject(size);
jfloat *samp = (env)->GetFloatArrayElements( arr, 0);
jfloat* samp =(float*) (env)->GetPrimitiveArrayCritical(arr,0);
//following your 2nd link I tried to change the method
of gaining a pointer to input array.
//However using this method causes the application to
crash down.
if (samp == NULL)
return NULL;
cppObject.function(samp,size);
unsigned int size1;
jfloat * buffer = cppObject.returnResultsBuffer(size1);
jfloatArray fl;
fl=(env)->NewFloatArray(size1);
(env)->SetFloatArrayRegion(fl, 0, size1, buffer );
return fl;
}
}
The code compiles without errors and the application runs corectly.
The output arrays seems to be correct although the size of the input
array is 5000 (and the function is called many imes (from hundreds up
to thousands depending on the wav sound time). But you wrote that the
method I use is incorrect (about the improper array passing) so I
please ask an advice on how to better write the code because this
application should be infallable
> For now, I have decided to focus on points 2 and 3 so I just create a
> single instance of my object inside of the JNI method. The code I use
> is the following:
> [...]
> fl=(env)->NewFloatArray(size1);
>
> (env)->SetFloatArrayRegion(fl, 0, size1, buffer )
I don't think you're heading the wrong way anymore. This looks just
right. I've been sceptical at first because you just used the method for
reading arrays (GetFloatArrayElements()) and it seemed as if you were
thinking you would obtain a pointer to the memory location where _Java_
manages the storage (but rather, Java would be free to hand you a copy
of the data at a different location). But you seem to be very aware of
the JNI functions to set the array's values reliably (as you presented
by the code cited above). Please note that there still might be some
value copying involved, but you're on the right side of the specs with
what you do.
So don't take my critic words too seriously. I think you already found
your way. Since you were not indicating that anything goes wrong for the
moment: do you consider the problems solved for now? I just ask because
I feel somewhat committed to try to help with what's left :-)
-hwh
> Thank you for your confirmation. But in your previous post you stated
> that my example for question 2 (passing array from Java to JNI and C+
> +)is inappropriate and I still use the same way (because I did not
> found any other - in each example I have found including the book you
> referred to it looked the same).
Yes. I didn't look very carefully, as it seems, because now I don't
really know what I was thinking when answering your question.
Note that you didn't state the "ReleaseFloatArrayElements(...)", which
cleans up memory or unpins the data.
BTW, I've just dug out an older thread in which an alternative approach
is discussed:
http://groups.google.com/group/android-ndk/browse_thread/thread/b77b06b5c3f5d503/cfedb84c71e1a83a?#cfedb84c71e1a83a
It might be an interesting read.
> I just wanted to add that in my c++
> code the first thing I do inside cppObject.function(samp,size); i to
> memcpy the input value to a new array I create dynamically so all in
> all I work on a copy.
>
You don't really need to do that, I think - the data will not be touched
until you release it again (see comment above).
-hwh
-hwh