JNI byteArray传递帮助

时间:2011-04-09 18:48:42

标签: c java-native-interface android-ndk

尝试执行以下代码时,我的Android应用程序关闭(没有错误或任何内容)一直存在问题:

JNIEXPORT void Java_teamjeff_oggstreamtest_MainTest_audioFunc(JNIEnv* env, jobject obj) {
//<REMOVED VARIABLE INITIALIZATION>
  jclass cls = (*env)->GetObjectClass(env, obj);
  jmethodID writeDataFunc = (*env)->GetMethodID(env, cls, "writeToAudioTrack", "([B)V");
  if (!writeDataFunc) return;
  jmethodID readDataFunc = (*env)->GetMethodID(env, cls, "readFromBuffer", "([B)I");
  if (!readDataFunc) return;

  rawDataRead = (*env)->NewByteArray(env, 4096);
  bytes = (*env)->CallIntMethod(env, obj,readDataFunc, &rawDataRead);
  char* carr = (*env)->GetByteArrayElements(env, rawDataRead, NULL);
  memcpy(buffer, carr, bytes);
  (*env)->DeleteLocalRef(env, rawDataRead);
//<REMOVED REST OF FUNCTION>
}

我已经跟踪了bytes = (*env)->CallIntMethod(env, obj,readDataFunc, &rawDataRead);行的“麻烦”代码。如果我在此行之前返回,我的应用程序不会关闭,但如果我在此行之后立即返回,我的应用程序会随机关闭,甚至没有错误。

这是JAVA代码:

package teamjeff.oggstreamtest;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.os.Handler;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import com.Ostermiller.util.CircularByteBuffer;


public class MainTest extends Activity {

    public static Handler mHandler = new Handler();
    private final CircularByteBuffer cbb = new CircularByteBuffer(1024*512, true);
    public AudioTrack mAudioTrack;

    static {
        System.loadLibrary("vorbis-decoder");
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        try {

            final Socket test = new Socket(InetAddress.getByName(<HOME SERVER URL>), <PORT>);

            new Thread(
                    new Runnable(){
                      public void run(){
                          try {
                                 while(!test.isClosed()) {
                                     byte[] temp = new byte[4096];
                                     int bytes = test.getInputStream().read(temp, 0, 4096);
                                     cbb.getOutputStream().write(temp, 0, bytes);
                                 }
                              } catch (Exception e) {
                                  e.printStackTrace();
                              }
                      }
                    }
                  ).start();


            mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                    44100,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    1024*64,
                    AudioTrack.MODE_STREAM);
            mAudioTrack.play();

            new Thread(new Runnable() {
                public void run() {
                    audioFunc();
                }
            }).start();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public native void audioFunc();

    @SuppressWarnings("unused")
    private void writeToAudioTrack(final byte[] media) {
        mHandler.post(new Runnable() {
            public void run() {
                mAudioTrack.write(media, 0, media.length);
            }
        });
    }

    @SuppressWarnings("unused")
    private int readFromBuffer(byte[] buffer) {
        try {
            return cbb.getInputStream().read(buffer, 0, buffer.length);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return -1;
    }

}

我已经在这里和谷歌搜索了如何完成我想要做的事情。我上面的代码是将我在互联网上发现的各种代码片段粘合在一起,调整以适应我的用例。

我正在努力实现的目标:

我将从Android应用程序中的套接字读取数据,将此数据传递给我的C代码进行解码(尽管算法在算法期间逐个读取它,这意味着我无法从Java传递byteArray到C并多次调用我的C函数,因为解码器有时使用来自先前读入字节的数据)。我的C代码执行解码,并将PCM数据传递回我的Android应用程序以在AudioTrack上播放。

我正在使用循环缓冲区缓冲来自套接字的数据。

当我尝试调试我的Android应用程序时,我在读取和写入功能的条目中设置了断点,并且它们似乎永远不会被调用。

当我从我的C代码传递byteArray到JAVA以填充数据时,我做错了什么?我应该这样做吗?

1 个答案:

答案 0 :(得分:1)

一些可能有用的说明。

  1. &amp; rawDataRead错了。失去&amp ;.你只需传递你得到的参考号,而不是它的地址。

  2. 您无需删除该本地参考。当本机函数返回时,将删除所有本地引用。我相信这在 java 中是正确的,但是android情况可能会有所不同。

  3. 您不必继续检索方法ID。你可以把它们拿到一次并挂在它们上面。