2010-04-01 2 views
4

은 내가 JNI 콜백에서 AudioTrack에 쓰기를 시도했다, 나는 신호 (7) (SIGBUS)를 얻을, 장애 요지 00000000충돌없이 jni에서 AudioTrack에 대한 호출을 처리하는 방법은 무엇입니까?

내가 odroid에 대한 Wolf3D의 예를 살펴 보았다 그리고 그들은 안드로이드를 사용하는 것 같다. os.Handler가 올바른 스레드 컨텍스트에서 업데이트를 수행하는 Runnable을 게시합니다. AttachCurrentThread도 시도했지만이 경우에도 실패합니다.

생성자에서 실행 중일 때 사운드를 재생하고 스레드에서 래핑하고 핸들러에 게시하더라도 작동합니다. jni에서 콜백을 통해 "동일"할 때 실패합니다. 나는 몇몇 규칙을 말하고 있다고 가정하지만, 나는 그들이 무엇인지 알아낼 수 없었다. 지금까지 나는 대답을 찾지 못했습니다.

이렇게 어떻게해야 하는지를 아는 사람이 있는지 궁금합니다.

편집 : 아래에서 답변.

다음 코드는 문제를 설명하기위한 것입니다.

자바 :

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

+0

나는 이것을 시험 할 것이다. – icecream

답변

4

메모리 문제가 있었던 것 같습니다. mAudioTrack과 mArr를 정적으로 만들면 해결됩니다. 콜백에 잘못된 객체를 보냈습니다. fadden 님의 댓글보기 이 경우에는 아무런 차이가 없으므로 AttachCurrentThread에 대한 호출을 제거했습니다.

자바 :

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

+0

네, 맞습니다. 감사. 나는 대답을 편집 할 것이다. – icecream

관련 문제