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