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 // 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 
     51         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 
     98         void exit(JNIEnv *env) {
     99             env->DeleteGlobalRef(coClazz);
    100             coClazz = nullptr;
    101         }
    102     };
    103 
    104     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 
    146     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 
    179     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 
    191     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 
    203     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 
    212     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