blob: 1171b467e64414d2bb86938254940508ad330ae0 [file] [log] [blame]
Andy Hung035d4ec2017-01-24 13:45:02 -08001/*
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
22namespace android {
23
Ivan Lozano330d8762017-08-08 12:51:06 -070024using media::VolumeShaper;
25
Andy Hung035d4ec2017-01-24 13:45:02 -080026// This entire class is inline as it is used from both core and media
27struct VolumeShaperHelper {
28 struct fields_t {
29 // VolumeShaper.Configuration
30 jclass coClazz;
31 jmethodID coConstructId;
32 jfieldID coTypeId;
33 jfieldID coIdId;
Andy Hung035d4ec2017-01-24 13:45:02 -080034 jfieldID coOptionFlagsId;
35 jfieldID coDurationMsId;
Andy Hungd4f1e862017-03-06 11:39:10 -080036 jfieldID coInterpolatorTypeId;
Andy Hung035d4ec2017-01-24 13:45:02 -080037 jfieldID coTimesId;
38 jfieldID coVolumesId;
39
40 // VolumeShaper.Operation
41 jclass opClazz;
42 jmethodID opConstructId;
43 jfieldID opFlagsId;
44 jfieldID opReplaceIdId;
Andy Hung3c0f5d22017-05-15 15:41:14 -070045 jfieldID opXOffsetId;
Andy Hung035d4ec2017-01-24 13:45:02 -080046
47 // VolumeShaper.State
48 jclass stClazz;
49 jmethodID stConstructId;
50 jfieldID stVolumeId;
51 jfieldID stXOffsetId;
52
53 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 }
Andy Hungd4f1e862017-03-06 11:39:10 -080062 coConstructId = env->GetMethodID(coClazz, "<init>", "(IIIDI[F[F)V");
Andy Hung035d4ec2017-01-24 13:45:02 -080063 coTypeId = env->GetFieldID(coClazz, "mType", "I");
64 coIdId = env->GetFieldID(coClazz, "mId", "I");
Andy Hung035d4ec2017-01-24 13:45:02 -080065 coOptionFlagsId = env->GetFieldID(coClazz, "mOptionFlags", "I");
66 coDurationMsId = env->GetFieldID(coClazz, "mDurationMs", "D");
Andy Hungd4f1e862017-03-06 11:39:10 -080067 coInterpolatorTypeId = env->GetFieldID(coClazz, "mInterpolatorType", "I");
Andy Hung035d4ec2017-01-24 13:45:02 -080068 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 }
Andy Hung3c0f5d22017-05-15 15:41:14 -070080 opConstructId = env->GetMethodID(opClazz, "<init>", "(IIF)V");
Andy Hung035d4ec2017-01-24 13:45:02 -080081 opFlagsId = env->GetFieldID(opClazz, "mFlags", "I");
82 opReplaceIdId = env->GetFieldID(opClazz, "mReplaceId", "I");
Andy Hung3c0f5d22017-05-15 15:41:14 -070083 opXOffsetId = env->GetFieldID(opClazz, "mXOffset", "F");
Andy Hung035d4ec2017-01-24 13:45:02 -080084 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
100 void exit(JNIEnv *env) {
101 env->DeleteGlobalRef(coClazz);
102 coClazz = nullptr;
103 }
104 };
105
106 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) {
Andy Hung035d4ec2017-01-24 13:45:02 -0800115 configuration->setOptionFlags(
116 (VolumeShaper::Configuration::OptionFlag)
117 env->GetIntField(jshaper, fields.coOptionFlagsId));
118 configuration->setDurationMs(
119 (double)env->GetDoubleField(jshaper, fields.coDurationMsId));
Andy Hungd4f1e862017-03-06 11:39:10 -0800120 configuration->setInterpolatorType(
121 (VolumeShaper::Configuration::InterpolatorType)
122 env->GetIntField(jshaper, fields.coInterpolatorTypeId));
Andy Hung035d4ec2017-01-24 13:45:02 -0800123
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
148 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();
Andy Hungd4f1e862017-03-06 11:39:10 -0800172 args[2].i = (jint)configuration->getOptionFlags();
173 args[3].d = (jdouble)configuration->getDurationMs();
174 args[4].i = (jint)configuration->getInterpolatorType();
Andy Hung035d4ec2017-01-24 13:45:02 -0800175 args[5].l = xarray;
176 args[6].l = yarray;
177 jobject jshaper = env->NewObjectA(fields.coClazz, fields.coConstructId, args);
178 return jshaper;
179 }
180
181 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);
Andy Hung3c0f5d22017-05-15 15:41:14 -0700186 float xOffset = env->GetFloatField(joperation, fields.opXOffsetId);
Andy Hung035d4ec2017-01-24 13:45:02 -0800187
Andy Hung3c0f5d22017-05-15 15:41:14 -0700188 sp<VolumeShaper::Operation> operation =
189 new VolumeShaper::Operation(flags, replaceId, xOffset);
Andy Hung035d4ec2017-01-24 13:45:02 -0800190 return operation;
191 }
192
193 static jobject convertOperationToJobject(
194 JNIEnv *env, const fields_t &fields, const sp<VolumeShaper::Operation> &operation) {
195 // prepare constructor args
Andy Hung3c0f5d22017-05-15 15:41:14 -0700196 jvalue args[3];
Andy Hung035d4ec2017-01-24 13:45:02 -0800197 args[0].i = (jint)operation->getFlags();
198 args[1].i = (jint)operation->getReplaceId();
Andy Hung3c0f5d22017-05-15 15:41:14 -0700199 args[2].f = (jfloat)operation->getXOffset();
Andy Hung035d4ec2017-01-24 13:45:02 -0800200
201 jobject joperation = env->NewObjectA(fields.opClazz, fields.opConstructId, args);
202 return joperation;
203 }
204
205 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
214 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_