1 /* clang-format off */
2 #include "jni.h"
3 #include <assert.h>
4 #include "cubeb-jni-instances.h"
5 /* clang-format on */
6 
7 #define AUDIO_STREAM_TYPE_MUSIC 3
8 
9 struct cubeb_jni {
10   jobject s_audio_manager_obj = nullptr;
11   jclass s_audio_manager_class = nullptr;
12   jmethodID s_get_output_latency_id = nullptr;
13 };
14 
15 extern "C" cubeb_jni *
cubeb_jni_init()16 cubeb_jni_init()
17 {
18   jobject ctx_obj = cubeb_jni_get_context_instance();
19   JNIEnv * jni_env = cubeb_get_jni_env_for_thread();
20   if (!jni_env || !ctx_obj) {
21     return nullptr;
22   }
23 
24   cubeb_jni * cubeb_jni_ptr = new cubeb_jni;
25   assert(cubeb_jni_ptr);
26 
27   // Find the audio manager object and make it global to call it from another
28   // method
29   jclass context_class = jni_env->FindClass("android/content/Context");
30   jfieldID audio_service_field = jni_env->GetStaticFieldID(
31       context_class, "AUDIO_SERVICE", "Ljava/lang/String;");
32   jstring jstr = (jstring)jni_env->GetStaticObjectField(context_class,
33                                                         audio_service_field);
34   jmethodID get_system_service_id =
35       jni_env->GetMethodID(context_class, "getSystemService",
36                            "(Ljava/lang/String;)Ljava/lang/Object;");
37   jobject audio_manager_obj =
38       jni_env->CallObjectMethod(ctx_obj, get_system_service_id, jstr);
39   cubeb_jni_ptr->s_audio_manager_obj =
40       reinterpret_cast<jobject>(jni_env->NewGlobalRef(audio_manager_obj));
41 
42   // Make the audio manager class a global reference in order to preserve method
43   // id
44   jclass audio_manager_class = jni_env->FindClass("android/media/AudioManager");
45   cubeb_jni_ptr->s_audio_manager_class =
46       reinterpret_cast<jclass>(jni_env->NewGlobalRef(audio_manager_class));
47   cubeb_jni_ptr->s_get_output_latency_id =
48       jni_env->GetMethodID(audio_manager_class, "getOutputLatency", "(I)I");
49 
50   jni_env->DeleteLocalRef(ctx_obj);
51   jni_env->DeleteLocalRef(context_class);
52   jni_env->DeleteLocalRef(jstr);
53   jni_env->DeleteLocalRef(audio_manager_obj);
54   jni_env->DeleteLocalRef(audio_manager_class);
55 
56   return cubeb_jni_ptr;
57 }
58 
59 extern "C" int
cubeb_get_output_latency_from_jni(cubeb_jni * cubeb_jni_ptr)60 cubeb_get_output_latency_from_jni(cubeb_jni * cubeb_jni_ptr)
61 {
62   assert(cubeb_jni_ptr);
63   JNIEnv * jni_env = cubeb_get_jni_env_for_thread();
64   return jni_env->CallIntMethod(
65       cubeb_jni_ptr->s_audio_manager_obj,
66       cubeb_jni_ptr->s_get_output_latency_id,
67       AUDIO_STREAM_TYPE_MUSIC); // param: AudioManager.STREAM_MUSIC
68 }
69 
70 extern "C" void
cubeb_jni_destroy(cubeb_jni * cubeb_jni_ptr)71 cubeb_jni_destroy(cubeb_jni * cubeb_jni_ptr)
72 {
73   assert(cubeb_jni_ptr);
74 
75   JNIEnv * jni_env = cubeb_get_jni_env_for_thread();
76   assert(jni_env);
77 
78   jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_audio_manager_obj);
79   jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_audio_manager_class);
80 
81   delete cubeb_jni_ptr;
82 }
83