Home | History | Annotate | Download | only in jni
      1 /*
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 //#define LOG_NDEBUG 0
     19 
     20 #define LOG_TAG "AudioSystem-JNI"
     21 #include <utils/Log.h>
     22 
     23 #include <sstream>
     24 #include <jni.h>
     25 #include <JNIHelp.h>
     26 #include "core_jni_helpers.h"
     27 
     28 #include <media/AudioSystem.h>
     29 #include <media/AudioPolicy.h>
     30 #include <nativehelper/ScopedLocalRef.h>
     31 #include <system/audio.h>
     32 #include <system/audio_policy.h>
     33 #include "android_media_AudioFormat.h"
     34 #include "android_media_AudioErrors.h"
     35 
     36 // ----------------------------------------------------------------------------
     37 
     38 using namespace android;
     39 
     40 static const char* const kClassPathName = "android/media/AudioSystem";
     41 
     42 static jclass gArrayListClass;
     43 static struct {
     44     jmethodID    add;
     45     jmethodID    toArray;
     46 } gArrayListMethods;
     47 
     48 static jclass gAudioHandleClass;
     49 static jmethodID gAudioHandleCstor;
     50 static struct {
     51     jfieldID    mId;
     52 } gAudioHandleFields;
     53 
     54 static jclass gAudioPortClass;
     55 static jmethodID gAudioPortCstor;
     56 static struct {
     57     jfieldID    mHandle;
     58     jfieldID    mRole;
     59     jfieldID    mGains;
     60     jfieldID    mActiveConfig;
     61     // other fields unused by JNI
     62 } gAudioPortFields;
     63 
     64 static jclass gAudioPortConfigClass;
     65 static jmethodID gAudioPortConfigCstor;
     66 static struct {
     67     jfieldID    mPort;
     68     jfieldID    mSamplingRate;
     69     jfieldID    mChannelMask;
     70     jfieldID    mFormat;
     71     jfieldID    mGain;
     72     jfieldID    mConfigMask;
     73 } gAudioPortConfigFields;
     74 
     75 static jclass gAudioDevicePortClass;
     76 static jmethodID gAudioDevicePortCstor;
     77 
     78 static jclass gAudioDevicePortConfigClass;
     79 static jmethodID gAudioDevicePortConfigCstor;
     80 
     81 static jclass gAudioMixPortClass;
     82 static jmethodID gAudioMixPortCstor;
     83 
     84 static jclass gAudioMixPortConfigClass;
     85 static jmethodID gAudioMixPortConfigCstor;
     86 
     87 static jclass gAudioGainClass;
     88 static jmethodID gAudioGainCstor;
     89 
     90 static jclass gAudioGainConfigClass;
     91 static jmethodID gAudioGainConfigCstor;
     92 static struct {
     93     jfieldID mIndex;
     94     jfieldID mMode;
     95     jfieldID mChannelMask;
     96     jfieldID mValues;
     97     jfieldID mRampDurationMs;
     98     // other fields unused by JNI
     99 } gAudioGainConfigFields;
    100 
    101 static jclass gAudioPatchClass;
    102 static jmethodID gAudioPatchCstor;
    103 static struct {
    104     jfieldID    mHandle;
    105     // other fields unused by JNI
    106 } gAudioPatchFields;
    107 
    108 static jclass gAudioMixClass;
    109 static struct {
    110     jfieldID    mRule;
    111     jfieldID    mFormat;
    112     jfieldID    mRouteFlags;
    113     jfieldID    mDeviceType;
    114     jfieldID    mDeviceAddress;
    115     jfieldID    mMixType;
    116     jfieldID    mCallbackFlags;
    117 } gAudioMixFields;
    118 
    119 static jclass gAudioFormatClass;
    120 static struct {
    121     jfieldID    mEncoding;
    122     jfieldID    mSampleRate;
    123     jfieldID    mChannelMask;
    124     // other fields unused by JNI
    125 } gAudioFormatFields;
    126 
    127 static jclass gAudioMixingRuleClass;
    128 static struct {
    129     jfieldID    mCriteria;
    130     // other fields unused by JNI
    131 } gAudioMixingRuleFields;
    132 
    133 static jclass gAudioMixMatchCriterionClass;
    134 static struct {
    135     jfieldID    mAttr;
    136     jfieldID    mIntProp;
    137     jfieldID    mRule;
    138 } gAudioMixMatchCriterionFields;
    139 
    140 static jclass gAudioAttributesClass;
    141 static struct {
    142     jfieldID    mUsage;
    143     jfieldID    mSource;
    144 } gAudioAttributesFields;
    145 
    146 
    147 static const char* const kEventHandlerClassPathName =
    148         "android/media/AudioPortEventHandler";
    149 static struct {
    150     jfieldID    mJniCallback;
    151 } gEventHandlerFields;
    152 static struct {
    153     jmethodID    postEventFromNative;
    154 } gAudioPortEventHandlerMethods;
    155 
    156 static struct {
    157     jmethodID postDynPolicyEventFromNative;
    158     jmethodID postRecordConfigEventFromNative;
    159 } gAudioPolicyEventHandlerMethods;
    160 
    161 static Mutex gLock;
    162 
    163 enum AudioError {
    164     kAudioStatusOk = 0,
    165     kAudioStatusError = 1,
    166     kAudioStatusMediaServerDied = 100
    167 };
    168 
    169 enum  {
    170     AUDIOPORT_EVENT_PORT_LIST_UPDATED = 1,
    171     AUDIOPORT_EVENT_PATCH_LIST_UPDATED = 2,
    172     AUDIOPORT_EVENT_SERVICE_DIED = 3,
    173 };
    174 
    175 #define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
    176 
    177 // ----------------------------------------------------------------------------
    178 // ref-counted object for audio port callbacks
    179 class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
    180 {
    181 public:
    182     JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
    183     ~JNIAudioPortCallback();
    184 
    185     virtual void onAudioPortListUpdate();
    186     virtual void onAudioPatchListUpdate();
    187     virtual void onServiceDied();
    188 
    189 private:
    190     void sendEvent(int event);
    191 
    192     jclass      mClass;     // Reference to AudioPortEventHandler class
    193     jobject     mObject;    // Weak ref to AudioPortEventHandler Java object to call on
    194 };
    195 
    196 JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
    197 {
    198 
    199     // Hold onto the AudioPortEventHandler class for use in calling the static method
    200     // that posts events to the application thread.
    201     jclass clazz = env->GetObjectClass(thiz);
    202     if (clazz == NULL) {
    203         ALOGE("Can't find class %s", kEventHandlerClassPathName);
    204         return;
    205     }
    206     mClass = (jclass)env->NewGlobalRef(clazz);
    207 
    208     // We use a weak reference so the AudioPortEventHandler object can be garbage collected.
    209     // The reference is only used as a proxy for callbacks.
    210     mObject  = env->NewGlobalRef(weak_thiz);
    211 }
    212 
    213 JNIAudioPortCallback::~JNIAudioPortCallback()
    214 {
    215     // remove global references
    216     JNIEnv *env = AndroidRuntime::getJNIEnv();
    217     if (env == NULL) {
    218         return;
    219     }
    220     env->DeleteGlobalRef(mObject);
    221     env->DeleteGlobalRef(mClass);
    222 }
    223 
    224 void JNIAudioPortCallback::sendEvent(int event)
    225 {
    226     JNIEnv *env = AndroidRuntime::getJNIEnv();
    227     if (env == NULL) {
    228         return;
    229     }
    230     env->CallStaticVoidMethod(mClass, gAudioPortEventHandlerMethods.postEventFromNative, mObject,
    231                               event, 0, 0, NULL);
    232     if (env->ExceptionCheck()) {
    233         ALOGW("An exception occurred while notifying an event.");
    234         env->ExceptionClear();
    235     }
    236 }
    237 
    238 void JNIAudioPortCallback::onAudioPortListUpdate()
    239 {
    240     sendEvent(AUDIOPORT_EVENT_PORT_LIST_UPDATED);
    241 }
    242 
    243 void JNIAudioPortCallback::onAudioPatchListUpdate()
    244 {
    245     sendEvent(AUDIOPORT_EVENT_PATCH_LIST_UPDATED);
    246 }
    247 
    248 void JNIAudioPortCallback::onServiceDied()
    249 {
    250     sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
    251 }
    252 
    253 static sp<JNIAudioPortCallback> setJniCallback(JNIEnv* env,
    254                                        jobject thiz,
    255                                        const sp<JNIAudioPortCallback>& callback)
    256 {
    257     Mutex::Autolock l(gLock);
    258     sp<JNIAudioPortCallback> old =
    259             (JNIAudioPortCallback*)env->GetLongField(thiz, gEventHandlerFields.mJniCallback);
    260     if (callback.get()) {
    261         callback->incStrong((void*)setJniCallback);
    262     }
    263     if (old != 0) {
    264         old->decStrong((void*)setJniCallback);
    265     }
    266     env->SetLongField(thiz, gEventHandlerFields.mJniCallback, (jlong)callback.get());
    267     return old;
    268 }
    269 
    270 static int check_AudioSystem_Command(status_t status)
    271 {
    272     switch (status) {
    273     case DEAD_OBJECT:
    274         return kAudioStatusMediaServerDied;
    275     case NO_ERROR:
    276         return kAudioStatusOk;
    277     default:
    278         break;
    279     }
    280     return kAudioStatusError;
    281 }
    282 
    283 static jint
    284 android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
    285 {
    286     return (jint) check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
    287 }
    288 
    289 static jboolean
    290 android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
    291 {
    292     bool state = false;
    293     AudioSystem::isMicrophoneMuted(&state);
    294     return state;
    295 }
    296 
    297 static jboolean
    298 android_media_AudioSystem_isStreamActive(JNIEnv *env, jobject thiz, jint stream, jint inPastMs)
    299 {
    300     bool state = false;
    301     AudioSystem::isStreamActive((audio_stream_type_t) stream, &state, inPastMs);
    302     return state;
    303 }
    304 
    305 static jboolean
    306 android_media_AudioSystem_isStreamActiveRemotely(JNIEnv *env, jobject thiz, jint stream,
    307         jint inPastMs)
    308 {
    309     bool state = false;
    310     AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
    311     return state;
    312 }
    313 
    314 static jboolean
    315 android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
    316 {
    317     bool state = false;
    318     AudioSystem::isSourceActive((audio_source_t) source, &state);
    319     return state;
    320 }
    321 
    322 static jint
    323 android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
    324 {
    325     return AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
    326 }
    327 
    328 static jint
    329 android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
    330 {
    331     const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
    332     String8 c_keyValuePairs8;
    333     if (keyValuePairs) {
    334         c_keyValuePairs8 = String8(
    335             reinterpret_cast<const char16_t*>(c_keyValuePairs),
    336             env->GetStringLength(keyValuePairs));
    337         env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
    338     }
    339     int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
    340     return (jint) status;
    341 }
    342 
    343 static jstring
    344 android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
    345 {
    346     const jchar* c_keys = env->GetStringCritical(keys, 0);
    347     String8 c_keys8;
    348     if (keys) {
    349         c_keys8 = String8(reinterpret_cast<const char16_t*>(c_keys),
    350                           env->GetStringLength(keys));
    351         env->ReleaseStringCritical(keys, c_keys);
    352     }
    353     return env->NewStringUTF(AudioSystem::getParameters(c_keys8).string());
    354 }
    355 
    356 static void
    357 android_media_AudioSystem_error_callback(status_t err)
    358 {
    359     JNIEnv *env = AndroidRuntime::getJNIEnv();
    360     if (env == NULL) {
    361         return;
    362     }
    363 
    364     jclass clazz = env->FindClass(kClassPathName);
    365 
    366     env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
    367                               "errorCallbackFromNative","(I)V"),
    368                               check_AudioSystem_Command(err));
    369 
    370     env->DeleteLocalRef(clazz);
    371 }
    372 
    373 static void
    374 android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val)
    375 {
    376     JNIEnv *env = AndroidRuntime::getJNIEnv();
    377     if (env == NULL) {
    378         return;
    379     }
    380 
    381     jclass clazz = env->FindClass(kClassPathName);
    382     const char* zechars = regId.string();
    383     jstring zestring = env->NewStringUTF(zechars);
    384 
    385     env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative,
    386             event, zestring, val);
    387 
    388     env->ReleaseStringUTFChars(zestring, zechars);
    389     env->DeleteLocalRef(clazz);
    390 }
    391 
    392 static void
    393 android_media_AudioSystem_recording_callback(int event, audio_session_t session, int source,
    394         const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
    395         audio_patch_handle_t patchHandle)
    396 {
    397     JNIEnv *env = AndroidRuntime::getJNIEnv();
    398     if (env == NULL) {
    399         return;
    400     }
    401     if (clientConfig == NULL || deviceConfig == NULL) {
    402         ALOGE("Unexpected null client/device configurations in recording callback");
    403         return;
    404     }
    405 
    406     // create an array for 2*3 integers to store the record configurations (client + device)
    407     //                 plus 1 integer for the patch handle
    408     const int REC_PARAM_SIZE = 7;
    409     jintArray recParamArray = env->NewIntArray(REC_PARAM_SIZE);
    410     if (recParamArray == NULL) {
    411         ALOGE("recording callback: Couldn't allocate int array for configuration data");
    412         return;
    413     }
    414     jint recParamData[REC_PARAM_SIZE];
    415     recParamData[0] = (jint) audioFormatFromNative(clientConfig->format);
    416     // FIXME this doesn't support index-based masks
    417     recParamData[1] = (jint) inChannelMaskFromNative(clientConfig->channel_mask);
    418     recParamData[2] = (jint) clientConfig->sample_rate;
    419     recParamData[3] = (jint) audioFormatFromNative(deviceConfig->format);
    420     // FIXME this doesn't support index-based masks
    421     recParamData[4] = (jint) inChannelMaskFromNative(deviceConfig->channel_mask);
    422     recParamData[5] = (jint) deviceConfig->sample_rate;
    423     recParamData[6] = (jint) patchHandle;
    424     env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData);
    425 
    426     // callback into java
    427     jclass clazz = env->FindClass(kClassPathName);
    428     env->CallStaticVoidMethod(clazz,
    429             gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
    430             event, session, source, recParamArray);
    431     env->DeleteLocalRef(clazz);
    432 
    433     env->DeleteLocalRef(recParamArray);
    434 }
    435 
    436 static jint
    437 android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
    438 {
    439     const char *c_address = env->GetStringUTFChars(device_address, NULL);
    440     const char *c_name = env->GetStringUTFChars(device_name, NULL);
    441     int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
    442                                           static_cast <audio_policy_dev_state_t>(state),
    443                                           c_address, c_name));
    444     env->ReleaseStringUTFChars(device_address, c_address);
    445     env->ReleaseStringUTFChars(device_name, c_name);
    446     return (jint) status;
    447 }
    448 
    449 static jint
    450 android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
    451 {
    452     const char *c_address = env->GetStringUTFChars(device_address, NULL);
    453     int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
    454                                           c_address));
    455     env->ReleaseStringUTFChars(device_address, c_address);
    456     return (jint) state;
    457 }
    458 
    459 static jint
    460 android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
    461 {
    462     return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
    463 }
    464 
    465 static jint
    466 android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
    467 {
    468     return (jint) check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
    469                                                            static_cast <audio_policy_forced_cfg_t>(config)));
    470 }
    471 
    472 static jint
    473 android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
    474 {
    475     return static_cast <jint>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
    476 }
    477 
    478 static jint
    479 android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
    480 {
    481     return (jint) check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
    482                                                                    indexMin,
    483                                                                    indexMax));
    484 }
    485 
    486 static jint
    487 android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
    488                                                jobject thiz,
    489                                                jint stream,
    490                                                jint index,
    491                                                jint device)
    492 {
    493     return (jint) check_AudioSystem_Command(
    494             AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
    495                                               index,
    496                                               (audio_devices_t)device));
    497 }
    498 
    499 static jint
    500 android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env,
    501                                                jobject thiz,
    502                                                jint stream,
    503                                                jint device)
    504 {
    505     int index;
    506     if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
    507                                           &index,
    508                                           (audio_devices_t)device)
    509             != NO_ERROR) {
    510         index = -1;
    511     }
    512     return (jint) index;
    513 }
    514 
    515 static jint
    516 android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
    517 {
    518     return (jint) check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
    519 }
    520 
    521 static jfloat
    522 android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
    523 {
    524     float value;
    525     if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
    526         value = -1.0;
    527     }
    528     return value;
    529 }
    530 
    531 static jint
    532 android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
    533 {
    534     return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
    535 }
    536 
    537 static jboolean
    538 android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
    539 {
    540     bool mute;
    541     if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
    542         mute = false;
    543     }
    544     return mute;
    545 }
    546 
    547 static jint
    548 android_media_AudioSystem_setMasterMono(JNIEnv *env, jobject thiz, jboolean mono)
    549 {
    550     return (jint) check_AudioSystem_Command(AudioSystem::setMasterMono(mono));
    551 }
    552 
    553 static jboolean
    554 android_media_AudioSystem_getMasterMono(JNIEnv *env, jobject thiz)
    555 {
    556     bool mono;
    557     if (AudioSystem::getMasterMono(&mono) != NO_ERROR) {
    558         mono = false;
    559     }
    560     return mono;
    561 }
    562 
    563 static jint
    564 android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
    565 {
    566     return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
    567 }
    568 
    569 static jint
    570 android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
    571 {
    572     return (jint) AudioSystem::getPrimaryOutputSamplingRate();
    573 }
    574 
    575 static jint
    576 android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
    577 {
    578     return (jint) AudioSystem::getPrimaryOutputFrameCount();
    579 }
    580 
    581 static jint
    582 android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
    583 {
    584     uint32_t afLatency;
    585     if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
    586             != NO_ERROR) {
    587         afLatency = -1;
    588     }
    589     return (jint) afLatency;
    590 }
    591 
    592 static jint
    593 android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
    594 {
    595     return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
    596 }
    597 
    598 static jint
    599 android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
    600 {
    601     return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
    602 }
    603 
    604 
    605 static bool useInChannelMask(audio_port_type_t type, audio_port_role_t role)
    606 {
    607     return ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
    608                 ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
    609 }
    610 
    611 static void convertAudioGainConfigToNative(JNIEnv *env,
    612                                                struct audio_gain_config *nAudioGainConfig,
    613                                                const jobject jAudioGainConfig,
    614                                                bool useInMask)
    615 {
    616     nAudioGainConfig->index = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mIndex);
    617     nAudioGainConfig->mode = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
    618     ALOGV("convertAudioGainConfigToNative got gain index %d", nAudioGainConfig->index);
    619     jint jMask = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mChannelMask);
    620     audio_channel_mask_t nMask;
    621     if (useInMask) {
    622         nMask = inChannelMaskToNative(jMask);
    623         ALOGV("convertAudioGainConfigToNative IN mask java %x native %x", jMask, nMask);
    624     } else {
    625         nMask = outChannelMaskToNative(jMask);
    626         ALOGV("convertAudioGainConfigToNative OUT mask java %x native %x", jMask, nMask);
    627     }
    628     nAudioGainConfig->channel_mask = nMask;
    629     nAudioGainConfig->ramp_duration_ms = env->GetIntField(jAudioGainConfig,
    630                                                        gAudioGainConfigFields.mRampDurationMs);
    631     jintArray jValues = (jintArray)env->GetObjectField(jAudioGainConfig,
    632                                                        gAudioGainConfigFields.mValues);
    633     int *nValues = env->GetIntArrayElements(jValues, NULL);
    634     size_t size = env->GetArrayLength(jValues);
    635     memcpy(nAudioGainConfig->values, nValues, size * sizeof(int));
    636     env->DeleteLocalRef(jValues);
    637 }
    638 
    639 
    640 static jint convertAudioPortConfigToNative(JNIEnv *env,
    641                                                struct audio_port_config *nAudioPortConfig,
    642                                                const jobject jAudioPortConfig,
    643                                                bool useConfigMask)
    644 {
    645     jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
    646     jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
    647     nAudioPortConfig->id = env->GetIntField(jHandle, gAudioHandleFields.mId);
    648     nAudioPortConfig->role = (audio_port_role_t)env->GetIntField(jAudioPort,
    649                                                                  gAudioPortFields.mRole);
    650     if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
    651         nAudioPortConfig->type = AUDIO_PORT_TYPE_DEVICE;
    652     } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
    653         nAudioPortConfig->type = AUDIO_PORT_TYPE_MIX;
    654     } else {
    655         env->DeleteLocalRef(jAudioPort);
    656         env->DeleteLocalRef(jHandle);
    657         return (jint)AUDIO_JAVA_ERROR;
    658     }
    659     ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
    660           nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
    661 
    662     unsigned int configMask = 0;
    663 
    664     nAudioPortConfig->sample_rate = env->GetIntField(jAudioPortConfig,
    665                                                      gAudioPortConfigFields.mSamplingRate);
    666     if (nAudioPortConfig->sample_rate != 0) {
    667         configMask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
    668     }
    669 
    670     bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
    671     audio_channel_mask_t nMask;
    672     jint jMask = env->GetIntField(jAudioPortConfig,
    673                                    gAudioPortConfigFields.mChannelMask);
    674     if (useInMask) {
    675         nMask = inChannelMaskToNative(jMask);
    676         ALOGV("convertAudioPortConfigToNative IN mask java %x native %x", jMask, nMask);
    677     } else {
    678         nMask = outChannelMaskToNative(jMask);
    679         ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
    680     }
    681     nAudioPortConfig->channel_mask = nMask;
    682     if (nAudioPortConfig->channel_mask != AUDIO_CHANNEL_NONE) {
    683         configMask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
    684     }
    685 
    686     jint jFormat = env->GetIntField(jAudioPortConfig, gAudioPortConfigFields.mFormat);
    687     audio_format_t nFormat = audioFormatToNative(jFormat);
    688     ALOGV("convertAudioPortConfigToNative format %d native %d", jFormat, nFormat);
    689     nAudioPortConfig->format = nFormat;
    690     if (nAudioPortConfig->format != AUDIO_FORMAT_DEFAULT &&
    691             nAudioPortConfig->format != AUDIO_FORMAT_INVALID) {
    692         configMask |= AUDIO_PORT_CONFIG_FORMAT;
    693     }
    694 
    695     jobject jGain = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mGain);
    696     if (jGain != NULL) {
    697         convertAudioGainConfigToNative(env, &nAudioPortConfig->gain, jGain, useInMask);
    698         env->DeleteLocalRef(jGain);
    699         configMask |= AUDIO_PORT_CONFIG_GAIN;
    700     } else {
    701         ALOGV("convertAudioPortConfigToNative no gain");
    702         nAudioPortConfig->gain.index = -1;
    703     }
    704     if (useConfigMask) {
    705         nAudioPortConfig->config_mask = env->GetIntField(jAudioPortConfig,
    706                                                          gAudioPortConfigFields.mConfigMask);
    707     } else {
    708         nAudioPortConfig->config_mask = configMask;
    709     }
    710     env->DeleteLocalRef(jAudioPort);
    711     env->DeleteLocalRef(jHandle);
    712     return (jint)AUDIO_JAVA_SUCCESS;
    713 }
    714 
    715 static jint convertAudioPortConfigFromNative(JNIEnv *env,
    716                                                  jobject jAudioPort,
    717                                                  jobject *jAudioPortConfig,
    718                                                  const struct audio_port_config *nAudioPortConfig)
    719 {
    720     jint jStatus = AUDIO_JAVA_SUCCESS;
    721     jobject jAudioGainConfig = NULL;
    722     jobject jAudioGain = NULL;
    723     jintArray jGainValues;
    724     bool audioportCreated = false;
    725 
    726     ALOGV("convertAudioPortConfigFromNative jAudioPort %p", jAudioPort);
    727 
    728     if (jAudioPort == NULL) {
    729         jobject jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
    730                                                  nAudioPortConfig->id);
    731 
    732         ALOGV("convertAudioPortConfigFromNative handle %d is a %s", nAudioPortConfig->id,
    733               nAudioPortConfig->type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix");
    734 
    735         if (jHandle == NULL) {
    736             return (jint)AUDIO_JAVA_ERROR;
    737         }
    738         // create dummy port and port config objects with just the correct handle
    739         // and configuration data. The actual AudioPortConfig objects will be
    740         // constructed by java code with correct class type (device, mix etc...)
    741         // and reference to AudioPort instance in this client
    742         jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
    743                                            jHandle, // handle
    744                                            0,       // role
    745                                            NULL,    // name
    746                                            NULL,    // samplingRates
    747                                            NULL,    // channelMasks
    748                                            NULL,    // channelIndexMasks
    749                                            NULL,    // formats
    750                                            NULL);   // gains
    751         env->DeleteLocalRef(jHandle);
    752         if (jAudioPort == NULL) {
    753             return (jint)AUDIO_JAVA_ERROR;
    754         }
    755         ALOGV("convertAudioPortConfigFromNative jAudioPort created for handle %d",
    756               nAudioPortConfig->id);
    757 
    758         audioportCreated = true;
    759     }
    760 
    761     bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
    762 
    763     audio_channel_mask_t nMask;
    764     jint jMask;
    765 
    766     int gainIndex = nAudioPortConfig->gain.index;
    767     if (gainIndex >= 0) {
    768         ALOGV("convertAudioPortConfigFromNative gain found with index %d mode %x",
    769               gainIndex, nAudioPortConfig->gain.mode);
    770         if (audioportCreated) {
    771             ALOGV("convertAudioPortConfigFromNative creating gain");
    772             jAudioGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
    773                                                gainIndex,
    774                                                0,
    775                                                0,
    776                                                0,
    777                                                0,
    778                                                0,
    779                                                0,
    780                                                0,
    781                                                0);
    782             if (jAudioGain == NULL) {
    783                 ALOGV("convertAudioPortConfigFromNative creating gain FAILED");
    784                 jStatus = (jint)AUDIO_JAVA_ERROR;
    785                 goto exit;
    786             }
    787         } else {
    788             ALOGV("convertAudioPortConfigFromNative reading gain from port");
    789             jobjectArray jGains = (jobjectArray)env->GetObjectField(jAudioPort,
    790                                                                       gAudioPortFields.mGains);
    791             if (jGains == NULL) {
    792                 ALOGV("convertAudioPortConfigFromNative could not get gains from port");
    793                 jStatus = (jint)AUDIO_JAVA_ERROR;
    794                 goto exit;
    795             }
    796             jAudioGain = env->GetObjectArrayElement(jGains, gainIndex);
    797             env->DeleteLocalRef(jGains);
    798             if (jAudioGain == NULL) {
    799                 ALOGV("convertAudioPortConfigFromNative could not get gain at index %d", gainIndex);
    800                 jStatus = (jint)AUDIO_JAVA_ERROR;
    801                 goto exit;
    802             }
    803         }
    804         int numValues;
    805         if (useInMask) {
    806             numValues = audio_channel_count_from_in_mask(nAudioPortConfig->gain.channel_mask);
    807         } else {
    808             numValues = audio_channel_count_from_out_mask(nAudioPortConfig->gain.channel_mask);
    809         }
    810         jGainValues = env->NewIntArray(numValues);
    811         if (jGainValues == NULL) {
    812             ALOGV("convertAudioPortConfigFromNative could not create gain values %d", numValues);
    813             jStatus = (jint)AUDIO_JAVA_ERROR;
    814             goto exit;
    815         }
    816         env->SetIntArrayRegion(jGainValues, 0, numValues,
    817                                nAudioPortConfig->gain.values);
    818 
    819         nMask = nAudioPortConfig->gain.channel_mask;
    820         if (useInMask) {
    821             jMask = inChannelMaskFromNative(nMask);
    822             ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
    823         } else {
    824             jMask = outChannelMaskFromNative(nMask);
    825             ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
    826         }
    827 
    828         jAudioGainConfig = env->NewObject(gAudioGainConfigClass,
    829                                         gAudioGainConfigCstor,
    830                                         gainIndex,
    831                                         jAudioGain,
    832                                         nAudioPortConfig->gain.mode,
    833                                         jMask,
    834                                         jGainValues,
    835                                         nAudioPortConfig->gain.ramp_duration_ms);
    836         env->DeleteLocalRef(jGainValues);
    837         if (jAudioGainConfig == NULL) {
    838             ALOGV("convertAudioPortConfigFromNative could not create gain config");
    839             jStatus = (jint)AUDIO_JAVA_ERROR;
    840             goto exit;
    841         }
    842     }
    843     jclass clazz;
    844     jmethodID methodID;
    845     if (audioportCreated) {
    846         clazz = gAudioPortConfigClass;
    847         methodID = gAudioPortConfigCstor;
    848         ALOGV("convertAudioPortConfigFromNative building a generic port config");
    849     } else {
    850         if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
    851             clazz = gAudioDevicePortConfigClass;
    852             methodID = gAudioDevicePortConfigCstor;
    853             ALOGV("convertAudioPortConfigFromNative building a device config");
    854         } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
    855             clazz = gAudioMixPortConfigClass;
    856             methodID = gAudioMixPortConfigCstor;
    857             ALOGV("convertAudioPortConfigFromNative building a mix config");
    858         } else {
    859             jStatus = (jint)AUDIO_JAVA_ERROR;
    860             goto exit;
    861         }
    862     }
    863     nMask = nAudioPortConfig->channel_mask;
    864     if (useInMask) {
    865         jMask = inChannelMaskFromNative(nMask);
    866         ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
    867     } else {
    868         jMask = outChannelMaskFromNative(nMask);
    869         ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
    870     }
    871 
    872     *jAudioPortConfig = env->NewObject(clazz, methodID,
    873                                        jAudioPort,
    874                                        nAudioPortConfig->sample_rate,
    875                                        jMask,
    876                                        audioFormatFromNative(nAudioPortConfig->format),
    877                                        jAudioGainConfig);
    878     if (*jAudioPortConfig == NULL) {
    879         ALOGV("convertAudioPortConfigFromNative could not create new port config");
    880         jStatus = (jint)AUDIO_JAVA_ERROR;
    881     } else {
    882         ALOGV("convertAudioPortConfigFromNative OK");
    883     }
    884 
    885 exit:
    886     if (audioportCreated) {
    887         env->DeleteLocalRef(jAudioPort);
    888         if (jAudioGain != NULL) {
    889             env->DeleteLocalRef(jAudioGain);
    890         }
    891     }
    892     if (jAudioGainConfig != NULL) {
    893         env->DeleteLocalRef(jAudioGainConfig);
    894     }
    895     return jStatus;
    896 }
    897 
    898 static bool hasFormat(int* formats, size_t size, int format) {
    899     for (size_t index = 0; index < size; index++) {
    900         if (formats[index] == format) {
    901             return true; // found
    902         }
    903     }
    904     return false; // not found
    905 }
    906 
    907 // TODO: pull out to separate file
    908 template <typename T, size_t N>
    909 static constexpr size_t array_size(const T (&)[N]) {
    910     return N;
    911 }
    912 
    913 static jint convertAudioPortFromNative(JNIEnv *env,
    914                                            jobject *jAudioPort, const struct audio_port *nAudioPort)
    915 {
    916     jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
    917     jintArray jSamplingRates = NULL;
    918     jintArray jChannelMasks = NULL;
    919     jintArray jChannelIndexMasks = NULL;
    920     int* cFormats = NULL;
    921     jintArray jFormats = NULL;
    922     jobjectArray jGains = NULL;
    923     jobject jHandle = NULL;
    924     jstring jDeviceName = NULL;
    925     bool useInMask;
    926     size_t numPositionMasks = 0;
    927     size_t numIndexMasks = 0;
    928     size_t numUniqueFormats = 0;
    929 
    930     ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
    931         nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
    932 
    933     // Verify audio port array count info.
    934     if (nAudioPort->num_sample_rates > array_size(nAudioPort->sample_rates)
    935             || nAudioPort->num_channel_masks > array_size(nAudioPort->channel_masks)
    936             || nAudioPort->num_formats > array_size(nAudioPort->formats)
    937             || nAudioPort->num_gains > array_size(nAudioPort->gains)) {
    938 
    939         std::stringstream ss;
    940         ss << "convertAudioPortFromNative array count out of bounds:"
    941                 << " num_sample_rates " << nAudioPort->num_sample_rates
    942                 << " num_channel_masks " << nAudioPort->num_channel_masks
    943                 << " num_formats " << nAudioPort->num_formats
    944                 << " num_gains " << nAudioPort->num_gains
    945                 ;
    946         std::string s = ss.str();
    947 
    948         // Prefer to log through Java wtf instead of native ALOGE.
    949         ScopedLocalRef<jclass> jLogClass(env, env->FindClass("android/util/Log"));
    950         jmethodID jWtfId = (jLogClass.get() == nullptr)
    951                 ? nullptr
    952                 : env->GetStaticMethodID(jLogClass.get(), "wtf",
    953                         "(Ljava/lang/String;Ljava/lang/String;)I");
    954         if (jWtfId != nullptr) {
    955             ScopedLocalRef<jstring> jMessage(env, env->NewStringUTF(s.c_str()));
    956             ScopedLocalRef<jstring> jTag(env, env->NewStringUTF(LOG_TAG));
    957             (void)env->CallStaticIntMethod(jLogClass.get(), jWtfId, jTag.get(), jMessage.get());
    958         } else {
    959             ALOGE("%s", s.c_str());
    960         }
    961         jStatus = (jint)AUDIO_JAVA_ERROR;
    962         goto exit;
    963     }
    964 
    965     jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
    966     if (jSamplingRates == NULL) {
    967         jStatus = (jint)AUDIO_JAVA_ERROR;
    968         goto exit;
    969     }
    970     if (nAudioPort->num_sample_rates) {
    971         env->SetIntArrayRegion(jSamplingRates, 0, nAudioPort->num_sample_rates,
    972                                (jint *)nAudioPort->sample_rates);
    973     }
    974 
    975     // count up how many masks are positional and indexed
    976     for(size_t index = 0; index < nAudioPort->num_channel_masks; index++) {
    977         const audio_channel_mask_t mask = nAudioPort->channel_masks[index];
    978         if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
    979             numIndexMasks++;
    980         } else {
    981             numPositionMasks++;
    982         }
    983     }
    984 
    985     jChannelMasks = env->NewIntArray(numPositionMasks);
    986     if (jChannelMasks == NULL) {
    987         jStatus = (jint)AUDIO_JAVA_ERROR;
    988         goto exit;
    989     }
    990     jChannelIndexMasks = env->NewIntArray(numIndexMasks);
    991     if (jChannelIndexMasks == NULL) {
    992         jStatus = (jint)AUDIO_JAVA_ERROR;
    993         goto exit;
    994     }
    995     useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
    996 
    997     // put the masks in the output arrays
    998     for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0;
    999          maskIndex < nAudioPort->num_channel_masks; maskIndex++) {
   1000         const audio_channel_mask_t mask = nAudioPort->channel_masks[maskIndex];
   1001         if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
   1002             jint jMask = audio_channel_mask_get_bits(mask);
   1003             env->SetIntArrayRegion(jChannelIndexMasks, indexedMaskIndex++, 1, &jMask);
   1004         } else {
   1005             jint jMask = useInMask ? inChannelMaskFromNative(mask)
   1006                                    : outChannelMaskFromNative(mask);
   1007             env->SetIntArrayRegion(jChannelMasks, posMaskIndex++, 1, &jMask);
   1008         }
   1009     }
   1010 
   1011     // formats
   1012     if (nAudioPort->num_formats != 0) {
   1013         cFormats = new int[nAudioPort->num_formats];
   1014         for (size_t index = 0; index < nAudioPort->num_formats; index++) {
   1015             int format = audioFormatFromNative(nAudioPort->formats[index]);
   1016             if (!hasFormat(cFormats, numUniqueFormats, format)) {
   1017                 cFormats[numUniqueFormats++] = format;
   1018             }
   1019         }
   1020     }
   1021     jFormats = env->NewIntArray(numUniqueFormats);
   1022     if (jFormats == NULL) {
   1023         jStatus = (jint)AUDIO_JAVA_ERROR;
   1024         goto exit;
   1025     }
   1026     if (numUniqueFormats != 0) {
   1027         env->SetIntArrayRegion(jFormats, 0, numUniqueFormats, cFormats);
   1028     }
   1029 
   1030     // gains
   1031     jGains = env->NewObjectArray(nAudioPort->num_gains,
   1032                                           gAudioGainClass, NULL);
   1033     if (jGains == NULL) {
   1034         jStatus = (jint)AUDIO_JAVA_ERROR;
   1035         goto exit;
   1036     }
   1037 
   1038     for (size_t j = 0; j < nAudioPort->num_gains; j++) {
   1039         audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
   1040         jint jMask;
   1041         if (useInMask) {
   1042             jMask = inChannelMaskFromNative(nMask);
   1043             ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
   1044         } else {
   1045             jMask = outChannelMaskFromNative(nMask);
   1046             ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
   1047         }
   1048 
   1049         jobject jGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
   1050                                                  j,
   1051                                                  nAudioPort->gains[j].mode,
   1052                                                  jMask,
   1053                                                  nAudioPort->gains[j].min_value,
   1054                                                  nAudioPort->gains[j].max_value,
   1055                                                  nAudioPort->gains[j].default_value,
   1056                                                  nAudioPort->gains[j].step_value,
   1057                                                  nAudioPort->gains[j].min_ramp_ms,
   1058                                                  nAudioPort->gains[j].max_ramp_ms);
   1059         if (jGain == NULL) {
   1060             jStatus = (jint)AUDIO_JAVA_ERROR;
   1061             goto exit;
   1062         }
   1063         env->SetObjectArrayElement(jGains, j, jGain);
   1064         env->DeleteLocalRef(jGain);
   1065     }
   1066 
   1067     jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
   1068                                              nAudioPort->id);
   1069     if (jHandle == NULL) {
   1070         jStatus = (jint)AUDIO_JAVA_ERROR;
   1071         goto exit;
   1072     }
   1073 
   1074     jDeviceName = env->NewStringUTF(nAudioPort->name);
   1075 
   1076     if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
   1077         ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
   1078         jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
   1079         *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
   1080                                      jHandle, jDeviceName,
   1081                                      jSamplingRates, jChannelMasks, jChannelIndexMasks,
   1082                                      jFormats, jGains,
   1083                                      nAudioPort->ext.device.type, jAddress);
   1084         env->DeleteLocalRef(jAddress);
   1085     } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
   1086         ALOGV("convertAudioPortFromNative is a mix");
   1087         *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
   1088                                      jHandle, nAudioPort->ext.mix.handle,
   1089                                      nAudioPort->role, jDeviceName,
   1090                                      jSamplingRates, jChannelMasks, jChannelIndexMasks,
   1091                                      jFormats, jGains);
   1092     } else {
   1093         ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
   1094         jStatus = (jint)AUDIO_JAVA_ERROR;
   1095         goto exit;
   1096     }
   1097     if (*jAudioPort == NULL) {
   1098         jStatus = (jint)AUDIO_JAVA_ERROR;
   1099         goto exit;
   1100     }
   1101 
   1102     jobject jAudioPortConfig;
   1103     jStatus = convertAudioPortConfigFromNative(env,
   1104                                                        *jAudioPort,
   1105                                                        &jAudioPortConfig,
   1106                                                        &nAudioPort->active_config);
   1107     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1108         goto exit;
   1109     }
   1110 
   1111     env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
   1112 
   1113 exit:
   1114     if (jDeviceName != NULL) {
   1115         env->DeleteLocalRef(jDeviceName);
   1116     }
   1117     if (jSamplingRates != NULL) {
   1118         env->DeleteLocalRef(jSamplingRates);
   1119     }
   1120     if (jChannelMasks != NULL) {
   1121         env->DeleteLocalRef(jChannelMasks);
   1122     }
   1123     if (jChannelIndexMasks != NULL) {
   1124         env->DeleteLocalRef(jChannelIndexMasks);
   1125     }
   1126     if (cFormats != NULL) {
   1127         delete[] cFormats;
   1128     }
   1129     if (jFormats != NULL) {
   1130         env->DeleteLocalRef(jFormats);
   1131     }
   1132     if (jGains != NULL) {
   1133         env->DeleteLocalRef(jGains);
   1134     }
   1135     if (jHandle != NULL) {
   1136         env->DeleteLocalRef(jHandle);
   1137     }
   1138 
   1139     return jStatus;
   1140 }
   1141 
   1142 
   1143 static jint
   1144 android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
   1145                                          jobject jPorts, jintArray jGeneration)
   1146 {
   1147     ALOGV("listAudioPorts");
   1148 
   1149     if (jPorts == NULL) {
   1150         ALOGE("listAudioPorts NULL AudioPort ArrayList");
   1151         return (jint)AUDIO_JAVA_BAD_VALUE;
   1152     }
   1153     if (!env->IsInstanceOf(jPorts, gArrayListClass)) {
   1154         ALOGE("listAudioPorts not an arraylist");
   1155         return (jint)AUDIO_JAVA_BAD_VALUE;
   1156     }
   1157 
   1158     if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
   1159         return (jint)AUDIO_JAVA_BAD_VALUE;
   1160     }
   1161 
   1162     status_t status;
   1163     unsigned int generation1;
   1164     unsigned int generation;
   1165     unsigned int numPorts;
   1166     jint *nGeneration;
   1167     struct audio_port *nPorts = NULL;
   1168     int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
   1169     jint jStatus;
   1170 
   1171     // get the port count and all the ports until they both return the same generation
   1172     do {
   1173         if (attempts-- < 0) {
   1174             status = TIMED_OUT;
   1175             break;
   1176         }
   1177 
   1178         numPorts = 0;
   1179         status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
   1180                                              AUDIO_PORT_TYPE_NONE,
   1181                                                       &numPorts,
   1182                                                       NULL,
   1183                                                       &generation1);
   1184         if (status != NO_ERROR) {
   1185             ALOGE_IF(status != NO_ERROR, "AudioSystem::listAudioPorts error %d", status);
   1186             break;
   1187         }
   1188         if (numPorts == 0) {
   1189             jStatus = (jint)AUDIO_JAVA_SUCCESS;
   1190             goto exit;
   1191         }
   1192         nPorts = (struct audio_port *)realloc(nPorts, numPorts * sizeof(struct audio_port));
   1193 
   1194         status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
   1195                                              AUDIO_PORT_TYPE_NONE,
   1196                                                       &numPorts,
   1197                                                       nPorts,
   1198                                                       &generation);
   1199         ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
   1200               numPorts, generation, generation1);
   1201     } while (generation1 != generation && status == NO_ERROR);
   1202 
   1203     jStatus = nativeToJavaStatus(status);
   1204     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1205         goto exit;
   1206     }
   1207 
   1208     for (size_t i = 0; i < numPorts; i++) {
   1209         jobject jAudioPort;
   1210         jStatus = convertAudioPortFromNative(env, &jAudioPort, &nPorts[i]);
   1211         if (jStatus != AUDIO_JAVA_SUCCESS) {
   1212             goto exit;
   1213         }
   1214         env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort);
   1215     }
   1216 
   1217 exit:
   1218     nGeneration = env->GetIntArrayElements(jGeneration, NULL);
   1219     if (nGeneration == NULL) {
   1220         jStatus = (jint)AUDIO_JAVA_ERROR;
   1221     } else {
   1222         nGeneration[0] = generation1;
   1223         env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
   1224     }
   1225     free(nPorts);
   1226     return jStatus;
   1227 }
   1228 
   1229 static int
   1230 android_media_AudioSystem_createAudioPatch(JNIEnv *env, jobject clazz,
   1231                                  jobjectArray jPatches, jobjectArray jSources, jobjectArray jSinks)
   1232 {
   1233     status_t status;
   1234     jint jStatus;
   1235 
   1236     ALOGV("createAudioPatch");
   1237     if (jPatches == NULL || jSources == NULL || jSinks == NULL) {
   1238         return (jint)AUDIO_JAVA_BAD_VALUE;
   1239     }
   1240 
   1241     if (env->GetArrayLength(jPatches) != 1) {
   1242         return (jint)AUDIO_JAVA_BAD_VALUE;
   1243     }
   1244     jint numSources = env->GetArrayLength(jSources);
   1245     if (numSources == 0 || numSources > AUDIO_PATCH_PORTS_MAX) {
   1246         return (jint)AUDIO_JAVA_BAD_VALUE;
   1247     }
   1248 
   1249     jint numSinks = env->GetArrayLength(jSinks);
   1250     if (numSinks == 0 || numSinks > AUDIO_PATCH_PORTS_MAX) {
   1251         return (jint)AUDIO_JAVA_BAD_VALUE;
   1252     }
   1253 
   1254     audio_patch_handle_t handle = (audio_patch_handle_t)0;
   1255     jobject jPatch = env->GetObjectArrayElement(jPatches, 0);
   1256     jobject jPatchHandle = NULL;
   1257     if (jPatch != NULL) {
   1258         if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
   1259             return (jint)AUDIO_JAVA_BAD_VALUE;
   1260         }
   1261         jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
   1262         handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
   1263     }
   1264 
   1265     struct audio_patch nPatch;
   1266 
   1267     nPatch.id = handle;
   1268     nPatch.num_sources = 0;
   1269     nPatch.num_sinks = 0;
   1270     jobject jSource = NULL;
   1271     jobject jSink = NULL;
   1272 
   1273     for (jint i = 0; i < numSources; i++) {
   1274         jSource = env->GetObjectArrayElement(jSources, i);
   1275         if (!env->IsInstanceOf(jSource, gAudioPortConfigClass)) {
   1276             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
   1277             goto exit;
   1278         }
   1279         jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource, false);
   1280         env->DeleteLocalRef(jSource);
   1281         jSource = NULL;
   1282         if (jStatus != AUDIO_JAVA_SUCCESS) {
   1283             goto exit;
   1284         }
   1285         nPatch.num_sources++;
   1286     }
   1287 
   1288     for (jint i = 0; i < numSinks; i++) {
   1289         jSink = env->GetObjectArrayElement(jSinks, i);
   1290         if (!env->IsInstanceOf(jSink, gAudioPortConfigClass)) {
   1291             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
   1292             goto exit;
   1293         }
   1294         jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink, false);
   1295         env->DeleteLocalRef(jSink);
   1296         jSink = NULL;
   1297         if (jStatus != AUDIO_JAVA_SUCCESS) {
   1298             goto exit;
   1299         }
   1300         nPatch.num_sinks++;
   1301     }
   1302 
   1303     ALOGV("AudioSystem::createAudioPatch");
   1304     status = AudioSystem::createAudioPatch(&nPatch, &handle);
   1305     ALOGV("AudioSystem::createAudioPatch() returned %d hande %d", status, handle);
   1306 
   1307     jStatus = nativeToJavaStatus(status);
   1308     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1309         goto exit;
   1310     }
   1311 
   1312     if (jPatchHandle == NULL) {
   1313         jPatchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
   1314                                            handle);
   1315         if (jPatchHandle == NULL) {
   1316             jStatus = (jint)AUDIO_JAVA_ERROR;
   1317             goto exit;
   1318         }
   1319         jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle, jSources, jSinks);
   1320         if (jPatch == NULL) {
   1321             jStatus = (jint)AUDIO_JAVA_ERROR;
   1322             goto exit;
   1323         }
   1324         env->SetObjectArrayElement(jPatches, 0, jPatch);
   1325     } else {
   1326         env->SetIntField(jPatchHandle, gAudioHandleFields.mId, handle);
   1327     }
   1328 
   1329 exit:
   1330     if (jPatchHandle != NULL) {
   1331         env->DeleteLocalRef(jPatchHandle);
   1332     }
   1333     if (jPatch != NULL) {
   1334         env->DeleteLocalRef(jPatch);
   1335     }
   1336     if (jSource != NULL) {
   1337         env->DeleteLocalRef(jSource);
   1338     }
   1339     if (jSink != NULL) {
   1340         env->DeleteLocalRef(jSink);
   1341     }
   1342     return jStatus;
   1343 }
   1344 
   1345 static jint
   1346 android_media_AudioSystem_releaseAudioPatch(JNIEnv *env, jobject clazz,
   1347                                                jobject jPatch)
   1348 {
   1349     ALOGV("releaseAudioPatch");
   1350     if (jPatch == NULL) {
   1351         return (jint)AUDIO_JAVA_BAD_VALUE;
   1352     }
   1353 
   1354     audio_patch_handle_t handle = (audio_patch_handle_t)0;
   1355     jobject jPatchHandle = NULL;
   1356     if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
   1357         return (jint)AUDIO_JAVA_BAD_VALUE;
   1358     }
   1359     jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
   1360     handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
   1361     env->DeleteLocalRef(jPatchHandle);
   1362 
   1363     ALOGV("AudioSystem::releaseAudioPatch");
   1364     status_t status = AudioSystem::releaseAudioPatch(handle);
   1365     ALOGV("AudioSystem::releaseAudioPatch() returned %d", status);
   1366     jint jStatus = nativeToJavaStatus(status);
   1367     return jStatus;
   1368 }
   1369 
   1370 static jint
   1371 android_media_AudioSystem_listAudioPatches(JNIEnv *env, jobject clazz,
   1372                                            jobject jPatches, jintArray jGeneration)
   1373 {
   1374     ALOGV("listAudioPatches");
   1375     if (jPatches == NULL) {
   1376         ALOGE("listAudioPatches NULL AudioPatch ArrayList");
   1377         return (jint)AUDIO_JAVA_BAD_VALUE;
   1378     }
   1379     if (!env->IsInstanceOf(jPatches, gArrayListClass)) {
   1380         ALOGE("listAudioPatches not an arraylist");
   1381         return (jint)AUDIO_JAVA_BAD_VALUE;
   1382     }
   1383 
   1384     if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
   1385         return (jint)AUDIO_JAVA_BAD_VALUE;
   1386     }
   1387 
   1388     status_t status;
   1389     unsigned int generation1;
   1390     unsigned int generation;
   1391     unsigned int numPatches;
   1392     jint *nGeneration;
   1393     struct audio_patch *nPatches = NULL;
   1394     jobjectArray jSources = NULL;
   1395     jobject jSource = NULL;
   1396     jobjectArray jSinks = NULL;
   1397     jobject jSink = NULL;
   1398     jobject jPatch = NULL;
   1399     int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
   1400     jint jStatus;
   1401 
   1402     // get the patch count and all the patches until they both return the same generation
   1403     do {
   1404         if (attempts-- < 0) {
   1405             status = TIMED_OUT;
   1406             break;
   1407         }
   1408 
   1409         numPatches = 0;
   1410         status = AudioSystem::listAudioPatches(&numPatches,
   1411                                                NULL,
   1412                                                &generation1);
   1413         if (status != NO_ERROR) {
   1414             ALOGE_IF(status != NO_ERROR, "listAudioPatches AudioSystem::listAudioPatches error %d",
   1415                                       status);
   1416             break;
   1417         }
   1418         if (numPatches == 0) {
   1419             jStatus = (jint)AUDIO_JAVA_SUCCESS;
   1420             goto exit;
   1421         }
   1422 
   1423         nPatches = (struct audio_patch *)realloc(nPatches, numPatches * sizeof(struct audio_patch));
   1424 
   1425         status = AudioSystem::listAudioPatches(&numPatches,
   1426                                                nPatches,
   1427                                                &generation);
   1428         ALOGV("listAudioPatches AudioSystem::listAudioPatches numPatches %d generation %d generation1 %d",
   1429               numPatches, generation, generation1);
   1430 
   1431     } while (generation1 != generation && status == NO_ERROR);
   1432 
   1433     jStatus = nativeToJavaStatus(status);
   1434     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1435         goto exit;
   1436     }
   1437 
   1438     for (size_t i = 0; i < numPatches; i++) {
   1439         jobject patchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
   1440                                                  nPatches[i].id);
   1441         if (patchHandle == NULL) {
   1442             jStatus = AUDIO_JAVA_ERROR;
   1443             goto exit;
   1444         }
   1445         ALOGV("listAudioPatches patch %zu num_sources %d num_sinks %d",
   1446               i, nPatches[i].num_sources, nPatches[i].num_sinks);
   1447 
   1448         env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
   1449 
   1450         // load sources
   1451         jSources = env->NewObjectArray(nPatches[i].num_sources,
   1452                                        gAudioPortConfigClass, NULL);
   1453         if (jSources == NULL) {
   1454             jStatus = AUDIO_JAVA_ERROR;
   1455             goto exit;
   1456         }
   1457 
   1458         for (size_t j = 0; j < nPatches[i].num_sources; j++) {
   1459             jStatus = convertAudioPortConfigFromNative(env,
   1460                                                       NULL,
   1461                                                       &jSource,
   1462                                                       &nPatches[i].sources[j]);
   1463             if (jStatus != AUDIO_JAVA_SUCCESS) {
   1464                 goto exit;
   1465             }
   1466             env->SetObjectArrayElement(jSources, j, jSource);
   1467             env->DeleteLocalRef(jSource);
   1468             jSource = NULL;
   1469             ALOGV("listAudioPatches patch %zu source %zu is a %s handle %d",
   1470                   i, j,
   1471                   nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
   1472                   nPatches[i].sources[j].id);
   1473         }
   1474         // load sinks
   1475         jSinks = env->NewObjectArray(nPatches[i].num_sinks,
   1476                                      gAudioPortConfigClass, NULL);
   1477         if (jSinks == NULL) {
   1478             jStatus = AUDIO_JAVA_ERROR;
   1479             goto exit;
   1480         }
   1481 
   1482         for (size_t j = 0; j < nPatches[i].num_sinks; j++) {
   1483             jStatus = convertAudioPortConfigFromNative(env,
   1484                                                       NULL,
   1485                                                       &jSink,
   1486                                                       &nPatches[i].sinks[j]);
   1487 
   1488             if (jStatus != AUDIO_JAVA_SUCCESS) {
   1489                 goto exit;
   1490             }
   1491             env->SetObjectArrayElement(jSinks, j, jSink);
   1492             env->DeleteLocalRef(jSink);
   1493             jSink = NULL;
   1494             ALOGV("listAudioPatches patch %zu sink %zu is a %s handle %d",
   1495                   i, j,
   1496                   nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
   1497                   nPatches[i].sinks[j].id);
   1498         }
   1499 
   1500         jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor,
   1501                                        patchHandle, jSources, jSinks);
   1502         env->DeleteLocalRef(jSources);
   1503         jSources = NULL;
   1504         env->DeleteLocalRef(jSinks);
   1505         jSinks = NULL;
   1506         if (jPatch == NULL) {
   1507             jStatus = AUDIO_JAVA_ERROR;
   1508             goto exit;
   1509         }
   1510         env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch);
   1511         env->DeleteLocalRef(jPatch);
   1512         jPatch = NULL;
   1513     }
   1514 
   1515 exit:
   1516 
   1517     nGeneration = env->GetIntArrayElements(jGeneration, NULL);
   1518     if (nGeneration == NULL) {
   1519         jStatus = AUDIO_JAVA_ERROR;
   1520     } else {
   1521         nGeneration[0] = generation1;
   1522         env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
   1523     }
   1524 
   1525     if (jSources != NULL) {
   1526         env->DeleteLocalRef(jSources);
   1527     }
   1528     if (jSource != NULL) {
   1529         env->DeleteLocalRef(jSource);
   1530     }
   1531     if (jSinks != NULL) {
   1532         env->DeleteLocalRef(jSinks);
   1533     }
   1534     if (jSink != NULL) {
   1535         env->DeleteLocalRef(jSink);
   1536     }
   1537     if (jPatch != NULL) {
   1538         env->DeleteLocalRef(jPatch);
   1539     }
   1540     free(nPatches);
   1541     return jStatus;
   1542 }
   1543 
   1544 static jint
   1545 android_media_AudioSystem_setAudioPortConfig(JNIEnv *env, jobject clazz,
   1546                                  jobject jAudioPortConfig)
   1547 {
   1548     ALOGV("setAudioPortConfig");
   1549     if (jAudioPortConfig == NULL) {
   1550         return AUDIO_JAVA_BAD_VALUE;
   1551     }
   1552     if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
   1553         return AUDIO_JAVA_BAD_VALUE;
   1554     }
   1555     struct audio_port_config nAudioPortConfig;
   1556     jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig, true);
   1557     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1558         return jStatus;
   1559     }
   1560     status_t status = AudioSystem::setAudioPortConfig(&nAudioPortConfig);
   1561     ALOGV("AudioSystem::setAudioPortConfig() returned %d", status);
   1562     jStatus = nativeToJavaStatus(status);
   1563     return jStatus;
   1564 }
   1565 
   1566 static void
   1567 android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this)
   1568 {
   1569     ALOGV("eventHandlerSetup");
   1570 
   1571     sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
   1572 
   1573     if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) {
   1574         setJniCallback(env, thiz, callback);
   1575     }
   1576 }
   1577 
   1578 static void
   1579 android_media_AudioSystem_eventHandlerFinalize(JNIEnv *env, jobject thiz)
   1580 {
   1581     ALOGV("eventHandlerFinalize");
   1582 
   1583     sp<JNIAudioPortCallback> callback = setJniCallback(env, thiz, 0);
   1584 
   1585     if (callback != 0) {
   1586         AudioSystem::removeAudioPortCallback(callback);
   1587     }
   1588 }
   1589 
   1590 static jint
   1591 android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
   1592 {
   1593     return (jint) AudioSystem::getAudioHwSyncForSession((audio_session_t) sessionId);
   1594 }
   1595 
   1596 static void
   1597 android_media_AudioSystem_registerDynPolicyCallback(JNIEnv *env, jobject thiz)
   1598 {
   1599     AudioSystem::setDynPolicyCallback(android_media_AudioSystem_dyn_policy_callback);
   1600 }
   1601 
   1602 static void
   1603 android_media_AudioSystem_registerRecordingCallback(JNIEnv *env, jobject thiz)
   1604 {
   1605     AudioSystem::setRecordConfigCallback(android_media_AudioSystem_recording_callback);
   1606 }
   1607 
   1608 
   1609 static jint convertAudioMixToNative(JNIEnv *env,
   1610                                     AudioMix *nAudioMix,
   1611                                     const jobject jAudioMix)
   1612 {
   1613     nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
   1614     nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
   1615     nAudioMix->mDeviceType = (audio_devices_t)
   1616             env->GetIntField(jAudioMix, gAudioMixFields.mDeviceType);
   1617 
   1618     jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioMix,
   1619                                                            gAudioMixFields.mDeviceAddress);
   1620     const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
   1621     nAudioMix->mDeviceAddress = String8(nDeviceAddress);
   1622     env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
   1623     env->DeleteLocalRef(jDeviceAddress);
   1624 
   1625     nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
   1626 
   1627     jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
   1628     nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
   1629                                                      gAudioFormatFields.mSampleRate);
   1630     nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat,
   1631                                                      gAudioFormatFields.mChannelMask));
   1632     nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat,
   1633                                                      gAudioFormatFields.mEncoding));
   1634     env->DeleteLocalRef(jFormat);
   1635 
   1636     jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
   1637     jobject jRuleCriteria = env->GetObjectField(jRule, gAudioMixingRuleFields.mCriteria);
   1638     env->DeleteLocalRef(jRule);
   1639     jobjectArray jCriteria = (jobjectArray)env->CallObjectMethod(jRuleCriteria,
   1640                                                                  gArrayListMethods.toArray);
   1641     env->DeleteLocalRef(jRuleCriteria);
   1642 
   1643     jint numCriteria = env->GetArrayLength(jCriteria);
   1644     if (numCriteria > MAX_CRITERIA_PER_MIX) {
   1645         numCriteria = MAX_CRITERIA_PER_MIX;
   1646     }
   1647 
   1648     for (jint i = 0; i < numCriteria; i++) {
   1649         AudioMixMatchCriterion nCriterion;
   1650 
   1651         jobject jCriterion = env->GetObjectArrayElement(jCriteria, i);
   1652 
   1653         nCriterion.mRule = env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mRule);
   1654 
   1655         const uint32_t match_rule = nCriterion.mRule & ~RULE_EXCLUSION_MASK;
   1656         switch (match_rule) {
   1657         case RULE_MATCH_UID:
   1658             nCriterion.mValue.mUid = env->GetIntField(jCriterion,
   1659                     gAudioMixMatchCriterionFields.mIntProp);
   1660             break;
   1661         case RULE_MATCH_ATTRIBUTE_USAGE:
   1662         case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
   1663             jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
   1664             if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
   1665                 nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
   1666                         gAudioAttributesFields.mUsage);
   1667             } else {
   1668                 nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
   1669                         gAudioAttributesFields.mSource);
   1670             }
   1671             env->DeleteLocalRef(jAttributes);
   1672             }
   1673             break;
   1674         }
   1675 
   1676         nAudioMix->mCriteria.add(nCriterion);
   1677         env->DeleteLocalRef(jCriterion);
   1678     }
   1679 
   1680     env->DeleteLocalRef(jCriteria);
   1681 
   1682     return (jint)AUDIO_JAVA_SUCCESS;
   1683 }
   1684 
   1685 static jint
   1686 android_media_AudioSystem_registerPolicyMixes(JNIEnv *env, jobject clazz,
   1687                                               jobject jMixesList, jboolean registration)
   1688 {
   1689     ALOGV("registerPolicyMixes");
   1690 
   1691     if (jMixesList == NULL) {
   1692         return (jint)AUDIO_JAVA_BAD_VALUE;
   1693     }
   1694     if (!env->IsInstanceOf(jMixesList, gArrayListClass)) {
   1695         return (jint)AUDIO_JAVA_BAD_VALUE;
   1696     }
   1697     jobjectArray jMixes = (jobjectArray)env->CallObjectMethod(jMixesList,
   1698                                                               gArrayListMethods.toArray);
   1699     jint numMixes = env->GetArrayLength(jMixes);
   1700     if (numMixes > MAX_MIXES_PER_POLICY) {
   1701         numMixes = MAX_MIXES_PER_POLICY;
   1702     }
   1703 
   1704     status_t status;
   1705     jint jStatus;
   1706     jobject jAudioMix = NULL;
   1707     Vector <AudioMix> mixes;
   1708     for (jint i = 0; i < numMixes; i++) {
   1709         jAudioMix = env->GetObjectArrayElement(jMixes, i);
   1710         if (!env->IsInstanceOf(jAudioMix, gAudioMixClass)) {
   1711             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
   1712             goto exit;
   1713         }
   1714         AudioMix mix;
   1715         jStatus = convertAudioMixToNative(env, &mix, jAudioMix);
   1716         env->DeleteLocalRef(jAudioMix);
   1717         jAudioMix = NULL;
   1718         if (jStatus != AUDIO_JAVA_SUCCESS) {
   1719             goto exit;
   1720         }
   1721         mixes.add(mix);
   1722     }
   1723 
   1724     ALOGV("AudioSystem::registerPolicyMixes numMixes %d registration %d", numMixes, registration);
   1725     status = AudioSystem::registerPolicyMixes(mixes, registration);
   1726     ALOGV("AudioSystem::registerPolicyMixes() returned %d", status);
   1727 
   1728     jStatus = nativeToJavaStatus(status);
   1729     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1730         goto exit;
   1731     }
   1732 
   1733 exit:
   1734     if (jAudioMix != NULL) {
   1735         env->DeleteLocalRef(jAudioMix);
   1736     }
   1737     return jStatus;
   1738 }
   1739 
   1740 static jint
   1741 android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz)
   1742 {
   1743     return nativeToJavaStatus(AudioSystem::systemReady());
   1744 }
   1745 
   1746 
   1747 // ----------------------------------------------------------------------------
   1748 
   1749 static const JNINativeMethod gMethods[] = {
   1750     {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
   1751     {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
   1752     {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
   1753     {"isMicrophoneMuted",   "()Z",      (void *)android_media_AudioSystem_isMicrophoneMuted},
   1754     {"isStreamActive",      "(II)Z",    (void *)android_media_AudioSystem_isStreamActive},
   1755     {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
   1756     {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
   1757     {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
   1758     {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
   1759     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
   1760     {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
   1761     {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
   1762     {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
   1763     {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
   1764     {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
   1765     {"getStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_getStreamVolumeIndex},
   1766     {"setMasterVolume",     "(F)I",     (void *)android_media_AudioSystem_setMasterVolume},
   1767     {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
   1768     {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
   1769     {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
   1770     {"setMasterMono",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMono},
   1771     {"getMasterMono",       "()Z",      (void *)android_media_AudioSystem_getMasterMono},
   1772     {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
   1773     {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
   1774     {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
   1775     {"getOutputLatency",    "(I)I",     (void *)android_media_AudioSystem_getOutputLatency},
   1776     {"setLowRamDevice",     "(Z)I",     (void *)android_media_AudioSystem_setLowRamDevice},
   1777     {"checkAudioFlinger",    "()I",     (void *)android_media_AudioSystem_checkAudioFlinger},
   1778     {"listAudioPorts",      "(Ljava/util/ArrayList;[I)I",
   1779                                                 (void *)android_media_AudioSystem_listAudioPorts},
   1780     {"createAudioPatch",    "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
   1781                                             (void *)android_media_AudioSystem_createAudioPatch},
   1782     {"releaseAudioPatch",   "(Landroid/media/AudioPatch;)I",
   1783                                             (void *)android_media_AudioSystem_releaseAudioPatch},
   1784     {"listAudioPatches",    "(Ljava/util/ArrayList;[I)I",
   1785                                                 (void *)android_media_AudioSystem_listAudioPatches},
   1786     {"setAudioPortConfig",   "(Landroid/media/AudioPortConfig;)I",
   1787                                             (void *)android_media_AudioSystem_setAudioPortConfig},
   1788     {"getAudioHwSyncForSession", "(I)I",
   1789                                     (void *)android_media_AudioSystem_getAudioHwSyncForSession},
   1790     {"registerPolicyMixes",    "(Ljava/util/ArrayList;Z)I",
   1791                                             (void *)android_media_AudioSystem_registerPolicyMixes},
   1792     {"native_register_dynamic_policy_callback", "()V",
   1793                                     (void *)android_media_AudioSystem_registerDynPolicyCallback},
   1794     {"native_register_recording_callback", "()V",
   1795                                     (void *)android_media_AudioSystem_registerRecordingCallback},
   1796     {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
   1797 };
   1798 
   1799 
   1800 static const JNINativeMethod gEventHandlerMethods[] = {
   1801     {"native_setup",
   1802         "(Ljava/lang/Object;)V",
   1803         (void *)android_media_AudioSystem_eventHandlerSetup},
   1804     {"native_finalize",
   1805         "()V",
   1806         (void *)android_media_AudioSystem_eventHandlerFinalize},
   1807 };
   1808 
   1809 int register_android_media_AudioSystem(JNIEnv *env)
   1810 {
   1811     jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
   1812     gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
   1813     gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
   1814     gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass, "toArray", "()[Ljava/lang/Object;");
   1815 
   1816     jclass audioHandleClass = FindClassOrDie(env, "android/media/AudioHandle");
   1817     gAudioHandleClass = MakeGlobalRefOrDie(env, audioHandleClass);
   1818     gAudioHandleCstor = GetMethodIDOrDie(env, audioHandleClass, "<init>", "(I)V");
   1819     gAudioHandleFields.mId = GetFieldIDOrDie(env, audioHandleClass, "mId", "I");
   1820 
   1821     jclass audioPortClass = FindClassOrDie(env, "android/media/AudioPort");
   1822     gAudioPortClass = MakeGlobalRefOrDie(env, audioPortClass);
   1823     gAudioPortCstor = GetMethodIDOrDie(env, audioPortClass, "<init>",
   1824             "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
   1825     gAudioPortFields.mHandle = GetFieldIDOrDie(env, audioPortClass, "mHandle",
   1826                                                "Landroid/media/AudioHandle;");
   1827     gAudioPortFields.mRole = GetFieldIDOrDie(env, audioPortClass, "mRole", "I");
   1828     gAudioPortFields.mGains = GetFieldIDOrDie(env, audioPortClass, "mGains",
   1829                                               "[Landroid/media/AudioGain;");
   1830     gAudioPortFields.mActiveConfig = GetFieldIDOrDie(env, audioPortClass, "mActiveConfig",
   1831                                                      "Landroid/media/AudioPortConfig;");
   1832 
   1833     jclass audioPortConfigClass = FindClassOrDie(env, "android/media/AudioPortConfig");
   1834     gAudioPortConfigClass = MakeGlobalRefOrDie(env, audioPortConfigClass);
   1835     gAudioPortConfigCstor = GetMethodIDOrDie(env, audioPortConfigClass, "<init>",
   1836             "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
   1837     gAudioPortConfigFields.mPort = GetFieldIDOrDie(env, audioPortConfigClass, "mPort",
   1838                                                    "Landroid/media/AudioPort;");
   1839     gAudioPortConfigFields.mSamplingRate = GetFieldIDOrDie(env, audioPortConfigClass,
   1840                                                            "mSamplingRate", "I");
   1841     gAudioPortConfigFields.mChannelMask = GetFieldIDOrDie(env, audioPortConfigClass,
   1842                                                           "mChannelMask", "I");
   1843     gAudioPortConfigFields.mFormat = GetFieldIDOrDie(env, audioPortConfigClass, "mFormat", "I");
   1844     gAudioPortConfigFields.mGain = GetFieldIDOrDie(env, audioPortConfigClass, "mGain",
   1845                                                    "Landroid/media/AudioGainConfig;");
   1846     gAudioPortConfigFields.mConfigMask = GetFieldIDOrDie(env, audioPortConfigClass, "mConfigMask",
   1847                                                          "I");
   1848 
   1849     jclass audioDevicePortConfigClass = FindClassOrDie(env, "android/media/AudioDevicePortConfig");
   1850     gAudioDevicePortConfigClass = MakeGlobalRefOrDie(env, audioDevicePortConfigClass);
   1851     gAudioDevicePortConfigCstor = GetMethodIDOrDie(env, audioDevicePortConfigClass, "<init>",
   1852             "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
   1853 
   1854     jclass audioMixPortConfigClass = FindClassOrDie(env, "android/media/AudioMixPortConfig");
   1855     gAudioMixPortConfigClass = MakeGlobalRefOrDie(env, audioMixPortConfigClass);
   1856     gAudioMixPortConfigCstor = GetMethodIDOrDie(env, audioMixPortConfigClass, "<init>",
   1857             "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
   1858 
   1859     jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort");
   1860     gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
   1861     gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
   1862             "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
   1863 
   1864     jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
   1865     gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
   1866     gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
   1867             "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
   1868 
   1869     jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
   1870     gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
   1871     gAudioGainCstor = GetMethodIDOrDie(env, audioGainClass, "<init>", "(IIIIIIIII)V");
   1872 
   1873     jclass audioGainConfigClass = FindClassOrDie(env, "android/media/AudioGainConfig");
   1874     gAudioGainConfigClass = MakeGlobalRefOrDie(env, audioGainConfigClass);
   1875     gAudioGainConfigCstor = GetMethodIDOrDie(env, audioGainConfigClass, "<init>",
   1876                                              "(ILandroid/media/AudioGain;II[II)V");
   1877     gAudioGainConfigFields.mIndex = GetFieldIDOrDie(env, gAudioGainConfigClass, "mIndex", "I");
   1878     gAudioGainConfigFields.mMode = GetFieldIDOrDie(env, audioGainConfigClass, "mMode", "I");
   1879     gAudioGainConfigFields.mChannelMask = GetFieldIDOrDie(env, audioGainConfigClass, "mChannelMask",
   1880                                                           "I");
   1881     gAudioGainConfigFields.mValues = GetFieldIDOrDie(env, audioGainConfigClass, "mValues", "[I");
   1882     gAudioGainConfigFields.mRampDurationMs = GetFieldIDOrDie(env, audioGainConfigClass,
   1883                                                              "mRampDurationMs", "I");
   1884 
   1885     jclass audioPatchClass = FindClassOrDie(env, "android/media/AudioPatch");
   1886     gAudioPatchClass = MakeGlobalRefOrDie(env, audioPatchClass);
   1887     gAudioPatchCstor = GetMethodIDOrDie(env, audioPatchClass, "<init>",
   1888 "(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V");
   1889     gAudioPatchFields.mHandle = GetFieldIDOrDie(env, audioPatchClass, "mHandle",
   1890                                                 "Landroid/media/AudioHandle;");
   1891 
   1892     jclass eventHandlerClass = FindClassOrDie(env, kEventHandlerClassPathName);
   1893     gAudioPortEventHandlerMethods.postEventFromNative = GetStaticMethodIDOrDie(
   1894                                                     env, eventHandlerClass, "postEventFromNative",
   1895                                                     "(Ljava/lang/Object;IIILjava/lang/Object;)V");
   1896     gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
   1897                                                     eventHandlerClass, "mJniCallback", "J");
   1898 
   1899     gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative =
   1900             GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
   1901                     "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
   1902     gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
   1903             GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
   1904                     "recordingCallbackFromNative", "(III[I)V");
   1905 
   1906     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
   1907     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
   1908     gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
   1909                                                 "Landroid/media/audiopolicy/AudioMixingRule;");
   1910     gAudioMixFields.mFormat = GetFieldIDOrDie(env, audioMixClass, "mFormat",
   1911                                                 "Landroid/media/AudioFormat;");
   1912     gAudioMixFields.mRouteFlags = GetFieldIDOrDie(env, audioMixClass, "mRouteFlags", "I");
   1913     gAudioMixFields.mDeviceType = GetFieldIDOrDie(env, audioMixClass, "mDeviceSystemType", "I");
   1914     gAudioMixFields.mDeviceAddress = GetFieldIDOrDie(env, audioMixClass, "mDeviceAddress",
   1915                                                       "Ljava/lang/String;");
   1916     gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
   1917     gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
   1918 
   1919     jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
   1920     gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
   1921     gAudioFormatFields.mEncoding = GetFieldIDOrDie(env, audioFormatClass, "mEncoding", "I");
   1922     gAudioFormatFields.mSampleRate = GetFieldIDOrDie(env, audioFormatClass, "mSampleRate", "I");
   1923     gAudioFormatFields.mChannelMask = GetFieldIDOrDie(env, audioFormatClass, "mChannelMask", "I");
   1924 
   1925     jclass audioMixingRuleClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule");
   1926     gAudioMixingRuleClass = MakeGlobalRefOrDie(env, audioMixingRuleClass);
   1927     gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
   1928                                                        "Ljava/util/ArrayList;");
   1929 
   1930     jclass audioMixMatchCriterionClass =
   1931                 FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion");
   1932     gAudioMixMatchCriterionClass = MakeGlobalRefOrDie(env,audioMixMatchCriterionClass);
   1933     gAudioMixMatchCriterionFields.mAttr = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mAttr",
   1934                                                        "Landroid/media/AudioAttributes;");
   1935     gAudioMixMatchCriterionFields.mIntProp = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mIntProp",
   1936                                                        "I");
   1937     gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
   1938                                                        "I");
   1939 
   1940     jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
   1941     gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
   1942     gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
   1943     gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
   1944 
   1945     AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
   1946 
   1947     RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
   1948     return RegisterMethodsOrDie(env, kEventHandlerClassPathName, gEventHandlerMethods,
   1949                                 NELEM(gEventHandlerMethods));
   1950 }
   1951