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