850 lines
27 KiB
C++
850 lines
27 KiB
C++
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
//#define LOG_NDEBUG 0
|
|
#define LOG_TAG "AudioEffects-JNI"
|
|
|
|
#include <utils/Log.h>
|
|
#include <nativehelper/jni.h>
|
|
#include <nativehelper/JNIHelp.h>
|
|
#include <android_runtime/AndroidRuntime.h>
|
|
#include "media/AudioEffect.h"
|
|
|
|
using namespace android;
|
|
|
|
#define AUDIOEFFECT_SUCCESS 0
|
|
#define AUDIOEFFECT_ERROR -1
|
|
#define AUDIOEFFECT_ERROR_ALREADY_EXISTS -2
|
|
#define AUDIOEFFECT_ERROR_NO_INIT -3
|
|
#define AUDIOEFFECT_ERROR_BAD_VALUE -4
|
|
#define AUDIOEFFECT_ERROR_INVALID_OPERATION -5
|
|
#define AUDIOEFFECT_ERROR_NO_MEMORY -6
|
|
#define AUDIOEFFECT_ERROR_DEAD_OBJECT -7
|
|
|
|
// ----------------------------------------------------------------------------
|
|
static const char* const kClassPathName = "android/media/audiofx/AudioEffect";
|
|
|
|
struct fields_t {
|
|
// these fields provide access from C++ to the...
|
|
jclass clazzEffect; // AudioEffect class
|
|
jmethodID midPostNativeEvent; // event post callback method
|
|
jfieldID fidNativeAudioEffect; // stores in Java the native AudioEffect object
|
|
jfieldID fidJniData; // stores in Java additional resources used by the native AudioEffect
|
|
jclass clazzDesc; // AudioEffect.Descriptor class
|
|
jmethodID midDescCstor; // AudioEffect.Descriptor class constructor
|
|
};
|
|
static fields_t fields;
|
|
|
|
struct effect_callback_cookie {
|
|
jclass audioEffect_class; // AudioEffect class
|
|
jobject audioEffect_ref; // AudioEffect object instance
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
class AudioEffectJniStorage {
|
|
public:
|
|
effect_callback_cookie mCallbackData;
|
|
|
|
AudioEffectJniStorage() {
|
|
}
|
|
|
|
~AudioEffectJniStorage() {
|
|
}
|
|
|
|
};
|
|
|
|
|
|
static jint translateError(int code) {
|
|
switch(code) {
|
|
case NO_ERROR:
|
|
return AUDIOEFFECT_SUCCESS;
|
|
case ALREADY_EXISTS:
|
|
return AUDIOEFFECT_ERROR_ALREADY_EXISTS;
|
|
case NO_INIT:
|
|
return AUDIOEFFECT_ERROR_NO_INIT;
|
|
case BAD_VALUE:
|
|
return AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
case INVALID_OPERATION:
|
|
return AUDIOEFFECT_ERROR_INVALID_OPERATION;
|
|
case NO_MEMORY:
|
|
return AUDIOEFFECT_ERROR_NO_MEMORY;
|
|
case DEAD_OBJECT:
|
|
return AUDIOEFFECT_ERROR_DEAD_OBJECT;
|
|
default:
|
|
return AUDIOEFFECT_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
static void effectCallback(int event, void* user, void *info) {
|
|
|
|
effect_param_t *p;
|
|
int arg1 = 0;
|
|
int arg2 = 0;
|
|
jobject obj = NULL;
|
|
jbyteArray array = NULL;
|
|
jbyte *bytes;
|
|
bool param;
|
|
size_t size;
|
|
|
|
effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
|
|
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
|
|
|
LOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
|
|
callbackInfo,
|
|
callbackInfo->audioEffect_ref,
|
|
callbackInfo->audioEffect_class);
|
|
|
|
if (!user || !env) {
|
|
LOGW("effectCallback error user %p, env %p", user, env);
|
|
return;
|
|
}
|
|
|
|
switch (event) {
|
|
case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
|
|
if (info == 0) {
|
|
LOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
|
|
goto effectCallback_Exit;
|
|
}
|
|
param = *(bool *)info;
|
|
arg1 = (int)param;
|
|
LOGV("EVENT_CONTROL_STATUS_CHANGED");
|
|
break;
|
|
case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
|
|
if (info == 0) {
|
|
LOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
|
|
goto effectCallback_Exit;
|
|
}
|
|
param = *(bool *)info;
|
|
arg1 = (int)param;
|
|
LOGV("EVENT_ENABLE_STATUS_CHANGED");
|
|
break;
|
|
case AudioEffect::EVENT_PARAMETER_CHANGED:
|
|
if (info == 0) {
|
|
LOGW("EVENT_PARAMETER_CHANGED info == NULL");
|
|
goto effectCallback_Exit;
|
|
}
|
|
p = (effect_param_t *)info;
|
|
if (p->psize == 0 || p->vsize == 0) {
|
|
goto effectCallback_Exit;
|
|
}
|
|
// arg1 contains offset of parameter value from start of byte array
|
|
arg1 = sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) + 1) * sizeof(int);
|
|
size = arg1 + p->vsize;
|
|
array = env->NewByteArray(size);
|
|
if (array == NULL) {
|
|
LOGE("effectCallback: Couldn't allocate byte array for parameter data");
|
|
goto effectCallback_Exit;
|
|
}
|
|
bytes = env->GetByteArrayElements(array, NULL);
|
|
memcpy(bytes, p, size);
|
|
env->ReleaseByteArrayElements(array, bytes, 0);
|
|
obj = array;
|
|
LOGV("EVENT_PARAMETER_CHANGED");
|
|
break;
|
|
case AudioEffect::EVENT_ERROR:
|
|
LOGW("EVENT_ERROR");
|
|
break;
|
|
}
|
|
|
|
env->CallStaticVoidMethod(
|
|
callbackInfo->audioEffect_class,
|
|
fields.midPostNativeEvent,
|
|
callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
|
|
|
|
effectCallback_Exit:
|
|
if (array) {
|
|
env->DeleteLocalRef(array);
|
|
}
|
|
|
|
if (env->ExceptionCheck()) {
|
|
env->ExceptionDescribe();
|
|
env->ExceptionClear();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// This function gets some field IDs, which in turn causes class initialization.
|
|
// It is called from a static block in AudioEffect, which won't run until the
|
|
// first time an instance of this class is used.
|
|
static void
|
|
android_media_AudioEffect_native_init(JNIEnv *env)
|
|
{
|
|
|
|
LOGV("android_media_AudioEffect_native_init");
|
|
|
|
fields.clazzEffect = NULL;
|
|
fields.clazzDesc = NULL;
|
|
|
|
// Get the AudioEffect class
|
|
jclass clazz = env->FindClass(kClassPathName);
|
|
if (clazz == NULL) {
|
|
LOGE("Can't find %s", kClassPathName);
|
|
return;
|
|
}
|
|
|
|
fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
|
|
|
|
// Get the postEvent method
|
|
fields.midPostNativeEvent = env->GetStaticMethodID(
|
|
fields.clazzEffect,
|
|
"postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
|
|
if (fields.midPostNativeEvent == NULL) {
|
|
LOGE("Can't find AudioEffect.%s", "postEventFromNative");
|
|
return;
|
|
}
|
|
|
|
// Get the variables fields
|
|
// nativeTrackInJavaObj
|
|
fields.fidNativeAudioEffect = env->GetFieldID(
|
|
fields.clazzEffect,
|
|
"mNativeAudioEffect", "I");
|
|
if (fields.fidNativeAudioEffect == NULL) {
|
|
LOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
|
|
return;
|
|
}
|
|
// fidJniData;
|
|
fields.fidJniData = env->GetFieldID(
|
|
fields.clazzEffect,
|
|
"mJniData", "I");
|
|
if (fields.fidJniData == NULL) {
|
|
LOGE("Can't find AudioEffect.%s", "mJniData");
|
|
return;
|
|
}
|
|
|
|
clazz = env->FindClass("android/media/audiofx/AudioEffect$Descriptor");
|
|
if (clazz == NULL) {
|
|
LOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class");
|
|
return;
|
|
}
|
|
fields.clazzDesc = (jclass)env->NewGlobalRef(clazz);
|
|
|
|
fields.midDescCstor
|
|
= env->GetMethodID(
|
|
fields.clazzDesc,
|
|
"<init>",
|
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
|
if (fields.midDescCstor == NULL) {
|
|
LOGE("Can't find android/media/audiofx/AudioEffect$Descriptor class constructor");
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
static jint
|
|
android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
|
|
jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)
|
|
{
|
|
LOGV("android_media_AudioEffect_native_setup");
|
|
AudioEffectJniStorage* lpJniStorage = NULL;
|
|
int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
|
|
AudioEffect* lpAudioEffect = NULL;
|
|
jint* nId = NULL;
|
|
const char *typeStr = NULL;
|
|
const char *uuidStr = NULL;
|
|
effect_descriptor_t desc;
|
|
jobject jdesc;
|
|
char str[EFFECT_STRING_LEN_MAX];
|
|
jstring jdescType;
|
|
jstring jdescUuid;
|
|
jstring jdescConnect;
|
|
jstring jdescName;
|
|
jstring jdescImplementor;
|
|
|
|
if (type != NULL) {
|
|
typeStr = env->GetStringUTFChars(type, NULL);
|
|
if (typeStr == NULL) { // Out of memory
|
|
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
|
|
goto setup_failure;
|
|
}
|
|
}
|
|
|
|
if (uuid != NULL) {
|
|
uuidStr = env->GetStringUTFChars(uuid, NULL);
|
|
if (uuidStr == NULL) { // Out of memory
|
|
jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
|
|
goto setup_failure;
|
|
}
|
|
}
|
|
|
|
if (typeStr == NULL && uuidStr == NULL) {
|
|
lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
goto setup_failure;
|
|
}
|
|
|
|
lpJniStorage = new AudioEffectJniStorage();
|
|
if (lpJniStorage == NULL) {
|
|
LOGE("setup: Error creating JNI Storage");
|
|
goto setup_failure;
|
|
}
|
|
|
|
lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
|
|
// we use a weak reference so the AudioEffect object can be garbage collected.
|
|
lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
|
|
|
|
LOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
|
|
lpJniStorage,
|
|
lpJniStorage->mCallbackData.audioEffect_ref,
|
|
lpJniStorage->mCallbackData.audioEffect_class,
|
|
&lpJniStorage->mCallbackData);
|
|
|
|
if (jId == NULL) {
|
|
LOGE("setup: NULL java array for id pointer");
|
|
lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
goto setup_failure;
|
|
}
|
|
|
|
// create the native AudioEffect object
|
|
lpAudioEffect = new AudioEffect(typeStr,
|
|
uuidStr,
|
|
priority,
|
|
effectCallback,
|
|
&lpJniStorage->mCallbackData,
|
|
sessionId,
|
|
0);
|
|
if (lpAudioEffect == NULL) {
|
|
LOGE("Error creating AudioEffect");
|
|
goto setup_failure;
|
|
}
|
|
|
|
lStatus = translateError(lpAudioEffect->initCheck());
|
|
if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
|
|
LOGE("AudioEffect initCheck failed %d", lStatus);
|
|
goto setup_failure;
|
|
}
|
|
|
|
nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
|
|
if (nId == NULL) {
|
|
LOGE("setup: Error retrieving id pointer");
|
|
lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
goto setup_failure;
|
|
}
|
|
nId[0] = lpAudioEffect->id();
|
|
env->ReleasePrimitiveArrayCritical(jId, nId, 0);
|
|
nId = NULL;
|
|
|
|
if (typeStr) {
|
|
env->ReleaseStringUTFChars(type, typeStr);
|
|
typeStr = NULL;
|
|
}
|
|
|
|
if (uuidStr) {
|
|
env->ReleaseStringUTFChars(uuid, uuidStr);
|
|
uuidStr = NULL;
|
|
}
|
|
|
|
// get the effect descriptor
|
|
desc = lpAudioEffect->descriptor();
|
|
|
|
AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
|
|
jdescType = env->NewStringUTF(str);
|
|
|
|
AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
|
|
jdescUuid = env->NewStringUTF(str);
|
|
|
|
if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
|
jdescConnect = env->NewStringUTF("Auxiliary");
|
|
} else {
|
|
jdescConnect = env->NewStringUTF("Insert");
|
|
}
|
|
|
|
jdescName = env->NewStringUTF(desc.name);
|
|
jdescImplementor = env->NewStringUTF(desc.implementor);
|
|
|
|
jdesc = env->NewObject(fields.clazzDesc,
|
|
fields.midDescCstor,
|
|
jdescType,
|
|
jdescUuid,
|
|
jdescConnect,
|
|
jdescName,
|
|
jdescImplementor);
|
|
env->DeleteLocalRef(jdescType);
|
|
env->DeleteLocalRef(jdescUuid);
|
|
env->DeleteLocalRef(jdescConnect);
|
|
env->DeleteLocalRef(jdescName);
|
|
env->DeleteLocalRef(jdescImplementor);
|
|
if (jdesc == NULL) {
|
|
LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
|
|
goto setup_failure;
|
|
}
|
|
|
|
env->SetObjectArrayElement(javadesc, 0, jdesc);
|
|
|
|
env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);
|
|
|
|
env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
|
|
|
|
return AUDIOEFFECT_SUCCESS;
|
|
|
|
// failures:
|
|
setup_failure:
|
|
|
|
if (nId != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(jId, nId, 0);
|
|
}
|
|
|
|
if (lpAudioEffect) {
|
|
delete lpAudioEffect;
|
|
}
|
|
env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
|
|
|
|
if (lpJniStorage) {
|
|
delete lpJniStorage;
|
|
}
|
|
env->SetIntField(thiz, fields.fidJniData, 0);
|
|
|
|
if (uuidStr != NULL) {
|
|
env->ReleaseStringUTFChars(uuid, uuidStr);
|
|
}
|
|
|
|
if (typeStr != NULL) {
|
|
env->ReleaseStringUTFChars(type, typeStr);
|
|
}
|
|
|
|
return lStatus;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
static void android_media_AudioEffect_native_finalize(JNIEnv *env, jobject thiz) {
|
|
LOGV("android_media_AudioEffect_native_finalize jobject: %x\n", (int)thiz);
|
|
|
|
// delete the AudioEffect object
|
|
AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
|
|
thiz, fields.fidNativeAudioEffect);
|
|
if (lpAudioEffect) {
|
|
LOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
|
|
delete lpAudioEffect;
|
|
}
|
|
|
|
// delete the JNI data
|
|
AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
|
|
thiz, fields.fidJniData);
|
|
if (lpJniStorage) {
|
|
LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
|
|
delete lpJniStorage;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
static void android_media_AudioEffect_native_release(JNIEnv *env, jobject thiz) {
|
|
|
|
// do everything a call to finalize would
|
|
android_media_AudioEffect_native_finalize(env, thiz);
|
|
// + reset the native resources in the Java object so any attempt to access
|
|
// them after a call to release fails.
|
|
env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
|
|
env->SetIntField(thiz, fields.fidJniData, 0);
|
|
}
|
|
|
|
static jint
|
|
android_media_AudioEffect_native_setEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
|
|
{
|
|
// retrieve the AudioEffect object
|
|
AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
|
|
thiz, fields.fidNativeAudioEffect);
|
|
|
|
if (lpAudioEffect == NULL) {
|
|
jniThrowException(env, "java/lang/IllegalStateException",
|
|
"Unable to retrieve AudioEffect pointer for enable()");
|
|
return AUDIOEFFECT_ERROR_NO_INIT;
|
|
}
|
|
|
|
return translateError(lpAudioEffect->setEnabled(enabled));
|
|
}
|
|
|
|
static jboolean
|
|
android_media_AudioEffect_native_getEnabled(JNIEnv *env, jobject thiz)
|
|
{
|
|
// retrieve the AudioEffect object
|
|
AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
|
|
thiz, fields.fidNativeAudioEffect);
|
|
|
|
if (lpAudioEffect == NULL) {
|
|
jniThrowException(env, "java/lang/IllegalStateException",
|
|
"Unable to retrieve AudioEffect pointer for getEnabled()");
|
|
return false;
|
|
}
|
|
|
|
return (jboolean)lpAudioEffect->getEnabled();
|
|
}
|
|
|
|
|
|
static jboolean
|
|
android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
|
|
{
|
|
// retrieve the AudioEffect object
|
|
AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
|
|
thiz, fields.fidNativeAudioEffect);
|
|
|
|
if (lpAudioEffect == NULL) {
|
|
jniThrowException(env, "java/lang/IllegalStateException",
|
|
"Unable to retrieve AudioEffect pointer for hasControl()");
|
|
return false;
|
|
}
|
|
|
|
if (lpAudioEffect->initCheck() == NO_ERROR) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
|
|
jobject thiz, int psize, jbyteArray pJavaParam, int vsize,
|
|
jbyteArray pJavaValue) {
|
|
// retrieve the AudioEffect object
|
|
jbyte* lpValue = NULL;
|
|
jbyte* lpParam = NULL;
|
|
jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
effect_param_t *p;
|
|
int voffset;
|
|
|
|
AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
|
|
fields.fidNativeAudioEffect);
|
|
|
|
if (lpAudioEffect == NULL) {
|
|
jniThrowException(env, "java/lang/IllegalStateException",
|
|
"Unable to retrieve AudioEffect pointer for setParameter()");
|
|
return AUDIOEFFECT_ERROR_NO_INIT;
|
|
}
|
|
|
|
if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
|
|
return AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
}
|
|
|
|
// get the pointer for the param from the java array
|
|
lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
|
|
if (lpParam == NULL) {
|
|
LOGE("setParameter: Error retrieving param pointer");
|
|
goto setParameter_Exit;
|
|
}
|
|
|
|
// get the pointer for the value from the java array
|
|
lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
|
|
if (lpValue == NULL) {
|
|
LOGE("setParameter: Error retrieving value pointer");
|
|
goto setParameter_Exit;
|
|
}
|
|
|
|
voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
|
|
p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
|
|
memcpy(p->data, lpParam, psize);
|
|
p->psize = psize;
|
|
memcpy(p->data + voffset, lpValue, vsize);
|
|
p->vsize = vsize;
|
|
|
|
lStatus = lpAudioEffect->setParameter(p);
|
|
if (lStatus == NO_ERROR) {
|
|
lStatus = p->status;
|
|
}
|
|
|
|
free(p);
|
|
|
|
setParameter_Exit:
|
|
|
|
if (lpParam != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
|
|
}
|
|
if (lpValue != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
|
|
}
|
|
return translateError(lStatus);
|
|
}
|
|
|
|
static jint
|
|
android_media_AudioEffect_native_getParameter(JNIEnv *env,
|
|
jobject thiz, int psize, jbyteArray pJavaParam,
|
|
jintArray pJavaValueSize, jbyteArray pJavaValue) {
|
|
// retrieve the AudioEffect object
|
|
jbyte* lpParam = NULL;
|
|
jbyte* lpValue = NULL;
|
|
jbyte* lpValueSize = NULL;
|
|
jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
effect_param_t *p;
|
|
int voffset;
|
|
|
|
AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
|
|
fields.fidNativeAudioEffect);
|
|
|
|
if (lpAudioEffect == NULL) {
|
|
jniThrowException(env, "java/lang/IllegalStateException",
|
|
"Unable to retrieve AudioEffect pointer for getParameter()");
|
|
return AUDIOEFFECT_ERROR_NO_INIT;
|
|
}
|
|
|
|
if (psize == 0 || pJavaValueSize == NULL || pJavaParam == NULL || pJavaValue == NULL) {
|
|
return AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
}
|
|
|
|
// get the pointer for the param from the java array
|
|
lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
|
|
if (lpParam == NULL) {
|
|
LOGE("getParameter: Error retrieving param pointer");
|
|
goto getParameter_Exit;
|
|
}
|
|
|
|
// get the pointer for the value from the java array
|
|
lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
|
|
if (lpValue == NULL) {
|
|
LOGE("getParameter: Error retrieving value pointer");
|
|
goto getParameter_Exit;
|
|
}
|
|
|
|
// get the pointer for the value size from the java array
|
|
lpValueSize = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValueSize, NULL);
|
|
if (lpValueSize == NULL) {
|
|
LOGE("getParameter: Error retrieving value size pointer");
|
|
goto getParameter_Exit;
|
|
}
|
|
|
|
voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
|
|
p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset
|
|
+ lpValueSize[0]);
|
|
memcpy(p->data, lpParam, psize);
|
|
p->psize = psize;
|
|
p->vsize = lpValueSize[0];
|
|
|
|
lStatus = lpAudioEffect->getParameter(p);
|
|
if (lStatus == NO_ERROR) {
|
|
lStatus = p->status;
|
|
if (lStatus == NO_ERROR) {
|
|
memcpy(lpValue, p->data + voffset, p->vsize);
|
|
lpValueSize[0] = p->vsize;
|
|
}
|
|
}
|
|
|
|
free(p);
|
|
|
|
getParameter_Exit:
|
|
|
|
if (lpParam != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
|
|
}
|
|
if (lpValue != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
|
|
}
|
|
if (lpValueSize != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(pJavaValueSize, lpValueSize, 0);
|
|
}
|
|
|
|
return translateError(lStatus);
|
|
}
|
|
|
|
static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
|
|
jint cmdCode, jint cmdSize, jbyteArray jCmdData, jintArray jReplySize,
|
|
jbyteArray jReplyData) {
|
|
jbyte* pCmdData = NULL;
|
|
jbyte* pReplyData = NULL;
|
|
jint* pReplySize = NULL;
|
|
jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
|
|
// retrieve the AudioEffect object
|
|
AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
|
|
fields.fidNativeAudioEffect);
|
|
|
|
if (lpAudioEffect == NULL) {
|
|
jniThrowException(env, "java/lang/IllegalStateException",
|
|
"Unable to retrieve AudioEffect pointer for setParameter()");
|
|
return AUDIOEFFECT_ERROR_NO_INIT;
|
|
}
|
|
|
|
if ((cmdSize != 0 && jCmdData == NULL) || (jReplySize != NULL && jReplyData == NULL)) {
|
|
return AUDIOEFFECT_ERROR_BAD_VALUE;
|
|
}
|
|
|
|
// get the pointer for the command from the java array
|
|
if (cmdSize != 0) {
|
|
pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
|
|
if (pCmdData == NULL) {
|
|
LOGE("setParameter: Error retrieving command pointer");
|
|
goto command_Exit;
|
|
}
|
|
}
|
|
|
|
// get the pointer for the reply size from the java array
|
|
if (jReplySize != NULL) {
|
|
pReplySize = (jint *) env->GetPrimitiveArrayCritical(jReplySize, NULL);
|
|
if (pReplySize == NULL) {
|
|
LOGE("setParameter: Error retrieving reply pointer");
|
|
goto command_Exit;
|
|
}
|
|
}
|
|
|
|
// get the pointer for the reply from the java array
|
|
if (pReplySize != NULL && pReplySize[0] != 0 && jReplyData != NULL) {
|
|
pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
|
|
if (pReplyData == NULL) {
|
|
LOGE("setParameter: Error retrieving reply pointer");
|
|
goto command_Exit;
|
|
}
|
|
}
|
|
|
|
lStatus = translateError(lpAudioEffect->command((uint32_t)cmdCode,
|
|
(uint32_t)cmdSize,
|
|
pCmdData,
|
|
(uint32_t *)pReplySize,
|
|
pReplyData));
|
|
|
|
command_Exit:
|
|
|
|
if (pCmdData != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
|
|
}
|
|
if (pReplyData != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
|
|
}
|
|
if (pReplySize != NULL) {
|
|
env->ReleasePrimitiveArrayCritical(jReplySize, pReplySize, 0);
|
|
}
|
|
|
|
return lStatus;
|
|
}
|
|
|
|
static jobjectArray
|
|
android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
|
|
{
|
|
effect_descriptor_t desc;
|
|
char str[EFFECT_STRING_LEN_MAX];
|
|
uint32_t numEffects;
|
|
uint32_t i = 0;
|
|
jstring jdescType;
|
|
jstring jdescUuid;
|
|
jstring jdescConnect;
|
|
jstring jdescName;
|
|
jstring jdescImplementor;
|
|
jobject jdesc;
|
|
|
|
AudioEffect::queryNumberEffects(&numEffects);
|
|
jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
|
|
if (ret == NULL) {
|
|
return ret;
|
|
}
|
|
|
|
LOGV("queryEffects() numEffects: %d", numEffects);
|
|
|
|
for (i = 0; i < numEffects; i++) {
|
|
if (AudioEffect::queryEffect(i, &desc) != NO_ERROR) {
|
|
goto queryEffects_failure;
|
|
}
|
|
|
|
AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
|
|
jdescType = env->NewStringUTF(str);
|
|
|
|
AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
|
|
jdescUuid = env->NewStringUTF(str);
|
|
|
|
if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
|
|
jdescConnect = env->NewStringUTF("Auxiliary");
|
|
} else {
|
|
jdescConnect = env->NewStringUTF("Insert");
|
|
}
|
|
|
|
jdescName = env->NewStringUTF(desc.name);
|
|
jdescImplementor = env->NewStringUTF(desc.implementor);
|
|
|
|
jdesc = env->NewObject(fields.clazzDesc,
|
|
fields.midDescCstor,
|
|
jdescType,
|
|
jdescUuid,
|
|
jdescConnect,
|
|
jdescName,
|
|
jdescImplementor);
|
|
env->DeleteLocalRef(jdescType);
|
|
env->DeleteLocalRef(jdescUuid);
|
|
env->DeleteLocalRef(jdescConnect);
|
|
env->DeleteLocalRef(jdescName);
|
|
env->DeleteLocalRef(jdescImplementor);
|
|
if (jdesc == NULL) {
|
|
LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
|
|
goto queryEffects_failure;
|
|
}
|
|
|
|
env->SetObjectArrayElement(ret, i, jdesc);
|
|
}
|
|
|
|
return ret;
|
|
|
|
queryEffects_failure:
|
|
|
|
if (ret != NULL) {
|
|
env->DeleteLocalRef(ret);
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Dalvik VM type signatures
|
|
static JNINativeMethod gMethods[] = {
|
|
{"native_init", "()V", (void *)android_media_AudioEffect_native_init},
|
|
{"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
|
|
(void *)android_media_AudioEffect_native_setup},
|
|
{"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize},
|
|
{"native_release", "()V", (void *)android_media_AudioEffect_native_release},
|
|
{"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled},
|
|
{"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled},
|
|
{"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl},
|
|
{"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter},
|
|
{"native_getParameter", "(I[B[I[B)I", (void *)android_media_AudioEffect_native_getParameter},
|
|
{"native_command", "(II[B[I[B)I", (void *)android_media_AudioEffect_native_command},
|
|
{"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
|
|
};
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
extern int register_android_media_visualizer(JNIEnv *env);
|
|
|
|
int register_android_media_AudioEffect(JNIEnv *env)
|
|
{
|
|
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
|
|
}
|
|
|
|
jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|
{
|
|
|
|
JNIEnv* env = NULL;
|
|
jint result = -1;
|
|
|
|
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
|
|
LOGE("ERROR: GetEnv failed\n");
|
|
goto bail;
|
|
}
|
|
assert(env != NULL);
|
|
|
|
if (register_android_media_AudioEffect(env) < 0) {
|
|
LOGE("ERROR: AudioEffect native registration failed\n");
|
|
goto bail;
|
|
}
|
|
|
|
if (register_android_media_visualizer(env) < 0) {
|
|
LOGE("ERROR: Visualizer native registration failed\n");
|
|
goto bail;
|
|
}
|
|
|
|
/* success -- return valid version number */
|
|
result = JNI_VERSION_1_4;
|
|
|
|
bail:
|
|
return result;
|
|
}
|
|
|