Don't use a global JNIEnv across threads; it's not thread safe.
Obtain the correct environment in a thread-safe way when appropriate instead. Fixes Bugzilla #1312. Thanks to Bill Chenbin for the patch!
This commit is contained in:
parent
84848501c0
commit
3f0781af54
1 changed files with 63 additions and 8 deletions
|
@ -29,6 +29,14 @@ extern "C" {
|
||||||
#include "../../video/android/SDL_androidtouch.h"
|
#include "../../video/android/SDL_androidtouch.h"
|
||||||
#include "../../video/android/SDL_androidvideo.h"
|
#include "../../video/android/SDL_androidvideo.h"
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
#define LOG_TAG "SDL_android"
|
||||||
|
//#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
|
||||||
|
//#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
||||||
|
#define LOGI(...) do {} while (false)
|
||||||
|
#define LOGE(...) do {} while (false)
|
||||||
|
|
||||||
|
|
||||||
/* Impelemented in audio/android/SDL_androidaudio.c */
|
/* Impelemented in audio/android/SDL_androidaudio.c */
|
||||||
extern void Android_RunAudioThread();
|
extern void Android_RunAudioThread();
|
||||||
} // C
|
} // C
|
||||||
|
@ -45,6 +53,7 @@ extern void Android_RunAudioThread();
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
static JNIEnv* mEnv = NULL;
|
static JNIEnv* mEnv = NULL;
|
||||||
static JNIEnv* mAudioEnv = NULL;
|
static JNIEnv* mAudioEnv = NULL;
|
||||||
|
static JavaVM* mJavaVM;
|
||||||
|
|
||||||
// Main activity
|
// Main activity
|
||||||
static jclass mActivityClass;
|
static jclass mActivityClass;
|
||||||
|
@ -68,6 +77,14 @@ static float fLastAccelerometer[3];
|
||||||
// Library init
|
// Library init
|
||||||
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||||
{
|
{
|
||||||
|
JNIEnv *env;
|
||||||
|
mJavaVM = vm;
|
||||||
|
LOGI("JNI_OnLoad called");
|
||||||
|
if (mJavaVM->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
|
||||||
|
LOGE("Failed to get the environment using GetEnv()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return JNI_VERSION_1_4;
|
return JNI_VERSION_1_4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +113,7 @@ extern "C" void SDL_Android_Init(JNIEnv* env, jclass cls)
|
||||||
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) {
|
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit) {
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
|
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
|
||||||
}
|
}
|
||||||
|
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize
|
// Resize
|
||||||
|
@ -204,30 +222,49 @@ extern "C" int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int chan
|
||||||
{
|
{
|
||||||
int audioBufferFrames;
|
int audioBufferFrames;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
JNIEnv *env;
|
||||||
|
static bool isAttached = false;
|
||||||
|
status = mJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4);
|
||||||
|
if(status < 0) {
|
||||||
|
LOGE("callback_handler: failed to get JNI environment, assuming native thread");
|
||||||
|
status = mJavaVM->AttachCurrentThread(&env, NULL);
|
||||||
|
if(status < 0) {
|
||||||
|
LOGE("callback_handler: failed to attach current thread");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
isAttached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
|
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
|
||||||
audioBuffer16Bit = is16Bit;
|
audioBuffer16Bit = is16Bit;
|
||||||
audioBufferStereo = channelCount > 1;
|
audioBufferStereo = channelCount > 1;
|
||||||
|
|
||||||
audioBuffer = mEnv->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames);
|
audioBuffer = env->CallStaticObjectMethod(mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames);
|
||||||
|
|
||||||
if (audioBuffer == NULL) {
|
if (audioBuffer == NULL) {
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!");
|
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: didn't get back a good audio buffer!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
audioBuffer = mEnv->NewGlobalRef(audioBuffer);
|
audioBuffer = env->NewGlobalRef(audioBuffer);
|
||||||
|
|
||||||
jboolean isCopy = JNI_FALSE;
|
jboolean isCopy = JNI_FALSE;
|
||||||
if (audioBuffer16Bit) {
|
if (audioBuffer16Bit) {
|
||||||
audioBufferPinned = mEnv->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
|
audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy);
|
||||||
audioBufferFrames = mEnv->GetArrayLength((jshortArray)audioBuffer);
|
audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer);
|
||||||
} else {
|
} else {
|
||||||
audioBufferPinned = mEnv->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy);
|
audioBufferPinned = env->GetByteArrayElements((jbyteArray)audioBuffer, &isCopy);
|
||||||
audioBufferFrames = mEnv->GetArrayLength((jbyteArray)audioBuffer);
|
audioBufferFrames = env->GetArrayLength((jbyteArray)audioBuffer);
|
||||||
}
|
}
|
||||||
if (audioBufferStereo) {
|
if (audioBufferStereo) {
|
||||||
audioBufferFrames /= 2;
|
audioBufferFrames /= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAttached) {
|
||||||
|
mJavaVM->DetachCurrentThread();
|
||||||
|
}
|
||||||
|
|
||||||
return audioBufferFrames;
|
return audioBufferFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,13 +288,31 @@ extern "C" void Android_JNI_WriteAudioBuffer()
|
||||||
|
|
||||||
extern "C" void Android_JNI_CloseAudioDevice()
|
extern "C" void Android_JNI_CloseAudioDevice()
|
||||||
{
|
{
|
||||||
mEnv->CallStaticVoidMethod(mActivityClass, midAudioQuit);
|
int status;
|
||||||
|
JNIEnv *env;
|
||||||
|
static bool isAttached = false;
|
||||||
|
status = mJavaVM->GetEnv((void **) &env, JNI_VERSION_1_4);
|
||||||
|
if(status < 0) {
|
||||||
|
LOGE("callback_handler: failed to get JNI environment, assuming native thread");
|
||||||
|
status = mJavaVM->AttachCurrentThread(&env, NULL);
|
||||||
|
if(status < 0) {
|
||||||
|
LOGE("callback_handler: failed to attach current thread");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isAttached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->CallStaticVoidMethod(mActivityClass, midAudioQuit);
|
||||||
|
|
||||||
if (audioBuffer) {
|
if (audioBuffer) {
|
||||||
mEnv->DeleteGlobalRef(audioBuffer);
|
env->DeleteGlobalRef(audioBuffer);
|
||||||
audioBuffer = NULL;
|
audioBuffer = NULL;
|
||||||
audioBufferPinned = NULL;
|
audioBufferPinned = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAttached) {
|
||||||
|
mJavaVM->DetachCurrentThread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for an exception and call SDL_SetError with its detail if one occurs
|
// Test for an exception and call SDL_SetError with its detail if one occurs
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue