blob: 747d4c01867ed0cdfbf774bd0def568247adf5ca [file] [log] [blame]
Eric Laurent948235c2010-06-09 00:17:29 -07001/*
2 * Copyright (C) 2010 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
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -080017
Eric Laurent948235c2010-06-09 00:17:29 -070018#include <stdio.h>
19
20//#define LOG_NDEBUG 0
21#define LOG_TAG "AudioEffects-JNI"
22
23#include <utils/Log.h>
Steven Moreland889f9952017-07-17 12:08:45 -070024#include <jni.h>
Eric Laurent948235c2010-06-09 00:17:29 -070025#include <nativehelper/JNIHelp.h>
26#include <android_runtime/AndroidRuntime.h>
27#include "media/AudioEffect.h"
28
Steven Moreland2279b252017-07-19 09:50:45 -070029#include <nativehelper/ScopedUtfChars.h>
Svet Ganovfa5ecdc2015-04-28 12:03:28 -070030
Eric Laurent7c31847e2018-11-29 14:33:56 -080031#include "android_media_AudioEffect.h"
32#include "android_media_AudioEffectDescriptor.h"
33#include "android_media_AudioErrors.h"
34
Eric Laurent948235c2010-06-09 00:17:29 -070035using namespace android;
36
37#define AUDIOEFFECT_SUCCESS 0
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -070038#define AUDIOEFFECT_ERROR (-1)
39#define AUDIOEFFECT_ERROR_ALREADY_EXISTS (-2)
40#define AUDIOEFFECT_ERROR_NO_INIT (-3)
41#define AUDIOEFFECT_ERROR_BAD_VALUE (-4)
42#define AUDIOEFFECT_ERROR_INVALID_OPERATION (-5)
43#define AUDIOEFFECT_ERROR_NO_MEMORY (-6)
44#define AUDIOEFFECT_ERROR_DEAD_OBJECT (-7)
Eric Laurent948235c2010-06-09 00:17:29 -070045
46// ----------------------------------------------------------------------------
Eric Laurent1a5149e2010-09-21 18:18:20 -070047static const char* const kClassPathName = "android/media/audiofx/AudioEffect";
Eric Laurent948235c2010-06-09 00:17:29 -070048
49struct fields_t {
50 // these fields provide access from C++ to the...
51 jclass clazzEffect; // AudioEffect class
52 jmethodID midPostNativeEvent; // event post callback method
53 jfieldID fidNativeAudioEffect; // stores in Java the native AudioEffect object
54 jfieldID fidJniData; // stores in Java additional resources used by the native AudioEffect
Eric Laurent948235c2010-06-09 00:17:29 -070055};
56static fields_t fields;
57
58struct effect_callback_cookie {
59 jclass audioEffect_class; // AudioEffect class
60 jobject audioEffect_ref; // AudioEffect object instance
61 };
62
63// ----------------------------------------------------------------------------
64class AudioEffectJniStorage {
65 public:
66 effect_callback_cookie mCallbackData;
67
68 AudioEffectJniStorage() {
69 }
70
71 ~AudioEffectJniStorage() {
72 }
73
74};
75
76
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -080077jint AudioEffectJni::translateNativeErrorToJava(int code) {
Eric Laurent948235c2010-06-09 00:17:29 -070078 switch(code) {
79 case NO_ERROR:
80 return AUDIOEFFECT_SUCCESS;
81 case ALREADY_EXISTS:
82 return AUDIOEFFECT_ERROR_ALREADY_EXISTS;
83 case NO_INIT:
84 return AUDIOEFFECT_ERROR_NO_INIT;
85 case BAD_VALUE:
86 return AUDIOEFFECT_ERROR_BAD_VALUE;
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -080087 case NAME_NOT_FOUND:
88 // Name not found means the client tried to create an effect not found on the system,
89 // which is a form of bad value.
90 return AUDIOEFFECT_ERROR_BAD_VALUE;
Eric Laurent948235c2010-06-09 00:17:29 -070091 case INVALID_OPERATION:
92 return AUDIOEFFECT_ERROR_INVALID_OPERATION;
93 case NO_MEMORY:
94 return AUDIOEFFECT_ERROR_NO_MEMORY;
95 case DEAD_OBJECT:
Andy Hung32d51632017-05-16 12:32:27 -070096 case FAILED_TRANSACTION: // Hidl crash shows as FAILED_TRANSACTION: -2147483646
Eric Laurent948235c2010-06-09 00:17:29 -070097 return AUDIOEFFECT_ERROR_DEAD_OBJECT;
98 default:
99 return AUDIOEFFECT_ERROR;
100 }
101}
102
Eric Laurent76f81332015-06-04 16:20:47 -0700103static Mutex sLock;
Eric Laurent948235c2010-06-09 00:17:29 -0700104
105// ----------------------------------------------------------------------------
106static void effectCallback(int event, void* user, void *info) {
107
108 effect_param_t *p;
109 int arg1 = 0;
110 int arg2 = 0;
111 jobject obj = NULL;
112 jbyteArray array = NULL;
113 jbyte *bytes;
114 bool param;
115 size_t size;
116
117 effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
118 JNIEnv *env = AndroidRuntime::getJNIEnv();
119
Eric Laurent948235c2010-06-09 00:17:29 -0700120 if (!user || !env) {
Steve Block8564c8d2012-01-05 23:22:43 +0000121 ALOGW("effectCallback error user %p, env %p", user, env);
Eric Laurent948235c2010-06-09 00:17:29 -0700122 return;
123 }
124
Greg Kaiser866645d2018-04-06 13:40:13 -0700125 ALOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
126 callbackInfo,
127 callbackInfo->audioEffect_ref,
128 callbackInfo->audioEffect_class);
129
Eric Laurent948235c2010-06-09 00:17:29 -0700130 switch (event) {
131 case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
132 if (info == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000133 ALOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
Eric Laurent948235c2010-06-09 00:17:29 -0700134 goto effectCallback_Exit;
135 }
136 param = *(bool *)info;
137 arg1 = (int)param;
Steve Block71f2cf12011-10-20 11:56:00 +0100138 ALOGV("EVENT_CONTROL_STATUS_CHANGED");
Eric Laurent948235c2010-06-09 00:17:29 -0700139 break;
140 case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
141 if (info == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000142 ALOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
Eric Laurent948235c2010-06-09 00:17:29 -0700143 goto effectCallback_Exit;
144 }
145 param = *(bool *)info;
146 arg1 = (int)param;
Steve Block71f2cf12011-10-20 11:56:00 +0100147 ALOGV("EVENT_ENABLE_STATUS_CHANGED");
Eric Laurent948235c2010-06-09 00:17:29 -0700148 break;
149 case AudioEffect::EVENT_PARAMETER_CHANGED:
150 if (info == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000151 ALOGW("EVENT_PARAMETER_CHANGED info == NULL");
Eric Laurent948235c2010-06-09 00:17:29 -0700152 goto effectCallback_Exit;
153 }
154 p = (effect_param_t *)info;
155 if (p->psize == 0 || p->vsize == 0) {
156 goto effectCallback_Exit;
157 }
158 // arg1 contains offset of parameter value from start of byte array
159 arg1 = sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) + 1) * sizeof(int);
160 size = arg1 + p->vsize;
161 array = env->NewByteArray(size);
162 if (array == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000163 ALOGE("effectCallback: Couldn't allocate byte array for parameter data");
Eric Laurent948235c2010-06-09 00:17:29 -0700164 goto effectCallback_Exit;
165 }
166 bytes = env->GetByteArrayElements(array, NULL);
167 memcpy(bytes, p, size);
168 env->ReleaseByteArrayElements(array, bytes, 0);
169 obj = array;
Steve Block71f2cf12011-10-20 11:56:00 +0100170 ALOGV("EVENT_PARAMETER_CHANGED");
Eric Laurent948235c2010-06-09 00:17:29 -0700171 break;
172 case AudioEffect::EVENT_ERROR:
Steve Block8564c8d2012-01-05 23:22:43 +0000173 ALOGW("EVENT_ERROR");
Eric Laurent948235c2010-06-09 00:17:29 -0700174 break;
175 }
176
177 env->CallStaticVoidMethod(
178 callbackInfo->audioEffect_class,
179 fields.midPostNativeEvent,
180 callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
181
182effectCallback_Exit:
183 if (array) {
184 env->DeleteLocalRef(array);
185 }
186
187 if (env->ExceptionCheck()) {
188 env->ExceptionDescribe();
189 env->ExceptionClear();
190 }
191}
192
193// ----------------------------------------------------------------------------
Eric Laurent76f81332015-06-04 16:20:47 -0700194
195static sp<AudioEffect> getAudioEffect(JNIEnv* env, jobject thiz)
196{
197 Mutex::Autolock l(sLock);
198 AudioEffect* const ae =
199 (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
200 return sp<AudioEffect>(ae);
201}
202
203static sp<AudioEffect> setAudioEffect(JNIEnv* env, jobject thiz,
204 const sp<AudioEffect>& ae)
205{
206 Mutex::Autolock l(sLock);
207 sp<AudioEffect> old =
208 (AudioEffect*)env->GetLongField(thiz, fields.fidNativeAudioEffect);
209 if (ae.get()) {
210 ae->incStrong((void*)setAudioEffect);
211 }
212 if (old != 0) {
213 old->decStrong((void*)setAudioEffect);
214 }
215 env->SetLongField(thiz, fields.fidNativeAudioEffect, (jlong)ae.get());
216 return old;
217}
218
219// ----------------------------------------------------------------------------
Eric Laurent948235c2010-06-09 00:17:29 -0700220// This function gets some field IDs, which in turn causes class initialization.
221// It is called from a static block in AudioEffect, which won't run until the
222// first time an instance of this class is used.
223static void
224android_media_AudioEffect_native_init(JNIEnv *env)
225{
226
Steve Block71f2cf12011-10-20 11:56:00 +0100227 ALOGV("android_media_AudioEffect_native_init");
Eric Laurent948235c2010-06-09 00:17:29 -0700228
229 fields.clazzEffect = NULL;
Eric Laurent948235c2010-06-09 00:17:29 -0700230
231 // Get the AudioEffect class
232 jclass clazz = env->FindClass(kClassPathName);
233 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000234 ALOGE("Can't find %s", kClassPathName);
Eric Laurent948235c2010-06-09 00:17:29 -0700235 return;
236 }
237
238 fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
239
240 // Get the postEvent method
241 fields.midPostNativeEvent = env->GetStaticMethodID(
242 fields.clazzEffect,
243 "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
244 if (fields.midPostNativeEvent == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000245 ALOGE("Can't find AudioEffect.%s", "postEventFromNative");
Eric Laurent948235c2010-06-09 00:17:29 -0700246 return;
247 }
248
249 // Get the variables fields
250 // nativeTrackInJavaObj
251 fields.fidNativeAudioEffect = env->GetFieldID(
252 fields.clazzEffect,
Ashok Bhatea7861c2013-12-17 12:42:00 +0000253 "mNativeAudioEffect", "J");
Eric Laurent948235c2010-06-09 00:17:29 -0700254 if (fields.fidNativeAudioEffect == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000255 ALOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
Eric Laurent948235c2010-06-09 00:17:29 -0700256 return;
257 }
258 // fidJniData;
259 fields.fidJniData = env->GetFieldID(
260 fields.clazzEffect,
Ashok Bhatea7861c2013-12-17 12:42:00 +0000261 "mJniData", "J");
Eric Laurent948235c2010-06-09 00:17:29 -0700262 if (fields.fidJniData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000263 ALOGE("Can't find AudioEffect.%s", "mJniData");
Eric Laurent948235c2010-06-09 00:17:29 -0700264 return;
265 }
Eric Laurent948235c2010-06-09 00:17:29 -0700266}
267
268
269static jint
270android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700271 jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId,
272 jobjectArray javadesc, jstring opPackageName)
Eric Laurent948235c2010-06-09 00:17:29 -0700273{
Steve Block71f2cf12011-10-20 11:56:00 +0100274 ALOGV("android_media_AudioEffect_native_setup");
Eric Laurent948235c2010-06-09 00:17:29 -0700275 AudioEffectJniStorage* lpJniStorage = NULL;
276 int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
Eric Laurent76f81332015-06-04 16:20:47 -0700277 sp<AudioEffect> lpAudioEffect;
Eric Laurent948235c2010-06-09 00:17:29 -0700278 jint* nId = NULL;
279 const char *typeStr = NULL;
280 const char *uuidStr = NULL;
281 effect_descriptor_t desc;
282 jobject jdesc;
Eric Laurent948235c2010-06-09 00:17:29 -0700283
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700284 ScopedUtfChars opPackageNameStr(env, opPackageName);
285
Eric Laurent76f81332015-06-04 16:20:47 -0700286 setAudioEffect(env, thiz, 0);
287
Eric Laurent948235c2010-06-09 00:17:29 -0700288 if (type != NULL) {
289 typeStr = env->GetStringUTFChars(type, NULL);
290 if (typeStr == NULL) { // Out of memory
291 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
292 goto setup_failure;
293 }
294 }
295
296 if (uuid != NULL) {
297 uuidStr = env->GetStringUTFChars(uuid, NULL);
298 if (uuidStr == NULL) { // Out of memory
299 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
300 goto setup_failure;
301 }
302 }
303
304 if (typeStr == NULL && uuidStr == NULL) {
305 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
306 goto setup_failure;
307 }
308
309 lpJniStorage = new AudioEffectJniStorage();
310 if (lpJniStorage == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000311 ALOGE("setup: Error creating JNI Storage");
Eric Laurent948235c2010-06-09 00:17:29 -0700312 goto setup_failure;
313 }
314
315 lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
316 // we use a weak reference so the AudioEffect object can be garbage collected.
317 lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
318
Steve Block71f2cf12011-10-20 11:56:00 +0100319 ALOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
Eric Laurent948235c2010-06-09 00:17:29 -0700320 lpJniStorage,
321 lpJniStorage->mCallbackData.audioEffect_ref,
322 lpJniStorage->mCallbackData.audioEffect_class,
323 &lpJniStorage->mCallbackData);
324
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700325 if (jId == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000326 ALOGE("setup: NULL java array for id pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700327 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
328 goto setup_failure;
329 }
330
331 // create the native AudioEffect object
332 lpAudioEffect = new AudioEffect(typeStr,
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700333 String16(opPackageNameStr.c_str()),
Eric Laurent948235c2010-06-09 00:17:29 -0700334 uuidStr,
335 priority,
336 effectCallback,
337 &lpJniStorage->mCallbackData,
Glenn Kasten33b84042016-03-08 12:02:55 -0800338 (audio_session_t) sessionId,
Glenn Kasten87e901cc2016-03-10 09:37:03 -0800339 AUDIO_IO_HANDLE_NONE);
Eric Laurent76f81332015-06-04 16:20:47 -0700340 if (lpAudioEffect == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000341 ALOGE("Error creating AudioEffect");
Eric Laurent948235c2010-06-09 00:17:29 -0700342 goto setup_failure;
343 }
344
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -0800345 lStatus = AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->initCheck());
Eric Laurent948235c2010-06-09 00:17:29 -0700346 if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
Steve Block3762c312012-01-06 19:20:56 +0000347 ALOGE("AudioEffect initCheck failed %d", lStatus);
Eric Laurent948235c2010-06-09 00:17:29 -0700348 goto setup_failure;
349 }
350
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700351 nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
352 if (nId == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000353 ALOGE("setup: Error retrieving id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700354 lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
355 goto setup_failure;
356 }
Eric Laurent948235c2010-06-09 00:17:29 -0700357 nId[0] = lpAudioEffect->id();
Eric Laurent948235c2010-06-09 00:17:29 -0700358 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
359 nId = NULL;
360
361 if (typeStr) {
362 env->ReleaseStringUTFChars(type, typeStr);
363 typeStr = NULL;
364 }
365
366 if (uuidStr) {
367 env->ReleaseStringUTFChars(uuid, uuidStr);
368 uuidStr = NULL;
369 }
370
371 // get the effect descriptor
372 desc = lpAudioEffect->descriptor();
373
Eric Laurent7c31847e2018-11-29 14:33:56 -0800374 if (convertAudioEffectDescriptorFromNative(env, &jdesc, &desc) != AUDIO_JAVA_SUCCESS) {
Eric Laurent948235c2010-06-09 00:17:29 -0700375 goto setup_failure;
376 }
377
378 env->SetObjectArrayElement(javadesc, 0, jdesc);
Eric Laurent7c31847e2018-11-29 14:33:56 -0800379 env->DeleteLocalRef(jdesc);
Eric Laurent948235c2010-06-09 00:17:29 -0700380
Eric Laurent76f81332015-06-04 16:20:47 -0700381 setAudioEffect(env, thiz, lpAudioEffect);
Eric Laurent948235c2010-06-09 00:17:29 -0700382
Ashok Bhatea7861c2013-12-17 12:42:00 +0000383 env->SetLongField(thiz, fields.fidJniData, (jlong)lpJniStorage);
Eric Laurent948235c2010-06-09 00:17:29 -0700384
Ashok Bhatea7861c2013-12-17 12:42:00 +0000385 return (jint) AUDIOEFFECT_SUCCESS;
Eric Laurent948235c2010-06-09 00:17:29 -0700386
387 // failures:
388setup_failure:
389
390 if (nId != NULL) {
391 env->ReleasePrimitiveArrayCritical(jId, nId, 0);
392 }
393
Eric Laurent948235c2010-06-09 00:17:29 -0700394 if (lpJniStorage) {
Eric Laurent76f81332015-06-04 16:20:47 -0700395 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
396 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
Eric Laurent948235c2010-06-09 00:17:29 -0700397 delete lpJniStorage;
398 }
Ashok Bhatea7861c2013-12-17 12:42:00 +0000399 env->SetLongField(thiz, fields.fidJniData, 0);
Eric Laurent948235c2010-06-09 00:17:29 -0700400
401 if (uuidStr != NULL) {
402 env->ReleaseStringUTFChars(uuid, uuidStr);
403 }
404
405 if (typeStr != NULL) {
406 env->ReleaseStringUTFChars(type, typeStr);
407 }
408
Ashok Bhatea7861c2013-12-17 12:42:00 +0000409 return (jint)lStatus;
Eric Laurent948235c2010-06-09 00:17:29 -0700410}
411
412
413// ----------------------------------------------------------------------------
Eric Laurent76f81332015-06-04 16:20:47 -0700414static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
415 sp<AudioEffect> lpAudioEffect = setAudioEffect(env, thiz, 0);
416 if (lpAudioEffect == 0) {
417 return;
Eric Laurent948235c2010-06-09 00:17:29 -0700418 }
419
420 // delete the JNI data
Eric Laurent76f81332015-06-04 16:20:47 -0700421 AudioEffectJniStorage* lpJniStorage =
422 (AudioEffectJniStorage *)env->GetLongField(thiz, fields.fidJniData);
423
424 // reset the native resources in the Java object so any attempt to access
425 // them after a call to release fails.
426 env->SetLongField(thiz, fields.fidJniData, 0);
427
Eric Laurent948235c2010-06-09 00:17:29 -0700428 if (lpJniStorage) {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000429 ALOGV("deleting pJniStorage: %p\n", lpJniStorage);
Eric Laurent07799982015-06-19 09:13:02 -0700430 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
431 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
Eric Laurent948235c2010-06-09 00:17:29 -0700432 delete lpJniStorage;
433 }
434}
435
436// ----------------------------------------------------------------------------
Eric Laurent76f81332015-06-04 16:20:47 -0700437static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
438 ALOGV("android_media_AudioEffect_native_finalize jobject: %p\n", thiz);
439 android_media_AudioEffect_native_release(env, thiz);
Eric Laurent948235c2010-06-09 00:17:29 -0700440}
441
Eric Laurent948235c2010-06-09 00:17:29 -0700442static jint
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700443android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
Eric Laurent948235c2010-06-09 00:17:29 -0700444{
Eric Laurent76f81332015-06-04 16:20:47 -0700445 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
446 if (lpAudioEffect == 0) {
Eric Laurent948235c2010-06-09 00:17:29 -0700447 jniThrowException(env, "java/lang/IllegalStateException",
448 "Unable to retrieve AudioEffect pointer for enable()");
449 return AUDIOEFFECT_ERROR_NO_INIT;
450 }
451
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -0800452 return AudioEffectJni::translateNativeErrorToJava(lpAudioEffect->setEnabled(enabled));
Eric Laurent948235c2010-06-09 00:17:29 -0700453}
454
Eric Laurent948235c2010-06-09 00:17:29 -0700455static jboolean
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700456android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
Eric Laurent948235c2010-06-09 00:17:29 -0700457{
Eric Laurent76f81332015-06-04 16:20:47 -0700458 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
459 if (lpAudioEffect == 0) {
Eric Laurent948235c2010-06-09 00:17:29 -0700460 jniThrowException(env, "java/lang/IllegalStateException",
461 "Unable to retrieve AudioEffect pointer for getEnabled()");
Ashok Bhatea7861c2013-12-17 12:42:00 +0000462 return JNI_FALSE;
Eric Laurent948235c2010-06-09 00:17:29 -0700463 }
464
Ashok Bhatea7861c2013-12-17 12:42:00 +0000465 if (lpAudioEffect->getEnabled()) {
466 return JNI_TRUE;
467 } else {
468 return JNI_FALSE;
469 }
Eric Laurent948235c2010-06-09 00:17:29 -0700470}
471
472
473static jboolean
474android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
475{
Eric Laurent76f81332015-06-04 16:20:47 -0700476 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
477 if (lpAudioEffect == 0) {
Eric Laurent948235c2010-06-09 00:17:29 -0700478 jniThrowException(env, "java/lang/IllegalStateException",
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700479 "Unable to retrieve AudioEffect pointer for hasControl()");
Ashok Bhatea7861c2013-12-17 12:42:00 +0000480 return JNI_FALSE;
Eric Laurent948235c2010-06-09 00:17:29 -0700481 }
482
483 if (lpAudioEffect->initCheck() == NO_ERROR) {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000484 return JNI_TRUE;
Eric Laurent948235c2010-06-09 00:17:29 -0700485 } else {
Ashok Bhatea7861c2013-12-17 12:42:00 +0000486 return JNI_FALSE;
Eric Laurent948235c2010-06-09 00:17:29 -0700487 }
488}
489
490static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
Ashok Bhatea7861c2013-12-17 12:42:00 +0000491 jobject thiz, jint psize, jbyteArray pJavaParam, jint vsize,
Eric Laurent948235c2010-06-09 00:17:29 -0700492 jbyteArray pJavaValue) {
493 // retrieve the AudioEffect object
494 jbyte* lpValue = NULL;
495 jbyte* lpParam = NULL;
496 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
497 effect_param_t *p;
498 int voffset;
499
Eric Laurent76f81332015-06-04 16:20:47 -0700500 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
501 if (lpAudioEffect == 0) {
Eric Laurent948235c2010-06-09 00:17:29 -0700502 jniThrowException(env, "java/lang/IllegalStateException",
503 "Unable to retrieve AudioEffect pointer for setParameter()");
504 return AUDIOEFFECT_ERROR_NO_INIT;
505 }
506
507 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
508 return AUDIOEFFECT_ERROR_BAD_VALUE;
509 }
510
511 // get the pointer for the param from the java array
512 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
513 if (lpParam == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000514 ALOGE("setParameter: Error retrieving param pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700515 goto setParameter_Exit;
516 }
517
518 // get the pointer for the value from the java array
519 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
520 if (lpValue == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000521 ALOGE("setParameter: Error retrieving value pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700522 goto setParameter_Exit;
523 }
524
525 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
526 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
527 memcpy(p->data, lpParam, psize);
528 p->psize = psize;
Eric Laurentca57d1c2010-07-23 00:19:11 -0700529 memcpy(p->data + voffset, lpValue, vsize);
Eric Laurent948235c2010-06-09 00:17:29 -0700530 p->vsize = vsize;
531
532 lStatus = lpAudioEffect->setParameter(p);
533 if (lStatus == NO_ERROR) {
534 lStatus = p->status;
535 }
536
537 free(p);
538
539setParameter_Exit:
540
541 if (lpParam != NULL) {
542 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
543 }
544 if (lpValue != NULL) {
545 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
546 }
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -0800547 return AudioEffectJni::translateNativeErrorToJava(lStatus);
Eric Laurent948235c2010-06-09 00:17:29 -0700548}
549
550static jint
551android_media_AudioEffect_native_getParameter(JNIEnv *env,
Eric Laurent602b3282011-03-18 08:33:14 -0700552 jobject thiz, jint psize, jbyteArray pJavaParam,
553 jint vsize, jbyteArray pJavaValue) {
Eric Laurent948235c2010-06-09 00:17:29 -0700554 // retrieve the AudioEffect object
555 jbyte* lpParam = NULL;
556 jbyte* lpValue = NULL;
Eric Laurent948235c2010-06-09 00:17:29 -0700557 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
558 effect_param_t *p;
559 int voffset;
560
Eric Laurent76f81332015-06-04 16:20:47 -0700561 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
562 if (lpAudioEffect == 0) {
Eric Laurent948235c2010-06-09 00:17:29 -0700563 jniThrowException(env, "java/lang/IllegalStateException",
564 "Unable to retrieve AudioEffect pointer for getParameter()");
565 return AUDIOEFFECT_ERROR_NO_INIT;
566 }
567
Eric Laurent602b3282011-03-18 08:33:14 -0700568 if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
Eric Laurent948235c2010-06-09 00:17:29 -0700569 return AUDIOEFFECT_ERROR_BAD_VALUE;
570 }
571
572 // get the pointer for the param from the java array
573 lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
574 if (lpParam == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000575 ALOGE("getParameter: Error retrieving param pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700576 goto getParameter_Exit;
577 }
578
579 // get the pointer for the value from the java array
580 lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
581 if (lpValue == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000582 ALOGE("getParameter: Error retrieving value pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700583 goto getParameter_Exit;
584 }
585
Eric Laurent948235c2010-06-09 00:17:29 -0700586 voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
Eric Laurent602b3282011-03-18 08:33:14 -0700587 p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
Eric Laurent948235c2010-06-09 00:17:29 -0700588 memcpy(p->data, lpParam, psize);
589 p->psize = psize;
Eric Laurent602b3282011-03-18 08:33:14 -0700590 p->vsize = vsize;
Eric Laurent948235c2010-06-09 00:17:29 -0700591
592 lStatus = lpAudioEffect->getParameter(p);
593 if (lStatus == NO_ERROR) {
594 lStatus = p->status;
595 if (lStatus == NO_ERROR) {
596 memcpy(lpValue, p->data + voffset, p->vsize);
Eric Laurent602b3282011-03-18 08:33:14 -0700597 vsize = p->vsize;
Eric Laurent948235c2010-06-09 00:17:29 -0700598 }
599 }
600
601 free(p);
602
603getParameter_Exit:
604
605 if (lpParam != NULL) {
606 env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
607 }
608 if (lpValue != NULL) {
609 env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
610 }
Eric Laurent948235c2010-06-09 00:17:29 -0700611
Eric Laurent602b3282011-03-18 08:33:14 -0700612 if (lStatus == NO_ERROR) {
613 return vsize;
614 }
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -0800615 return AudioEffectJni::translateNativeErrorToJava(lStatus);
Eric Laurent948235c2010-06-09 00:17:29 -0700616}
617
618static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
Eric Laurent602b3282011-03-18 08:33:14 -0700619 jint cmdCode, jint cmdSize, jbyteArray jCmdData, jint replySize,
Eric Laurent948235c2010-06-09 00:17:29 -0700620 jbyteArray jReplyData) {
621 jbyte* pCmdData = NULL;
622 jbyte* pReplyData = NULL;
Eric Laurent948235c2010-06-09 00:17:29 -0700623 jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
624
Eric Laurent76f81332015-06-04 16:20:47 -0700625 sp<AudioEffect> lpAudioEffect = getAudioEffect(env, thiz);
626 if (lpAudioEffect == 0) {
Eric Laurent948235c2010-06-09 00:17:29 -0700627 jniThrowException(env, "java/lang/IllegalStateException",
628 "Unable to retrieve AudioEffect pointer for setParameter()");
629 return AUDIOEFFECT_ERROR_NO_INIT;
630 }
631
Eric Laurent602b3282011-03-18 08:33:14 -0700632 if ((cmdSize != 0 && jCmdData == NULL) || (replySize != 0 && jReplyData == NULL)) {
Eric Laurent948235c2010-06-09 00:17:29 -0700633 return AUDIOEFFECT_ERROR_BAD_VALUE;
634 }
635
636 // get the pointer for the command from the java array
637 if (cmdSize != 0) {
638 pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
639 if (pCmdData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000640 ALOGE("setParameter: Error retrieving command pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700641 goto command_Exit;
642 }
643 }
644
Eric Laurent948235c2010-06-09 00:17:29 -0700645 // get the pointer for the reply from the java array
Eric Laurent602b3282011-03-18 08:33:14 -0700646 if (replySize != 0 && jReplyData != NULL) {
Eric Laurent948235c2010-06-09 00:17:29 -0700647 pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
648 if (pReplyData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000649 ALOGE("setParameter: Error retrieving reply pointer");
Eric Laurent948235c2010-06-09 00:17:29 -0700650 goto command_Exit;
651 }
652 }
653
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -0800654 lStatus = AudioEffectJni::translateNativeErrorToJava(
655 lpAudioEffect->command((uint32_t)cmdCode,
656 (uint32_t)cmdSize,
657 pCmdData,
658 (uint32_t *)&replySize,
659 pReplyData));
Eric Laurent948235c2010-06-09 00:17:29 -0700660
661command_Exit:
662
663 if (pCmdData != NULL) {
664 env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
665 }
666 if (pReplyData != NULL) {
667 env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
668 }
Eric Laurent948235c2010-06-09 00:17:29 -0700669
Eric Laurent602b3282011-03-18 08:33:14 -0700670 if (lStatus == NO_ERROR) {
671 return replySize;
672 }
Eric Laurent948235c2010-06-09 00:17:29 -0700673 return lStatus;
674}
675
676static jobjectArray
Eric Laurent4fc28d72014-09-10 15:05:03 -0700677android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz __unused)
Eric Laurent948235c2010-06-09 00:17:29 -0700678{
679 effect_descriptor_t desc;
Eric Laurent4fc28d72014-09-10 15:05:03 -0700680 uint32_t totalEffectsCount = 0;
681 uint32_t returnedEffectsCount = 0;
Eric Laurent948235c2010-06-09 00:17:29 -0700682 uint32_t i = 0;
Eric Laurent4fc28d72014-09-10 15:05:03 -0700683 jobjectArray ret;
Eric Laurent948235c2010-06-09 00:17:29 -0700684
Eric Laurent4fc28d72014-09-10 15:05:03 -0700685 if (AudioEffect::queryNumberEffects(&totalEffectsCount) != NO_ERROR) {
Peter Karlsson4526f0d2012-11-16 16:14:15 +0100686 return NULL;
687 }
688
Eric Laurent7c31847e2018-11-29 14:33:56 -0800689 jobjectArray temp = env->NewObjectArray(totalEffectsCount, audioEffectDescriptorClass(), NULL);
Eric Laurent4fc28d72014-09-10 15:05:03 -0700690 if (temp == NULL) {
691 return temp;
Eric Laurent948235c2010-06-09 00:17:29 -0700692 }
693
Eric Laurent4fc28d72014-09-10 15:05:03 -0700694 ALOGV("queryEffects() totalEffectsCount: %d", totalEffectsCount);
Eric Laurent948235c2010-06-09 00:17:29 -0700695
Eric Laurent4fc28d72014-09-10 15:05:03 -0700696 for (i = 0; i < totalEffectsCount; i++) {
Eric Laurent53334cd2010-06-23 17:38:20 -0700697 if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
Eric Laurent948235c2010-06-09 00:17:29 -0700698 goto queryEffects_failure;
699 }
700
Eric Laurent7c31847e2018-11-29 14:33:56 -0800701 jobject jdesc;
702 if (convertAudioEffectDescriptorFromNative(env, &jdesc, &desc) != AUDIO_JAVA_SUCCESS) {
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700703 continue;
704 }
Eric Laurent4fc28d72014-09-10 15:05:03 -0700705 env->SetObjectArrayElement(temp, returnedEffectsCount++, jdesc);
Eric Laurent7c31847e2018-11-29 14:33:56 -0800706 env->DeleteLocalRef(jdesc);
707 }
Eric Laurent948235c2010-06-09 00:17:29 -0700708
Eric Laurent4fc28d72014-09-10 15:05:03 -0700709 if (returnedEffectsCount == 0) {
710 goto queryEffects_failure;
711 }
Eric Laurent7c31847e2018-11-29 14:33:56 -0800712 ret = env->NewObjectArray(returnedEffectsCount, audioEffectDescriptorClass(), NULL);
Eric Laurent4fc28d72014-09-10 15:05:03 -0700713 if (ret == NULL) {
714 goto queryEffects_failure;
715 }
716 for (i = 0; i < returnedEffectsCount; i++) {
717 env->SetObjectArrayElement(ret, i, env->GetObjectArrayElement(temp, i));
718 }
719 env->DeleteLocalRef(temp);
Eric Laurent948235c2010-06-09 00:17:29 -0700720 return ret;
721
722queryEffects_failure:
723
Eric Laurent4fc28d72014-09-10 15:05:03 -0700724 if (temp != NULL) {
725 env->DeleteLocalRef(temp);
Eric Laurent948235c2010-06-09 00:17:29 -0700726 }
727 return NULL;
728
729}
730
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700731
732
733static jobjectArray
Eric Laurent4fc28d72014-09-10 15:05:03 -0700734android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz __unused,
735 jint audioSession)
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700736{
Andy Hung10701192018-08-21 14:29:33 -0700737 auto descriptors = std::make_unique<effect_descriptor_t[]>(AudioEffect::kMaxPreProcessing);
Eric Laurentb27a8a52014-11-05 12:18:05 -0800738 uint32_t numEffects = AudioEffect::kMaxPreProcessing;
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700739
Glenn Kasten33b84042016-03-08 12:02:55 -0800740 status_t status = AudioEffect::queryDefaultPreProcessing((audio_session_t) audioSession,
Andy Hung10701192018-08-21 14:29:33 -0700741 descriptors.get(),
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700742 &numEffects);
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700743 if (status != NO_ERROR || numEffects == 0) {
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700744 return NULL;
745 }
Steve Block71f2cf12011-10-20 11:56:00 +0100746 ALOGV("queryDefaultPreProcessing() got %d effects", numEffects);
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700747
Eric Laurent7c31847e2018-11-29 14:33:56 -0800748 std::vector<effect_descriptor_t> descVector(descriptors.get(), descriptors.get() + numEffects);
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700749
Eric Laurent7c31847e2018-11-29 14:33:56 -0800750 jobjectArray ret;
751 convertAudioEffectDescriptorVectorFromNative(env, &ret, descVector);
752 return ret;
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700753}
754
Eric Laurent948235c2010-06-09 00:17:29 -0700755// ----------------------------------------------------------------------------
756
757// Dalvik VM type signatures
Daniel Micay76f6a862015-09-19 17:31:01 -0400758static const JNINativeMethod gMethods[] = {
Eric Laurent948235c2010-06-09 00:17:29 -0700759 {"native_init", "()V", (void *)android_media_AudioEffect_native_init},
Svet Ganovfa5ecdc2015-04-28 12:03:28 -0700760 {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I",
Eric Laurent948235c2010-06-09 00:17:29 -0700761 (void *)android_media_AudioEffect_native_setup},
762 {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize},
763 {"native_release", "()V", (void *)android_media_AudioEffect_native_release},
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700764 {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled},
765 {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled},
Eric Laurent948235c2010-06-09 00:17:29 -0700766 {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
767 {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
Eric Laurent602b3282011-03-18 08:33:14 -0700768 {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter},
769 {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command},
Eric Laurent948235c2010-06-09 00:17:29 -0700770 {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
Eric Laurent0f7f4ec2011-07-24 13:36:09 -0700771 {"native_query_pre_processing", "(I)[Ljava/lang/Object;",
772 (void *)android_media_AudioEffect_native_queryPreProcessings},
Eric Laurent948235c2010-06-09 00:17:29 -0700773};
774
775
776// ----------------------------------------------------------------------------
777
Ari Hausman-Cohena555e742018-08-13 14:12:35 -0700778extern int register_android_media_SourceDefaultEffect(JNIEnv *env);
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -0800779extern int register_android_media_StreamDefaultEffect(JNIEnv *env);
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700780extern int register_android_media_visualizer(JNIEnv *env);
781
Eric Laurent948235c2010-06-09 00:17:29 -0700782int register_android_media_AudioEffect(JNIEnv *env)
783{
784 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
785}
786
Eric Laurent4fc28d72014-09-10 15:05:03 -0700787jint JNI_OnLoad(JavaVM* vm, void* reserved __unused)
Eric Laurent948235c2010-06-09 00:17:29 -0700788{
789
790 JNIEnv* env = NULL;
791 jint result = -1;
792
793 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
Steve Block3762c312012-01-06 19:20:56 +0000794 ALOGE("ERROR: GetEnv failed\n");
Eric Laurent948235c2010-06-09 00:17:29 -0700795 goto bail;
796 }
797 assert(env != NULL);
798
799 if (register_android_media_AudioEffect(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000800 ALOGE("ERROR: AudioEffect native registration failed\n");
Eric Laurent948235c2010-06-09 00:17:29 -0700801 goto bail;
802 }
803
Ari Hausman-Cohena555e742018-08-13 14:12:35 -0700804 if (register_android_media_SourceDefaultEffect(env) < 0) {
805 ALOGE("ERROR: SourceDefaultEffect native registration failed\n");
806 goto bail;
807 }
808
Ari Hausman-Cohen7d54c5d2018-01-10 16:58:18 -0800809 if (register_android_media_StreamDefaultEffect(env) < 0) {
810 ALOGE("ERROR: StreamDefaultEffect native registration failed\n");
811 goto bail;
812 }
813
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700814 if (register_android_media_visualizer(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000815 ALOGE("ERROR: Visualizer native registration failed\n");
Eric Laurentdf9b81c2010-07-02 08:12:41 -0700816 goto bail;
817 }
818
Eric Laurent948235c2010-06-09 00:17:29 -0700819 /* success -- return valid version number */
820 result = JNI_VERSION_1_4;
821
822bail:
823 return result;
824}