From 46fe3cded03a0505ad92830a5de7a98f1c5a592d Mon Sep 17 00:00:00 2001 From: davince Date: Tue, 29 Oct 2024 20:22:39 +0800 Subject: [PATCH] ao_audiotrack: make audiotrack jni multi-instance and multi-thread safe The detailed issue is here: #15212 problem: Since The AudioTrack is not an mpv instance level but a global object, it cannot support multiple mpv instances at the same time. For example, if you create two instances and then destroy one of them, the other instance may crash. Add jni usage count to fix this. --- audio/out/ao_audiotrack.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/audio/out/ao_audiotrack.c b/audio/out/ao_audiotrack.c index 940bffbec9..8068a09f9d 100644 --- a/audio/out/ao_audiotrack.c +++ b/audio/out/ao_audiotrack.c @@ -30,6 +30,9 @@ #include "osdep/timer.h" #include "misc/jni.h" +static mp_static_mutex jni_static_lock = MP_STATIC_MUTEX_INITIALIZER; +static int jni_static_use_count = 0; + struct priv { jobject audiotrack; jint samplerate; @@ -524,26 +527,40 @@ static int AudioTrack_write(struct ao *ao, int len) static void uninit_jni(struct ao *ao) { - JNIEnv *env = MP_JNI_GET_ENV(ao); - for (int i = 0; i < MP_ARRAY_SIZE(jclass_list); i++) { - mp_jni_reset_jfields(env, jclass_list[i].fields, - jclass_list[i].mapping, 1, ao->log); + mp_mutex_lock(&jni_static_lock); + jni_static_use_count--; + if (jni_static_use_count == 0) { + JNIEnv *env = MP_JNI_GET_ENV(ao); + for (int i = 0; i < MP_ARRAY_SIZE(jclass_list); i++) { + mp_jni_reset_jfields(env, jclass_list[i].fields, + jclass_list[i].mapping, 1, ao->log); + } } + mp_mutex_unlock(&jni_static_lock); } static int init_jni(struct ao *ao) { + mp_mutex_lock(&jni_static_lock); JNIEnv *env = MP_JNI_GET_ENV(ao); - for (int i = 0; i < MP_ARRAY_SIZE(jclass_list); i++) { - if (mp_jni_init_jfields(env, jclass_list[i].fields, - jclass_list[i].mapping, 1, ao->log) < 0) { - goto error; + if (jni_static_use_count == 0) { + for (int i = 0; i < MP_ARRAY_SIZE(jclass_list); i++) { + if (mp_jni_init_jfields(env, jclass_list[i].fields, + jclass_list[i].mapping, 1, ao->log) < 0) { + goto error; + } } } + jni_static_use_count++; + mp_mutex_unlock(&jni_static_lock); return 0; error: - uninit_jni(ao); + for (int i = 0; i < MP_ARRAY_SIZE(jclass_list); i++) { + mp_jni_reset_jfields(env, jclass_list[i].fields, + jclass_list[i].mapping, 1, ao->log); + } + mp_mutex_unlock(&jni_static_lock); return -1; }