¿Cómo puedo manejar las llamadas a AudioTrack de jni sin estrellarse?

Estaba tratando de escribir a un AudioTrack desde una devolución de llamada jni, y obtengo una señal 7 (SIGBUS), error addr 00000000.

He mirado el ejemplo de Wolf3D para odroid y parecen usar un android.os.Handler para publicar un Runnable que hará una actualización en el contexto de hilo correcto. También he intentado AttachCurrentThread, pero fallo en este caso también.

Funciona para reproducir el sonido cuando se ejecuta desde el constructor, incluso si lo envuelvo en un hilo y luego lo publica en el controlador. Cuando hago el "mismo" vía una devolución de llamada de jni falla. Supongo que estoy guardando algunas reglas, pero no he sido capaz de averiguar lo que son. Hasta ahora, no he encontrado la respuesta aquí en SO.

Así que me pregunto si alguien sabe cómo se debe hacer esto.

EDIT: Se responde a continuación.

El siguiente código es para ilustrar el problema.

Java:

package com.example.jniaudiotrack; 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 android.util.Log; public class JniAudioTrackActivity extends Activity { AudioTrack mAudioTrack; byte[] mArr; public static final Handler mHandler = new Handler(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mArr = new byte[2048]; for (int i = 0; i < 2048; i++) { mArr[i] = (byte) (Math.sin(i) * 128); } mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT, 2048, AudioTrack.MODE_STREAM); mAudioTrack.play(); new Thread(new Runnable() { public void run() { mHandler.post(new Runnable() { public void run() { mAudioTrack.write(mArr, 0, 2048); Log.i(TAG, "*** Handler from constructor ***"); } }); } }).start(); new Thread(new Runnable() { public void run() { audioFunc(); } }).start(); } public native void audioFunc(); @SuppressWarnings("unused") private void audioCB() { mHandler.post(new Runnable() { public void run() { mAudioTrack.write(mArr, 0, 2048); Log.i(TAG, "*** audioCB called ***"); } }); } private static final String TAG = "JniAudioTrackActivity"; static { System.loadLibrary("jni_audiotrack"); } } 

Cpp:

 #include <jni.h> extern "C" { JNIEXPORT void Java_com_example_jniaudiotrack_JniAudioTrackActivity_audioFunc(JNIEnv* env, jobject obj); } JNIEXPORT void Java_com_example_jniaudiotrack_JniAudioTrackActivity_audioFunc(JNIEnv* env, jobject obj) { JNIEnv* jniEnv; JavaVM* vm; env->GetJavaVM(&vm); vm->AttachCurrentThread(&jniEnv, 0); jclass cls = env->GetObjectClass(obj); jmethodID audioCBID = env->GetMethodID(cls, "audioCB", "()V"); if (!audioCBID) { return; } env->CallVoidMethod(cls, audioCBID); } 

Trazar un fragmento:

 I/DEBUG ( 1653): pid: 9811, tid: 9811 >>> com.example.jniaudiotrack <<< I/DEBUG ( 1653): signal 7 (SIGBUS), fault addr 00000000 I/DEBUG ( 1653): r0 00000800 r1 00000026 r2 00000001 r3 00000000 I/DEBUG ( 1653): r4 42385726 r5 41049e54 r6 bee25570 r7 ad00e540 I/DEBUG ( 1653): r8 000040f8 r9 41048200 10 41049e44 fp 00000000 I/DEBUG ( 1653): ip 000000f8 sp bee25530 lr ad02dbb5 pc ad012358 cpsr 20000010 I/DEBUG ( 1653): #00 pc 00012358 /system/lib/libdvm.so 

One Solution collect form web for “¿Cómo puedo manejar las llamadas a AudioTrack de jni sin estrellarse?”

Parece haber habido un problema de memoria. Hacer mAudioTrack y mArr static lo resolvió. Yo estaba enviando el objeto equivocado a la devolución de llamada. Ver comentario de fadden. He eliminado la llamada a AttachCurrentThread ya que no hizo ninguna diferencia en este caso.

Java:

 package com.example.jniaudiotrack; 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 android.util.Log; public class JniAudioTrackActivity extends Activity { public AudioTrack mAudioTrack; public byte[] mArr; public static Handler mHandler = new Handler(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mArr = new byte[2048]; for (int i = 0; i < 2048; i++) { mArr[i] = (byte) (Math.sin(i) * 128); } mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 11025, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_8BIT, 2048, AudioTrack.MODE_STREAM); mAudioTrack.play(); new Thread(new Runnable() { public void run() { audioFunc(); } }).start(); } public native void audioFunc(); @SuppressWarnings("unused") private void audioCB() { mHandler.post(new Runnable() { public void run() { mAudioTrack.write(mArr, 0, 2048); Log.i(TAG, "*** audioCB called ***"); } }); } private static final String TAG = "JniAudioTrackActivity"; static { System.loadLibrary("jni_audiotrack"); } } 

Cpp:

 #include <jni.h> extern "C" { JNIEXPORT void Java_com_example_jniaudiotrack_JniAudioTrackActivity_audioFunc(JNIEnv* env, jobject obj); } JNIEXPORT void Java_com_example_jniaudiotrack_JniAudioTrackActivity_audioFunc(JNIEnv* env, jobject obj) { jclass cls = env->GetObjectClass(obj); jmethodID audioCBID = env->GetMethodID(cls, "audioCB", "()V"); if (!audioCBID) { return; } env->CallVoidMethod(obj, audioCBID); } 
  • Generación de archivos .so en Android Studio 1.0.2 con NDK
  • ¿Cómo obtengo el búfer de la cámara Android en bruto en C con JNI?
  • JNI_OnLoad devolvió la versión incorrecta (-1)
  • Llamar a un objeto java guardado a través de JNI desde un hilo diferente
  • UnityPlayerActivity no recibe registro onCreate ()
  • OpenCV 2.4.1: UnsatisfiedLinkError
  • Cómo depurar código nativo en un proyecto de biblioteca de Android?
  • Acceda al objeto JNI a la capa de Java como puntero de referencia
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.