JNI byteArray прохождение справки - PullRequest
1 голос
/ 09 апреля 2011

У меня возникли проблемы с закрытием приложения для 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;
    }

}

Я искал несколько дней здесь и в Google, как выполнить то, что я хочу сделать. Мой код выше - это склейка различных фрагментов кода, которые я нашел в интернете, с настройками, подходящими для моего варианта использования.

Что я пытаюсь сделать:

Я прочитаю данные из сокета в моем приложении для Android, передам эти данные в мой код C для декодирования (хотя алгоритм читает их по частям во время выполнения алгоритма, то есть я не могу передать byteArray из Java на C и вызываю мою функцию C несколько раз, так как декодер иногда использует данные из предыдущих байтов чтения). Мой код C выполняет декодирование и передает данные PCM обратно в мое приложение Android для воспроизведения на AudioTrack.

Я использую кольцевой буфер для буферизации данных из сокета.

Когда я пытаюсь отладить свое Android-приложение, я устанавливаю точки останова на входах для функций чтения и записи, и они, кажется, никогда не вызываются.

Что-то не так, когда я передаю byteArray из моего C-кода в JAVA для заполнения данными? Должен ли я сделать это альтернативным способом?

1 Ответ

1 голос
/ 10 апреля 2011

Несколько замечаний, которые могут помочь.

  1. & rawDataRead неверно. Потерять &. Вы просто передаете полученный реф, а не его адрес.

  2. вам не нужно удалять этот локальный реф. Все локальные ссылки удаляются, когда возвращается нативная функция. Я вполне уверен, что это верно в Java , но ситуация с Android может быть другой.

  3. Вам не нужно постоянно получать идентификаторы методов. Вы можете получить их один раз и повесить на них.

...