代码之家  ›  专栏  ›  技术社区  ›  icecream

如何在不崩溃的情况下处理JNI对AudioTrack的调用?

  •  4
  • icecream  · 技术社区  · 16 年前

    我试图从JNI回调写入音频曲目,得到一个信号7(sigbus),fault addr 00000000。

    我看过wolf3d的例子 odroid 他们似乎使用android.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 ad012358  cpsr 20000010
    I/DEBUG   ( 1653):          #00  pc 00012358  /system/lib/libdvm.so
    
    1 回复  |  直到 14 年前
        1
  •  4
  •   icecream    16 年前

    好像有记忆问题。maudiotrack和marr static解决了这个问题。 我把错误的对象发送到回调。见法登评论。我已经删除了对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);
    }
    
    推荐文章