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