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