我在 Android 应用程序中使用 fmod 库来过滤声音。 GP 控制台发生崩溃,我无法在我的设备上重现它。这是回溯:
JNI DETECTED ERROR IN APPLICATION: java_object == null
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
backtrace:
#00 pc 0x000000000005c444 /apex/com.android.runtime/lib64/bionic/libc.so (abort+180)
#01 pc 0x000000000093091c /apex/com.android.art/lib64/libart.so (art::Runtime::Abort(char const*)+344)
#02 pc 0x00000000000160fc /apex/com.android.art/lib64/libbase.so (android::base::SetAborter(std::__1::function<void (char const*)>&&)::$_0::__invoke(char const*)+80)
#03 pc 0x00000000000156d0 /apex/com.android.art/lib64/libbase.so (android::base::LogMessage::~LogMessage()+516)
#04 pc 0x0000000000442390 /apex/com.android.art/lib64/libart.so (art::JavaVMExt::JniAbort(char const*, char const*)+1696)
#05 pc 0x0000000000525278 /apex/com.android.art/lib64/libart.so (art::JNI<false>::GetObjectClass(_JNIEnv*, _jobject*)+468)
#06 pc 0x0000000000005188 /data/app/~~Z_IFePTytjAkWkrXxToe1w==/com.my.app.package-y8HMT5XoWD5wlTXbflg7-A==/split_config.arm64_v8a.apk!libexample.so (Common_GetPropertyValue(int)+136) (BuildId: 7264cb4aa1e9a168b62455f5db85b4cf6e74945c)
#07 pc 0x000000000000623c /data/app/~~Z_IFePTytjAkWkrXxToe1w==/com.my.app.package-y8HMT5XoWD5wlTXbflg7-A==/split_config.arm64_v8a.apk!libexample.so (FMOD_LivePreview(char const*, float)+728) (BuildId: 7264cb4aa1e9a168b62455f5db85b4cf6e74945c)
#08 pc 0x0000000000005470 /data/app/~~Z_IFePTytjAkWkrXxToe1w==/com.my.app.package-y8HMT5XoWD5wlTXbflg7-A==/split_config.arm64_v8a.apk!libexample.so (Java_com_my_package_activitySound_SoundJavaActivity_fmodStartPlay+164) (BuildId: 7264cb4aa1e9a168b62455f5db85b4cf6e74945c)
#09 pc 0x000000000037412c /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (art_jni_trampoline+124)
#10 pc 0x0000000000780780 /apex/com.android.art/lib64/libart.so (nterp_helper+5648)
#11 pc 0x00000000003e3282 /data/app/~~Z_IFePTytjAkWkrXxToe1w==/com.my.app.package-y8HMT5XoWD5wlTXbflg7-A==/base.apk (com.my.package.activitySound.SoundJavaActivity.lambda$playSound$7+18)
#12 pc 0x00000000007800c4 /apex/com.android.art/lib64/libart.so (nterp_helper+3924)
#13 pc 0x00000000003e2ef0 /data/app/~~Z_IFePTytjAkWkrXxToe1w==/com.my.app.package-y8HMT5XoWD5wlTXbflg7-A==/base.apk (com.my.package.activitySound.SoundJavaActivity.$r8$lambda$AaHEezBg_mfaszt4Iimkszl0fc4)
#14 pc 0x000000000077f1a4 /apex/com.android.art/lib64/libart.so (nterp_helper+52)
#15 pc 0x00000000003e28c8 /data/app/~~Z_IFePTytjAkWkrXxToe1w==/com.my.app.package-y8HMT5XoWD5wlTXbflg7-A==/base.apk (com.my.package.activitySound.SoundJavaActivity$$ExternalSyntheticLambda2.run+4)
#16 pc 0x00000000005f49a4 /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+724)
#17 pc 0x00000000005f22d8 /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+56)
#18 pc 0x00000000004ccc50 /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (java.lang.Thread.run+64)
#19 pc 0x000000000036d574 /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612)
#20 pc 0x0000000000358bc0 /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+132)
#21 pc 0x0000000000944608 /apex/com.android.art/lib64/libart.so (art::detail::ShortyTraits<(char)86>::Type art::ArtMethod::InvokeInstance<(char)86>(art::Thread*, art::ObjPtr<art::mirror::Object>, art::detail::ShortyTraits<>::Type...)+60)
#22 pc 0x0000000000625d24 /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+1344)
#23 pc 0x00000000006257d4 /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallbackWithUffdGc(void*)+8)
#24 pc 0x00000000000c9fb0 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+208)
#25 pc 0x000000000005dd90 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
方法如下:
// Global JavaVM pointer
JavaVM *gJvm = nullptr;
jobject gMainActivityObject = nullptr;
void
Java_com_baby_hearth_monitor_activityEdit_EditJavaActivity_fmodStartPlay(JNIEnv *env, jobject thiz,
jstring index, jfloat f) {
// Log
soundShouldStop = false;
if (gMainActivityObject) {
printf("Deleting old global reference for gMainActivityObject\n");
env->DeleteGlobalRef(gMainActivityObject);
}
gMainActivityObject = env->NewGlobalRef(thiz);
printf("gMainActivityObject set with a new global reference\n");
const char *nativeString = env->GetStringUTFChars(index, nullptr);
FMOD_LivePreview(nativeString, f);
env->ReleaseStringUTFChars(index, nativeString);
}
int FMOD_LivePreview(const char *fileName, float f) {
FMOD::System *system = 0;
FMOD::Sound *sound = 0;
FMOD::Channel *channel = 0;
FMOD::ChannelGroup *mastergroup = 0;
FMOD::DSP *dsplowpass = 0;
FMOD::DSP *dsppitch = 0;
FMOD::DSP *dspnormalize = 0;
unsigned int version;
void *extradriverdata = 0;
unsigned int currentPosition = 0;
unsigned int startFrom = 0;
unsigned int endsTo = 0;
unsigned int lenms = 0;
Common_Init(&extradriverdata);
/*
Create a System object and initialize
*/
result = FMOD::System_Create(&system);
ERRCHECK(result);
result = system->getVersion(&version);
ERRCHECK(result);
if (version < FMOD_VERSION) {
Common_Fatal("FMOD lib version %08x doesn't match header version %08x", version,
FMOD_VERSION);
}
result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
ERRCHECK(result);
result = system->getMasterChannelGroup(&mastergroup);
ERRCHECK(result);
result = system->createSound(Common_MediaPath(fileName), FMOD_DEFAULT, 0, &sound);
ERRCHECK(result);
/*
Create some effects to play with
*/
result = system->createDSPByType(FMOD_DSP_TYPE_LOWPASS, &dsplowpass);
ERRCHECK(result);
result = system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsppitch);
ERRCHECK(result);
result = system->createDSPByType(FMOD_DSP_TYPE_NORMALIZE, &dspnormalize);
ERRCHECK(result);
/*
Add them to the master channel group. Each time an effect is added (to position 0) it pushes the others down the list.
*/
result = mastergroup->addDSP(0, dsplowpass);
ERRCHECK(result);
result = mastergroup->addDSP(0, dsppitch);
ERRCHECK(result);
result = mastergroup->addDSP(0, dspnormalize);
ERRCHECK(result);
/*
By default, bypass all effects. This means let the original signal go through without processing.
It will sound 'dry' until effects are enabled by the user.
*/
result = dsplowpass->setBypass(true);
ERRCHECK(result);
result = dsppitch->setBypass(true);
ERRCHECK(result);
result = dspnormalize->setBypass(true);
ERRCHECK(result);
/*
Main loop
*/
bool soundStarted = false;
Common_ShouldPlay();
do {
if (!soundStarted) {
channel->stop();
sound->setDefaults(f, 0);
}
channel->setLoopCount(10000);
channel->setMode(FMOD_LOOP_NORMAL);
channel->setFrequency(f);
float pitch = Common_GetPropertyValue(0);
float cutoff = Common_GetPropertyValue(1);
float maxAmp = Common_GetPropertyValue(2);
float threshold = Common_GetPropertyValue(3);
dsppitch->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, pitch);
dsppitch->setBypass(false);
dsplowpass->setParameterFloat(FMOD_DSP_LOWPASS_CUTOFF, cutoff);
dsplowpass->setBypass(false);
dspnormalize->setParameterFloat(FMOD_DSP_NORMALIZE_MAXAMP, maxAmp);
dspnormalize->setBypass(false);
dspnormalize->setParameterFloat(FMOD_DSP_NORMALIZE_THRESHOLD, threshold);
dspnormalize->setBypass(false);
if (!soundStarted) {
soundStarted = true;
system->playSound(sound, 0, false, &channel);
sound->getLength(&lenms, FMOD_TIMEUNIT_MS);
Common_SoundStarted(lenms);
}
result = system->update();
sound->getLength(&lenms, FMOD_TIMEUNIT_MS);
startFrom = 0.0; // lenms * Common_GetStartPosition();
endsTo = lenms; // * Common_GetEndPosition();
channel->getPosition(¤tPosition, FMOD_TIMEUNIT_MS);
if (currentPosition > 0) {
if (currentPosition <= startFrom) {
currentPosition = startFrom;
result = channel->setPosition(currentPosition, FMOD_TIMEUNIT_MS);
ERRCHECK(result);
}
if (currentPosition >= endsTo) {
channel->setPosition(startFrom, FMOD_TIMEUNIT_MS);
currentPosition = startFrom;
if (!Common_SoundLoopActive()) {
Common_Stop();
}
}
}
bool isPlaying;
channel->isPlaying(&isPlaying);
if (!isPlaying) {
Common_Stop();
}
Common_UpdateCurrentTime(float(currentPosition) / float(lenms));
Common_Sleep(1);
} while (!Common_SoundShouldStop());
/*
Shut down
*/
Common_SoundStoped();
result = mastergroup->removeDSP(dsplowpass);
ERRCHECK(result);
result = mastergroup->removeDSP(dsppitch);
ERRCHECK(result);
result = mastergroup->removeDSP(dspnormalize);
ERRCHECK(result);
result = dsplowpass->release();
ERRCHECK(result);
result = dsppitch->release();
ERRCHECK(result);
result = dspnormalize->release();
ERRCHECK(result);
result = sound->release();
ERRCHECK(result);
result = system->close();
ERRCHECK(result);
result = system->release();
ERRCHECK(result);
Common_Close();
return 0;
}
float Common_GetPropertyValue(int propertyIndex) {
JNIEnv *gJNIEnv = getJNIEnv();
jclass mainActivityClass = gJNIEnv->GetObjectClass(gMainActivityObject);
gJNIEnv = getJNIEnv(); // Ensure valid JNIEnv
float defaultValue = 1.0f;
if (!gJNIEnv || !gMainActivityObject) {
printf("JNI ERROR: Invalid JNIEnv or gMainActivityObject\n");
return defaultValue; // Default value if invalid
}
if (!mainActivityClass) {
printf("JNI ERROR: Failed to get class from gMainActivityObject\n");
if (gJNIEnv->ExceptionCheck()) {
gJNIEnv->ExceptionDescribe();
gJNIEnv->ExceptionClear();
}
return defaultValue; // Default value if invalid
}
jmethodID methodID = gJNIEnv->GetMethodID(mainActivityClass, "fmodGetPropertyValue", "(I)F");
if (!methodID) {
printf("JNI ERROR: Failed to get method ID for fmodGetPropertyValue\n");
gJNIEnv->DeleteLocalRef(mainActivityClass);
return defaultValue; // Default value if method not found
}
float result = gJNIEnv->CallFloatMethod(gMainActivityObject, methodID, propertyIndex);
if (gJNIEnv->ExceptionCheck()) {
gJNIEnv->ExceptionDescribe();
gJNIEnv->ExceptionClear();
result = defaultValue; // Default value if exception occurs
}
gJNIEnv->DeleteLocalRef(mainActivityClass);
return result;
}
堆栈跟踪再清楚不过了:
gMainActivityObject
是null
,但无论如何你都在调用GetObjectClass。将该调用移至 if (!gMainActivityObject)
复选框下。