我试图从jni回调中写入AudioTrack,但收到信号7(SIGBUS),错误地址00000000。
我已经看了看Wolf3D例如,对于odroid,他们似乎使用android.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 ad012358 cpsr 20000010
I/DEBUG ( 1653): #00 pc 00012358 /system/lib/libdvm.so
似乎出现了内存问题。
我向回调发送了错误的对象。请参阅fadden的评论。我已经删除了对AttachCurrentThread的调用,因为在这种情况下它没有任何区别。
使mAudioTrack和mArr静态可解决该问题。
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);
}
我在调用我的onLeScan时遇到问题。我在开始扫描中放置了一个标签,每次都会被调用。出于某种原因,我的onLeScan永远不会被调用。有人看到我所做的有问题吗?onLeScan应该在开始扫描后立即调用,对吗? 编辑更改了我的onLeScan函数。仍然不起作用,但我认为我正在走向正确的道路。DeviceBeacon是一个只包含方法的类:getName()、getSignal()和getAddres
我举了以下例子: 我为Profile类创建了复杂的模型管理器,并且我构建了一个视图来列出大量的人。我试图计算数据库中的所有内容,所以我想从PersonQuerySet调用配置文件管理器。 为此,我需要做如下工作: 然后我应该能够从SQL检索person.profile.computed_revenue,函数“with_computed_revenue”是注释computed_revenue的Pro
是否有一个gradle插件或任何其他方法调用hiberNate工具hbm2ddl任务来从注释的类生成数据库模式,而不必列出一些配置文件中的所有实体(@Entity),但在类路径中发现它们? 最好是针对Hibernate5,但Hibernate4也可以。
问题内容: 我有一个包含数百万行的文件,需要处理。文件的每一行都将导致HTTP调用。我正在尝试找出解决问题的最佳方法。 我显然可以读取文件并按顺序进行调用,但是速度会非常慢。我想并行化这些调用,但是不确定是否应该将整个文件读入内存(不是我的忠实拥护者)还是尝试并行化文件的读取(我想我不确定是否有道理)。 只是在这里寻找一些解决问题的最佳方法的想法。如果有一个类似的现有框架或库,我也很乐意使用它。
问题内容: 我需要从被叫方获取呼叫者信息(什么文件/什么行)。我了解到可以为此目的使用inpect模块,但不能完全使用它。 如何使用inspect获取那些信息?还是有其他方法来获取信息? 问题答案: 呼叫者的帧比当前帧高一帧。您可以用来查找呼叫者的框架。然后使用inspect.getframeinfo获取调用者的文件名和行号。