Commit e50fad5f authored by Thomas Guillem's avatar Thomas Guillem

libvlcjni: simplify/improve the attachment of a thread to the Java VM

There is now only one way to get a JNIEnv: jni_get_env. This function use the
thread-specific data (TSD) areas to save a JNIEnv into a TSD key. The thread
will be automatically detached to the Java VM when it's canceled or exited.
parent abb34b9c
......@@ -29,9 +29,7 @@
#include "log.h"
#define THREAD_NAME "JavaEventThread"
extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
extern void jni_detach_thread();
extern int jni_get_env(JNIEnv **env);
extern JNIEnv *jni_get_env(const char *name);
typedef struct event_queue_elm event_queue_elm;
struct event_queue_elm
......@@ -60,7 +58,7 @@ JavaEventThread_thread(void *data)
java_event_thread *p_java_event_thread = data;
if (jni_attach_thread(&env, THREAD_NAME) < 0)
if (!(env = jni_get_env(THREAD_NAME)))
{
pthread_mutex_lock(&p_java_event_thread->lock);
goto end;
......@@ -112,9 +110,6 @@ end:
}
pthread_mutex_unlock(&p_java_event_thread->lock);
if (env)
jni_detach_thread();
return NULL;
}
......
......@@ -31,11 +31,6 @@
#define LOG_TAG "VLC/JNI/Util"
#include "log.h"
#define THREAD_NAME "libvlcjni-util"
extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
extern void jni_detach_thread();
extern int jni_get_env(JNIEnv **env);
jint getInt(JNIEnv *env, jobject thiz, const char* field) {
jclass clazz = (*env)->GetObjectClass(env, thiz);
jfieldID fieldMP = (*env)->GetFieldID(env, clazz,
......
......@@ -55,9 +55,7 @@ struct fields fields;
#define VLC_JNI_VERSION JNI_VERSION_1_2
#define THREAD_NAME "libvlcjni"
int jni_attach_thread(JNIEnv **env, const char *thread_name);
void jni_detach_thread();
int jni_get_env(JNIEnv **env);
JNIEnv *jni_get_env(const char *name);
static void add_media_options(libvlc_media_t *p_md, JNIEnv *env, jobjectArray mediaOptions)
{
......@@ -117,28 +115,17 @@ static void releaseMediaPlayer(JNIEnv *env, jobject thiz)
}
}
/* Pointer to the Java virtual machine
* Note: It's okay to use a static variable for the VM pointer since there
* can only be one instance of this shared library in a single VM
*/
static JavaVM *myVm;
static jobject eventHandlerInstance = NULL;
static void vlc_event_callback(const libvlc_event_t *ev, void *data)
{
JNIEnv *env;
bool isAttached = false;
if (eventHandlerInstance == NULL)
return;
if (jni_get_env(&env) < 0) {
if (jni_attach_thread(&env, THREAD_NAME) < 0)
return;
isAttached = true;
}
if (!(env = jni_get_env(THREAD_NAME)))
return;
/* Creating the bundle in C allows us to subscribe to more events
* and get better flexibility for each event. For example, we can
......@@ -216,8 +203,55 @@ static void vlc_event_callback(const libvlc_event_t *ev, void *data)
end:
(*env)->DeleteLocalRef(env, bundle);
if (isAttached)
jni_detach_thread();
}
/* Pointer to the Java virtual machine
* Note: It's okay to use a static variable for the VM pointer since there
* can only be one instance of this shared library in a single VM
*/
static JavaVM *myVm;
static pthread_key_t jni_env_key;
/* This function is called when a thread attached to the Java VM is canceled or
* exited */
static void jni_detach_thread(void *data)
{
//JNIEnv *env = data;
(*myVm)->DetachCurrentThread(myVm);
}
JNIEnv *jni_get_env(const char *name)
{
JNIEnv *env;
env = pthread_getspecific(jni_env_key);
if (env == NULL) {
/* if GetEnv returns JNI_OK, the thread is already attached to the
* JavaVM, so we are already in a java thread, and we don't have to
* setup any destroy callbacks */
if ((*myVm)->GetEnv(myVm, (void **)&env, VLC_JNI_VERSION) != JNI_OK)
{
/* attach the thread to the Java VM */
JavaVMAttachArgs args;
jint result;
args.version = VLC_JNI_VERSION;
args.name = name;
args.group = NULL;
if ((*myVm)->AttachCurrentThread(myVm, &env, &args) != JNI_OK)
return NULL;
/* Set the attached env to the thread-specific data area (TSD) */
if (pthread_setspecific(jni_env_key, env) != 0)
{
(*myVm)->DetachCurrentThread(myVm);
return NULL;
}
}
}
return env;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved)
......@@ -228,9 +262,16 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved)
if ((*vm)->GetEnv(vm, (void**) &env, VLC_JNI_VERSION) != JNI_OK)
return -1;
/* Create a TSD area and setup a destroy callback when a thread that
* previously set the jni_env_key is canceled or exited */
if (pthread_key_create(&jni_env_key, jni_detach_thread) != 0)
return -1;
pthread_mutex_init(&vout_android_lock, NULL);
pthread_cond_init(&vout_android_surf_attached, NULL);
#define GET_CLASS(clazz, str, b_globlal) do { \
(clazz) = (*env)->FindClass(env, (str)); \
if (!(clazz)) { \
......@@ -356,29 +397,8 @@ void JNI_OnUnload(JavaVM* vm, void* reserved)
(*env)->DeleteGlobalRef(env, fields.String.clazz);
(*env)->DeleteGlobalRef(env, fields.VLCObject.clazz);
(*env)->DeleteGlobalRef(env, fields.Media.clazz);
}
int jni_attach_thread(JNIEnv **env, const char *thread_name)
{
JavaVMAttachArgs args;
jint result;
args.version = VLC_JNI_VERSION;
args.name = thread_name;
args.group = NULL;
result = (*myVm)->AttachCurrentThread(myVm, env, &args);
return result == JNI_OK ? 0 : -1;
}
void jni_detach_thread()
{
(*myVm)->DetachCurrentThread(myVm);
}
int jni_get_env(JNIEnv **env)
{
return (*myVm)->GetEnv(myVm, (void **)env, VLC_JNI_VERSION) == JNI_OK ? 0 : -1;
pthread_key_delete(jni_env_key);
}
void Java_org_videolan_libvlc_LibVLC_nativeInit(JNIEnv *env, jobject thiz)
......@@ -908,10 +928,10 @@ int jni_GetWindowSize(int *width, int *height)
int aout_get_native_sample_rate(void)
{
JNIEnv *p_env;
jni_attach_thread (&p_env, THREAD_NAME);
if (!(p_env = jni_get_env(THREAD_NAME)))
return -1;
jclass cls = (*p_env)->FindClass (p_env, "android/media/AudioTrack");
jmethodID method = (*p_env)->GetStaticMethodID (p_env, cls, "getNativeOutputSampleRate", "(I)I");
int sample_rate = (*p_env)->CallStaticIntMethod (p_env, cls, method, 3); // AudioManager.STREAM_MUSIC
jni_detach_thread ();
return sample_rate;
}
......@@ -27,9 +27,7 @@
static struct sigaction old_actions[NSIG];
#define THREAD_NAME "native_crash_handler"
extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
extern void jni_detach_thread();
extern int jni_get_env(JNIEnv **env);
extern JNIEnv *jni_get_env(const char *name);
// Monitored signals.
static const int monitored_signals[] = {
......@@ -53,13 +51,8 @@ static const int monitored_signals[] = {
void sigaction_callback(int signal, siginfo_t *info, void *reserved)
{
JNIEnv *env;
bool b_attached = false;
if (jni_get_env(&env) < 0) {
if (jni_attach_thread(&env, THREAD_NAME) < 0)
return;
b_attached = true;
}
if (!(env = jni_get_env(THREAD_NAME)))
return;
// Call the Java LibVLC method that handle the crash.
(*env)->CallStaticVoidMethod(env, fields.LibVLC.clazz,
......@@ -67,8 +60,6 @@ void sigaction_callback(int signal, siginfo_t *info, void *reserved)
// Call the old signal handler.
old_actions[signal].sa_handler(signal);
if (b_attached)
jni_detach_thread();
}
......
......@@ -24,9 +24,7 @@
#include <jni.h>
#define THREAD_NAME "jni_vout"
extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
extern void jni_detach_thread();
extern int jni_get_env(JNIEnv **env);
extern JNIEnv *jni_get_env(const char *name);
pthread_mutex_t vout_android_lock;
pthread_cond_t vout_android_surf_attached;
......@@ -56,7 +54,9 @@ void jni_UnlockAndroidSurface() {
void jni_EventHardwareAccelerationError()
{
JNIEnv *env;
bool isAttached = false;
if (!(env = jni_get_env(THREAD_NAME)))
return;
pthread_mutex_lock(&vout_android_lock);
if (vout_android_gui == NULL) {
......@@ -64,21 +64,11 @@ void jni_EventHardwareAccelerationError()
return;
}
if (jni_get_env(&env) < 0) {
if (jni_attach_thread(&env, THREAD_NAME) < 0) {
pthread_mutex_unlock(&vout_android_lock);
return;
}
isAttached = true;
}
jclass cls = (*env)->GetObjectClass(env, vout_android_gui);
jmethodID methodId = (*env)->GetMethodID(env, cls, "eventHardwareAccelerationError", "()V");
(*env)->CallVoidMethod(env, vout_android_gui, methodId);
(*env)->DeleteLocalRef(env, cls);
if (isAttached)
jni_detach_thread();
pthread_mutex_unlock(&vout_android_lock);
}
......@@ -102,17 +92,11 @@ static void jni_SetSurfaceLayoutEnv(JNIEnv *p_env, int width, int height, int vi
void jni_SetSurfaceLayout(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
{
JNIEnv *p_env;
bool isAttached = false;
if (jni_get_env(&p_env) < 0) {
if (jni_attach_thread(&p_env, THREAD_NAME) < 0)
return;
isAttached = true;
}
jni_SetSurfaceLayoutEnv(p_env, width, height, visible_width, visible_height, sar_num, sar_den);
if (!(p_env = jni_get_env(THREAD_NAME)))
return;
if (isAttached)
jni_detach_thread();
jni_SetSurfaceLayoutEnv(p_env, width, height, visible_width, visible_height, sar_num, sar_den);
}
void *jni_AndroidJavaSurfaceToNativeSurface(jobject surf)
......@@ -121,13 +105,10 @@ void *jni_AndroidJavaSurfaceToNativeSurface(jobject surf)
jclass clz;
jfieldID fid;
void *native_surface = NULL;
bool isAttached = false;
if (jni_get_env(&p_env) < 0) {
if (jni_attach_thread(&p_env, THREAD_NAME) < 0)
return NULL;
isAttached = true;
}
if (!(p_env = jni_get_env(THREAD_NAME)))
return NULL;
clz = (*p_env)->GetObjectClass(p_env, surf);
fid = (*p_env)->GetFieldID(p_env, clz, "mSurface", "I");
if (fid == NULL) {
......@@ -149,30 +130,23 @@ void *jni_AndroidJavaSurfaceToNativeSurface(jobject surf)
native_surface = (void*)(*p_env)->GetIntField(p_env, surf, fid);
(*p_env)->DeleteLocalRef(p_env, clz);
if (isAttached)
jni_detach_thread();
return native_surface;
}
int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *configured)
{
JNIEnv *p_env;
bool isAttached = false;
int ret;
if (!(p_env = jni_get_env(THREAD_NAME)))
return -1;
pthread_mutex_lock(&vout_android_lock);
if (vout_android_gui == NULL) {
pthread_mutex_unlock(&vout_android_lock);
return -1;
}
if (jni_get_env(&p_env) < 0) {
if (jni_attach_thread(&p_env, THREAD_NAME) < 0) {
pthread_mutex_unlock(&vout_android_lock);
return -1;
}
isAttached = true;
}
jclass clz = (*p_env)->GetObjectClass (p_env, vout_android_gui);
jmethodID methodId = (*p_env)->GetMethodID (p_env, clz, "configureSurface", "(Landroid/view/Surface;III)I");
ret = (*p_env)->CallIntMethod (p_env, vout_android_gui, methodId, jsurf, width, height, hal);
......@@ -181,8 +155,6 @@ int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *co
(*p_env)->DeleteLocalRef(p_env, clz);
if (isAttached)
jni_detach_thread();
pthread_mutex_unlock(&vout_android_lock);
return ret == -1 ? -1 : 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment