1 /* 2 * Copyright 2017, 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 #ifndef _ANDROID_MEDIA_VOLUME_SHAPER_H_ 18 #define _ANDROID_MEDIA_VOLUME_SHAPER_H_ 19 20 #include <media/VolumeShaper.h> 21 22 namespace android { 23 24 // This entire class is inline as it is used from both core and media 25 struct VolumeShaperHelper { 26 struct fields_t { 27 // VolumeShaper.Configuration 28 jclass coClazz; 29 jmethodID coConstructId; 30 jfieldID coTypeId; 31 jfieldID coIdId; 32 jfieldID coOptionFlagsId; 33 jfieldID coDurationMsId; 34 jfieldID coInterpolatorTypeId; 35 jfieldID coTimesId; 36 jfieldID coVolumesId; 37 38 // VolumeShaper.Operation 39 jclass opClazz; 40 jmethodID opConstructId; 41 jfieldID opFlagsId; 42 jfieldID opReplaceIdId; 43 jfieldID opXOffsetId; 44 45 // VolumeShaper.State 46 jclass stClazz; 47 jmethodID stConstructId; 48 jfieldID stVolumeId; 49 jfieldID stXOffsetId; 50 initVolumeShaperHelper::fields_t51 void init(JNIEnv *env) { 52 jclass lclazz = env->FindClass("android/media/VolumeShaper$Configuration"); 53 if (lclazz == nullptr) { 54 return; 55 } 56 coClazz = (jclass)env->NewGlobalRef(lclazz); 57 if (coClazz == nullptr) { 58 return; 59 } 60 coConstructId = env->GetMethodID(coClazz, "<init>", "(IIIDI[F[F)V"); 61 coTypeId = env->GetFieldID(coClazz, "mType", "I"); 62 coIdId = env->GetFieldID(coClazz, "mId", "I"); 63 coOptionFlagsId = env->GetFieldID(coClazz, "mOptionFlags", "I"); 64 coDurationMsId = env->GetFieldID(coClazz, "mDurationMs", "D"); 65 coInterpolatorTypeId = env->GetFieldID(coClazz, "mInterpolatorType", "I"); 66 coTimesId = env->GetFieldID(coClazz, "mTimes", "[F"); 67 coVolumesId = env->GetFieldID(coClazz, "mVolumes", "[F"); 68 env->DeleteLocalRef(lclazz); 69 70 lclazz = env->FindClass("android/media/VolumeShaper$Operation"); 71 if (lclazz == nullptr) { 72 return; 73 } 74 opClazz = (jclass)env->NewGlobalRef(lclazz); 75 if (opClazz == nullptr) { 76 return; 77 } 78 opConstructId = env->GetMethodID(opClazz, "<init>", "(IIF)V"); 79 opFlagsId = env->GetFieldID(opClazz, "mFlags", "I"); 80 opReplaceIdId = env->GetFieldID(opClazz, "mReplaceId", "I"); 81 opXOffsetId = env->GetFieldID(opClazz, "mXOffset", "F"); 82 env->DeleteLocalRef(lclazz); 83 84 lclazz = env->FindClass("android/media/VolumeShaper$State"); 85 if (lclazz == nullptr) { 86 return; 87 } 88 stClazz = (jclass)env->NewGlobalRef(lclazz); 89 if (stClazz == nullptr) { 90 return; 91 } 92 stConstructId = env->GetMethodID(stClazz, "<init>", "(FF)V"); 93 stVolumeId = env->GetFieldID(stClazz, "mVolume", "F"); 94 stXOffsetId = env->GetFieldID(stClazz, "mXOffset", "F"); 95 env->DeleteLocalRef(lclazz); 96 } 97 exitVolumeShaperHelper::fields_t98 void exit(JNIEnv *env) { 99 env->DeleteGlobalRef(coClazz); 100 coClazz = nullptr; 101 } 102 }; 103 convertJobjectToConfigurationVolumeShaperHelper104 static sp<VolumeShaper::Configuration> convertJobjectToConfiguration( 105 JNIEnv *env, const fields_t &fields, jobject jshaper) { 106 sp<VolumeShaper::Configuration> configuration = new VolumeShaper::Configuration(); 107 108 configuration->setType( 109 (VolumeShaper::Configuration::Type)env->GetIntField(jshaper, fields.coTypeId)); 110 configuration->setId( 111 (int)env->GetIntField(jshaper, fields.coIdId)); 112 if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) { 113 configuration->setOptionFlags( 114 (VolumeShaper::Configuration::OptionFlag) 115 env->GetIntField(jshaper, fields.coOptionFlagsId)); 116 configuration->setDurationMs( 117 (double)env->GetDoubleField(jshaper, fields.coDurationMsId)); 118 configuration->setInterpolatorType( 119 (VolumeShaper::Configuration::InterpolatorType) 120 env->GetIntField(jshaper, fields.coInterpolatorTypeId)); 121 122 // convert point arrays 123 jobject xobj = env->GetObjectField(jshaper, fields.coTimesId); 124 jfloatArray *xarray = reinterpret_cast<jfloatArray*>(&xobj); 125 jsize xlen = env->GetArrayLength(*xarray); 126 /* const */ float * const x = 127 env->GetFloatArrayElements(*xarray, nullptr /* isCopy */); 128 jobject yobj = env->GetObjectField(jshaper, fields.coVolumesId); 129 jfloatArray *yarray = reinterpret_cast<jfloatArray*>(&yobj); 130 jsize ylen = env->GetArrayLength(*yarray); 131 /* const */ float * const y = 132 env->GetFloatArrayElements(*yarray, nullptr /* isCopy */); 133 if (xlen != ylen) { 134 ALOGE("array size must match"); 135 return nullptr; 136 } 137 for (jsize i = 0; i < xlen; ++i) { 138 configuration->emplace(x[i], y[i]); 139 } 140 env->ReleaseFloatArrayElements(*xarray, x, JNI_ABORT); // no need to copy back 141 env->ReleaseFloatArrayElements(*yarray, y, JNI_ABORT); 142 } 143 return configuration; 144 } 145 convertVolumeShaperToJobjectVolumeShaperHelper146 static jobject convertVolumeShaperToJobject( 147 JNIEnv *env, const fields_t &fields, 148 const sp<VolumeShaper::Configuration> &configuration) { 149 jfloatArray xarray = nullptr; 150 jfloatArray yarray = nullptr; 151 if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) { 152 // convert curve arrays 153 jfloatArray xarray = env->NewFloatArray(configuration->size()); 154 jfloatArray yarray = env->NewFloatArray(configuration->size()); 155 float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */); 156 float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */); 157 float *xptr = x, *yptr = y; 158 for (const auto &pt : *configuration.get()) { 159 *xptr++ = pt.first; 160 *yptr++ = pt.second; 161 } 162 env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */); 163 env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */); 164 } 165 166 // prepare constructor args 167 jvalue args[7]; 168 args[0].i = (jint)configuration->getType(); 169 args[1].i = (jint)configuration->getId(); 170 args[2].i = (jint)configuration->getOptionFlags(); 171 args[3].d = (jdouble)configuration->getDurationMs(); 172 args[4].i = (jint)configuration->getInterpolatorType(); 173 args[5].l = xarray; 174 args[6].l = yarray; 175 jobject jshaper = env->NewObjectA(fields.coClazz, fields.coConstructId, args); 176 return jshaper; 177 } 178 convertJobjectToOperationVolumeShaperHelper179 static sp<VolumeShaper::Operation> convertJobjectToOperation( 180 JNIEnv *env, const fields_t &fields, jobject joperation) { 181 VolumeShaper::Operation::Flag flags = 182 (VolumeShaper::Operation::Flag)env->GetIntField(joperation, fields.opFlagsId); 183 int replaceId = env->GetIntField(joperation, fields.opReplaceIdId); 184 float xOffset = env->GetFloatField(joperation, fields.opXOffsetId); 185 186 sp<VolumeShaper::Operation> operation = 187 new VolumeShaper::Operation(flags, replaceId, xOffset); 188 return operation; 189 } 190 convertOperationToJobjectVolumeShaperHelper191 static jobject convertOperationToJobject( 192 JNIEnv *env, const fields_t &fields, const sp<VolumeShaper::Operation> &operation) { 193 // prepare constructor args 194 jvalue args[3]; 195 args[0].i = (jint)operation->getFlags(); 196 args[1].i = (jint)operation->getReplaceId(); 197 args[2].f = (jfloat)operation->getXOffset(); 198 199 jobject joperation = env->NewObjectA(fields.opClazz, fields.opConstructId, args); 200 return joperation; 201 } 202 convertJobjectToStateVolumeShaperHelper203 static sp<VolumeShaper::State> convertJobjectToState( 204 JNIEnv *env, const fields_t &fields, jobject jstate) { 205 float volume = env->GetFloatField(jstate, fields.stVolumeId); 206 float xOffset = env->GetFloatField(jstate, fields.stXOffsetId); 207 208 sp<VolumeShaper::State> state = new VolumeShaper::State(volume, xOffset); 209 return state; 210 } 211 convertStateToJobjectVolumeShaperHelper212 static jobject convertStateToJobject( 213 JNIEnv *env, const fields_t &fields, const sp<VolumeShaper::State> &state) { 214 // prepare constructor args 215 jvalue args[2]; 216 args[0].f = (jfloat)state->getVolume(); 217 args[1].f = (jfloat)state->getXOffset(); 218 219 jobject jstate = env->NewObjectA(fields.stClazz, fields.stConstructId, args); 220 return jstate; 221 } 222 }; 223 224 } // namespace android 225 226 #endif // _ANDROID_MEDIA_VOLUME_SHAPER_H_ 227