2010-04-01 117 views
4

我试图写从JNI回调的AudioTrack,我也得到一个信号7(SIGBUS),故障地址00000000如何从jni处理对AudioTrack的呼叫而不会崩溃?

我已经看了Wolf3D例如为odroid,他们似乎使用机器人。 os.Handler发布一个Runnable,它将在正确的线程上下文中进行更新。我也尝试过AttachCurrentThread,但在这种情况下我也失败了。

它可以在从构造函数运行时播放声音,即使我将它包装在线程中,然后将其发布到处理程序。当我通过jni的回调做“相同”时,它失败了。我假设我正在制定一些规则,但我一直无法弄清楚它们是什么。到目前为止,我还没有在SO上找到答案。

所以我想知道有没有人知道这应该怎么做。

编辑:下面回答。

以下代码是为了说明问题。

的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); 
} 

跟踪片断:

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 adcpsr 20000010 
I/DEBUG (1653):   #00 pc 00/system/lib/libdvm.so 
+0

您是否启用CheckJNI?它在默认情况下在模拟器中开启,但在设备上关闭。使用“adb shell setprop dalvik.vm.checkjni true”启用,然后使用“adb shell stop; adb shell start”重新启动框架。 (需要开发人员或根植设备。)CheckJNI将发现各种常见的JNI错误。 – fadden 2010-04-01 20:19:31

+0

我会试试这个。 – icecream 2010-04-06 06:05:11

回答

4

似乎一直是内存问题。使mAudioTrack和mArr静态解决它。 我正在向回调发送错误的对象。见fadden的评论。我已经删除了对AttachCurrentThread的调用,因为它在这种情况下没有任何区别。

的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); 
} 
+1

这应该是“env-> CallVoidMethod(obj,audioCBID)”。如果你的audioCB试图用“this”指针做任何事情,它将会失败。使它需要“静态”的数据避免了对“this”的解除引用。 (这可能是你的问题的根源;我刚刚第一时间通读它就会发现它太快) – fadden 2010-04-06 21:35:03

+0

是的,你是对的。谢谢。我将编辑答案。 – icecream 2010-04-07 06:06:53