You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
9.2 KiB
229 lines
9.2 KiB
/*
|
|
* Copyright 2017, 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.
|
|
*/
|
|
|
|
#ifndef _ANDROID_MEDIA_VOLUME_SHAPER_H_
|
|
#define _ANDROID_MEDIA_VOLUME_SHAPER_H_
|
|
|
|
#include <media/VolumeShaper.h>
|
|
|
|
namespace android {
|
|
|
|
using media::VolumeShaper;
|
|
|
|
// This entire class is inline as it is used from both core and media
|
|
struct VolumeShaperHelper {
|
|
struct fields_t {
|
|
// VolumeShaper.Configuration
|
|
jclass coClazz;
|
|
jmethodID coConstructId;
|
|
jfieldID coTypeId;
|
|
jfieldID coIdId;
|
|
jfieldID coOptionFlagsId;
|
|
jfieldID coDurationMsId;
|
|
jfieldID coInterpolatorTypeId;
|
|
jfieldID coTimesId;
|
|
jfieldID coVolumesId;
|
|
|
|
// VolumeShaper.Operation
|
|
jclass opClazz;
|
|
jmethodID opConstructId;
|
|
jfieldID opFlagsId;
|
|
jfieldID opReplaceIdId;
|
|
jfieldID opXOffsetId;
|
|
|
|
// VolumeShaper.State
|
|
jclass stClazz;
|
|
jmethodID stConstructId;
|
|
jfieldID stVolumeId;
|
|
jfieldID stXOffsetId;
|
|
|
|
void init(JNIEnv *env) {
|
|
jclass lclazz = env->FindClass("android/media/VolumeShaper$Configuration");
|
|
if (lclazz == nullptr) {
|
|
return;
|
|
}
|
|
coClazz = (jclass)env->NewGlobalRef(lclazz);
|
|
if (coClazz == nullptr) {
|
|
return;
|
|
}
|
|
coConstructId = env->GetMethodID(coClazz, "<init>", "(IIIDI[F[F)V");
|
|
coTypeId = env->GetFieldID(coClazz, "mType", "I");
|
|
coIdId = env->GetFieldID(coClazz, "mId", "I");
|
|
coOptionFlagsId = env->GetFieldID(coClazz, "mOptionFlags", "I");
|
|
coDurationMsId = env->GetFieldID(coClazz, "mDurationMs", "D");
|
|
coInterpolatorTypeId = env->GetFieldID(coClazz, "mInterpolatorType", "I");
|
|
coTimesId = env->GetFieldID(coClazz, "mTimes", "[F");
|
|
coVolumesId = env->GetFieldID(coClazz, "mVolumes", "[F");
|
|
env->DeleteLocalRef(lclazz);
|
|
|
|
lclazz = env->FindClass("android/media/VolumeShaper$Operation");
|
|
if (lclazz == nullptr) {
|
|
return;
|
|
}
|
|
opClazz = (jclass)env->NewGlobalRef(lclazz);
|
|
if (opClazz == nullptr) {
|
|
return;
|
|
}
|
|
opConstructId = env->GetMethodID(opClazz, "<init>", "(IIF)V");
|
|
opFlagsId = env->GetFieldID(opClazz, "mFlags", "I");
|
|
opReplaceIdId = env->GetFieldID(opClazz, "mReplaceId", "I");
|
|
opXOffsetId = env->GetFieldID(opClazz, "mXOffset", "F");
|
|
env->DeleteLocalRef(lclazz);
|
|
|
|
lclazz = env->FindClass("android/media/VolumeShaper$State");
|
|
if (lclazz == nullptr) {
|
|
return;
|
|
}
|
|
stClazz = (jclass)env->NewGlobalRef(lclazz);
|
|
if (stClazz == nullptr) {
|
|
return;
|
|
}
|
|
stConstructId = env->GetMethodID(stClazz, "<init>", "(FF)V");
|
|
stVolumeId = env->GetFieldID(stClazz, "mVolume", "F");
|
|
stXOffsetId = env->GetFieldID(stClazz, "mXOffset", "F");
|
|
env->DeleteLocalRef(lclazz);
|
|
}
|
|
|
|
void exit(JNIEnv *env) {
|
|
env->DeleteGlobalRef(coClazz);
|
|
coClazz = nullptr;
|
|
}
|
|
};
|
|
|
|
static sp<VolumeShaper::Configuration> convertJobjectToConfiguration(
|
|
JNIEnv *env, const fields_t &fields, jobject jshaper) {
|
|
sp<VolumeShaper::Configuration> configuration = new VolumeShaper::Configuration();
|
|
|
|
configuration->setType(
|
|
(VolumeShaper::Configuration::Type)env->GetIntField(jshaper, fields.coTypeId));
|
|
configuration->setId(
|
|
(int)env->GetIntField(jshaper, fields.coIdId));
|
|
if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) {
|
|
configuration->setOptionFlags(
|
|
(VolumeShaper::Configuration::OptionFlag)
|
|
env->GetIntField(jshaper, fields.coOptionFlagsId));
|
|
configuration->setDurationMs(
|
|
(double)env->GetDoubleField(jshaper, fields.coDurationMsId));
|
|
configuration->setInterpolatorType(
|
|
(VolumeShaper::Configuration::InterpolatorType)
|
|
env->GetIntField(jshaper, fields.coInterpolatorTypeId));
|
|
|
|
// convert point arrays
|
|
jobject xobj = env->GetObjectField(jshaper, fields.coTimesId);
|
|
jfloatArray *xarray = reinterpret_cast<jfloatArray*>(&xobj);
|
|
jsize xlen = env->GetArrayLength(*xarray);
|
|
/* const */ float * const x =
|
|
env->GetFloatArrayElements(*xarray, nullptr /* isCopy */);
|
|
jobject yobj = env->GetObjectField(jshaper, fields.coVolumesId);
|
|
jfloatArray *yarray = reinterpret_cast<jfloatArray*>(&yobj);
|
|
jsize ylen = env->GetArrayLength(*yarray);
|
|
/* const */ float * const y =
|
|
env->GetFloatArrayElements(*yarray, nullptr /* isCopy */);
|
|
if (xlen != ylen) {
|
|
ALOGE("array size must match");
|
|
return nullptr;
|
|
}
|
|
for (jsize i = 0; i < xlen; ++i) {
|
|
configuration->emplace(x[i], y[i]);
|
|
}
|
|
env->ReleaseFloatArrayElements(*xarray, x, JNI_ABORT); // no need to copy back
|
|
env->ReleaseFloatArrayElements(*yarray, y, JNI_ABORT);
|
|
}
|
|
return configuration;
|
|
}
|
|
|
|
static jobject convertVolumeShaperToJobject(
|
|
JNIEnv *env, const fields_t &fields,
|
|
const sp<VolumeShaper::Configuration> &configuration) {
|
|
jfloatArray xarray = nullptr;
|
|
jfloatArray yarray = nullptr;
|
|
if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) {
|
|
// convert curve arrays
|
|
jfloatArray xarray = env->NewFloatArray(configuration->size());
|
|
jfloatArray yarray = env->NewFloatArray(configuration->size());
|
|
float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
|
|
float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
|
|
float *xptr = x, *yptr = y;
|
|
for (const auto &pt : *configuration.get()) {
|
|
*xptr++ = pt.first;
|
|
*yptr++ = pt.second;
|
|
}
|
|
env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
|
|
env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
|
|
}
|
|
|
|
// prepare constructor args
|
|
jvalue args[7];
|
|
args[0].i = (jint)configuration->getType();
|
|
args[1].i = (jint)configuration->getId();
|
|
args[2].i = (jint)configuration->getOptionFlags();
|
|
args[3].d = (jdouble)configuration->getDurationMs();
|
|
args[4].i = (jint)configuration->getInterpolatorType();
|
|
args[5].l = xarray;
|
|
args[6].l = yarray;
|
|
jobject jshaper = env->NewObjectA(fields.coClazz, fields.coConstructId, args);
|
|
return jshaper;
|
|
}
|
|
|
|
static sp<VolumeShaper::Operation> convertJobjectToOperation(
|
|
JNIEnv *env, const fields_t &fields, jobject joperation) {
|
|
VolumeShaper::Operation::Flag flags =
|
|
(VolumeShaper::Operation::Flag)env->GetIntField(joperation, fields.opFlagsId);
|
|
int replaceId = env->GetIntField(joperation, fields.opReplaceIdId);
|
|
float xOffset = env->GetFloatField(joperation, fields.opXOffsetId);
|
|
|
|
sp<VolumeShaper::Operation> operation =
|
|
new VolumeShaper::Operation(flags, replaceId, xOffset);
|
|
return operation;
|
|
}
|
|
|
|
static jobject convertOperationToJobject(
|
|
JNIEnv *env, const fields_t &fields, const sp<VolumeShaper::Operation> &operation) {
|
|
// prepare constructor args
|
|
jvalue args[3];
|
|
args[0].i = (jint)operation->getFlags();
|
|
args[1].i = (jint)operation->getReplaceId();
|
|
args[2].f = (jfloat)operation->getXOffset();
|
|
|
|
jobject joperation = env->NewObjectA(fields.opClazz, fields.opConstructId, args);
|
|
return joperation;
|
|
}
|
|
|
|
static sp<VolumeShaper::State> convertJobjectToState(
|
|
JNIEnv *env, const fields_t &fields, jobject jstate) {
|
|
float volume = env->GetFloatField(jstate, fields.stVolumeId);
|
|
float xOffset = env->GetFloatField(jstate, fields.stXOffsetId);
|
|
|
|
sp<VolumeShaper::State> state = new VolumeShaper::State(volume, xOffset);
|
|
return state;
|
|
}
|
|
|
|
static jobject convertStateToJobject(
|
|
JNIEnv *env, const fields_t &fields, const sp<VolumeShaper::State> &state) {
|
|
// prepare constructor args
|
|
jvalue args[2];
|
|
args[0].f = (jfloat)state->getVolume();
|
|
args[1].f = (jfloat)state->getXOffset();
|
|
|
|
jobject jstate = env->NewObjectA(fields.stClazz, fields.stConstructId, args);
|
|
return jstate;
|
|
}
|
|
};
|
|
|
|
} // namespace android
|
|
|
|
#endif // _ANDROID_MEDIA_VOLUME_SHAPER_H_
|