Home | History | Annotate | Download | only in jni
      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 
     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             }
     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 
    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) {
    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 
    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();
    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 
    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);
    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 
    193     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 
    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_
    229