blob: cb4ddbd119d587c03bf186bfc63edb80b675e1a3 [file] [log] [blame]
François Gaffieadcd00a2018-09-18 17:06:26 +02001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18
19#define LOG_TAG "AudioVolumeGroupCallback-JNI"
20
21#include <utils/Log.h>
22#include <nativehelper/JNIHelp.h>
23#include "core_jni_helpers.h"
24
25#include "android_media_AudioVolumeGroupCallback.h"
26
27
28// ----------------------------------------------------------------------------
29using namespace android;
30
31static const char* const kAudioVolumeGroupChangeHandlerClassPathName =
32 "android/media/audiopolicy/AudioVolumeGroupChangeHandler";
33
34static struct {
35 jfieldID mJniCallback;
36} gAudioVolumeGroupChangeHandlerFields;
37
38static struct {
39 jmethodID postEventFromNative;
40} gAudioVolumeGroupChangeHandlerMethods;
41
42static Mutex gLock;
43
44JNIAudioVolumeGroupCallback::JNIAudioVolumeGroupCallback(JNIEnv* env,
45 jobject thiz,
46 jobject weak_thiz)
47{
48 jclass clazz = env->GetObjectClass(thiz);
49 if (clazz == NULL) {
50 ALOGE("Can't find class %s", kAudioVolumeGroupChangeHandlerClassPathName);
51 return;
52 }
53 mClass = (jclass)env->NewGlobalRef(clazz);
54
55 // We use a weak reference so the AudioVolumeGroupChangeHandler object can be garbage collected.
56 // The reference is only used as a proxy for callbacks.
57 mObject = env->NewGlobalRef(weak_thiz);
58}
59
60JNIAudioVolumeGroupCallback::~JNIAudioVolumeGroupCallback()
61{
62 // remove global references
63 JNIEnv *env = AndroidRuntime::getJNIEnv();
64 if (env == NULL) {
65 return;
66 }
67 env->DeleteGlobalRef(mObject);
68 env->DeleteGlobalRef(mClass);
69}
70
71void JNIAudioVolumeGroupCallback::onAudioVolumeGroupChanged(volume_group_t group, int flags)
72{
73 JNIEnv *env = AndroidRuntime::getJNIEnv();
74 if (env == NULL) {
75 return;
76 }
77 ALOGV("%s volume group id %d", __FUNCTION__, group);
78 env->CallStaticVoidMethod(mClass,
79 gAudioVolumeGroupChangeHandlerMethods.postEventFromNative,
80 mObject,
81 AUDIOVOLUMEGROUP_EVENT_VOLUME_CHANGED, group, flags, NULL);
82 if (env->ExceptionCheck()) {
83 ALOGW("An exception occurred while notifying an event.");
84 env->ExceptionClear();
85 }
86}
87
88void JNIAudioVolumeGroupCallback::onServiceDied()
89{
90 JNIEnv *env = AndroidRuntime::getJNIEnv();
91 if (env == NULL) {
92 return;
93 }
94 env->CallStaticVoidMethod(mClass,
95 gAudioVolumeGroupChangeHandlerMethods.postEventFromNative,
96 mObject,
97 AUDIOVOLUMEGROUP_EVENT_SERVICE_DIED, 0, 0, NULL);
98 if (env->ExceptionCheck()) {
99 ALOGW("An exception occurred while notifying an event.");
100 env->ExceptionClear();
101 }
102}
103
104static
105sp<JNIAudioVolumeGroupCallback> setJniCallback(JNIEnv* env,
106 jobject thiz,
107 const sp<JNIAudioVolumeGroupCallback>& callback)
108{
109 Mutex::Autolock l(gLock);
110 sp<JNIAudioVolumeGroupCallback> old = (JNIAudioVolumeGroupCallback*)env->GetLongField(
111 thiz, gAudioVolumeGroupChangeHandlerFields.mJniCallback);
112 if (callback.get()) {
113 callback->incStrong((void*)setJniCallback);
114 }
115 if (old != 0) {
116 old->decStrong((void*)setJniCallback);
117 }
118 env->SetLongField(thiz, gAudioVolumeGroupChangeHandlerFields.mJniCallback,
119 (jlong)callback.get());
120 return old;
121}
122
123static void
124android_media_AudioVolumeGroupChangeHandler_eventHandlerSetup(JNIEnv *env,
125 jobject thiz,
126 jobject weak_this)
127{
128 ALOGV("%s", __FUNCTION__);
129 sp<JNIAudioVolumeGroupCallback> callback =
130 new JNIAudioVolumeGroupCallback(env, thiz, weak_this);
131
132 if (AudioSystem::addAudioVolumeGroupCallback(callback) == NO_ERROR) {
133 setJniCallback(env, thiz, callback);
134 }
135}
136
137static void
138android_media_AudioVolumeGroupChangeHandler_eventHandlerFinalize(JNIEnv *env, jobject thiz)
139{
140 ALOGV("%s", __FUNCTION__);
141 sp<JNIAudioVolumeGroupCallback> callback = setJniCallback(env, thiz, 0);
142 if (callback != 0) {
143 AudioSystem::removeAudioVolumeGroupCallback(callback);
144 }
145}
146
147/*
148 * JNI registration.
149 */
150static const JNINativeMethod gMethods[] = {
151 {"native_setup", "(Ljava/lang/Object;)V",
152 (void *)android_media_AudioVolumeGroupChangeHandler_eventHandlerSetup},
153 {"native_finalize", "()V",
154 (void *)android_media_AudioVolumeGroupChangeHandler_eventHandlerFinalize},
155};
156
157int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env)
158{
159 jclass audioVolumeGroupChangeHandlerClass =
160 FindClassOrDie(env, kAudioVolumeGroupChangeHandlerClassPathName);
161 gAudioVolumeGroupChangeHandlerMethods.postEventFromNative =
162 GetStaticMethodIDOrDie(env, audioVolumeGroupChangeHandlerClass, "postEventFromNative",
163 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
164
165 gAudioVolumeGroupChangeHandlerFields.mJniCallback =
166 GetFieldIDOrDie(env, audioVolumeGroupChangeHandlerClass, "mJniCallback", "J");
167
168 env->DeleteLocalRef(audioVolumeGroupChangeHandlerClass);
169
170 return RegisterMethodsOrDie(env,
171 kAudioVolumeGroupChangeHandlerClassPathName,
172 gMethods,
173 NELEM(gMethods));
174}
175