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 <android_runtime/AndroidRuntime.h>
     26 
     27 #include <media/AudioSystem.h>
     28 
     29 #include <system/audio.h>
     30 #include <system/audio_policy.h>
     31 #include "android_media_AudioFormat.h"
     32 #include "android_media_AudioErrors.h"
     33 
     34 // ----------------------------------------------------------------------------
     35 
     36 using namespace android;
     37 
     38 static const char* const kClassPathName = "android/media/AudioSystem";
     39 
     40 static jclass gArrayListClass;
     41 static struct {
     42     jmethodID    add;
     43 } gArrayListMethods;
     44 
     45 static jclass gAudioHandleClass;
     46 static jmethodID gAudioHandleCstor;
     47 static struct {
     48     jfieldID    mId;
     49 } gAudioHandleFields;
     50 
     51 static jclass gAudioPortClass;
     52 static jmethodID gAudioPortCstor;
     53 static struct {
     54     jfieldID    mHandle;
     55     jfieldID    mRole;
     56     jfieldID    mGains;
     57     jfieldID    mActiveConfig;
     58     // other fields unused by JNI
     59 } gAudioPortFields;
     60 
     61 static jclass gAudioPortConfigClass;
     62 static jmethodID gAudioPortConfigCstor;
     63 static struct {
     64     jfieldID    mPort;
     65     jfieldID    mSamplingRate;
     66     jfieldID    mChannelMask;
     67     jfieldID    mFormat;
     68     jfieldID    mGain;
     69     jfieldID    mConfigMask;
     70 } gAudioPortConfigFields;
     71 
     72 static jclass gAudioDevicePortClass;
     73 static jmethodID gAudioDevicePortCstor;
     74 
     75 static jclass gAudioDevicePortConfigClass;
     76 static jmethodID gAudioDevicePortConfigCstor;
     77 
     78 static jclass gAudioMixPortClass;
     79 static jmethodID gAudioMixPortCstor;
     80 
     81 static jclass gAudioMixPortConfigClass;
     82 static jmethodID gAudioMixPortConfigCstor;
     83 
     84 static jclass gAudioGainClass;
     85 static jmethodID gAudioGainCstor;
     86 
     87 static jclass gAudioGainConfigClass;
     88 static jmethodID gAudioGainConfigCstor;
     89 static struct {
     90     jfieldID mIndex;
     91     jfieldID mMode;
     92     jfieldID mChannelMask;
     93     jfieldID mValues;
     94     jfieldID mRampDurationMs;
     95     // other fields unused by JNI
     96 } gAudioGainConfigFields;
     97 
     98 static jclass gAudioPatchClass;
     99 static jmethodID gAudioPatchCstor;
    100 static struct {
    101     jfieldID    mHandle;
    102     // other fields unused by JNI
    103 } gAudioPatchFields;
    104 
    105 static const char* const kEventHandlerClassPathName =
    106         "android/media/AudioPortEventHandler";
    107 static jmethodID gPostEventFromNative;
    108 
    109 enum AudioError {
    110     kAudioStatusOk = 0,
    111     kAudioStatusError = 1,
    112     kAudioStatusMediaServerDied = 100
    113 };
    114 
    115 enum  {
    116     AUDIOPORT_EVENT_PORT_LIST_UPDATED = 1,
    117     AUDIOPORT_EVENT_PATCH_LIST_UPDATED = 2,
    118     AUDIOPORT_EVENT_SERVICE_DIED = 3,
    119 };
    120 
    121 #define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
    122 
    123 // ----------------------------------------------------------------------------
    124 // ref-counted object for callbacks
    125 class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
    126 {
    127 public:
    128     JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
    129     ~JNIAudioPortCallback();
    130 
    131     virtual void onAudioPortListUpdate();
    132     virtual void onAudioPatchListUpdate();
    133     virtual void onServiceDied();
    134 
    135 private:
    136     void sendEvent(int event);
    137 
    138     jclass      mClass;     // Reference to AudioPortEventHandlerDelegate class
    139     jobject     mObject;    // Weak ref to AudioPortEventHandlerDelegate Java object to call on
    140 };
    141 
    142 JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
    143 {
    144 
    145     // Hold onto the SoundTriggerModule class for use in calling the static method
    146     // that posts events to the application thread.
    147     jclass clazz = env->GetObjectClass(thiz);
    148     if (clazz == NULL) {
    149         ALOGE("Can't find class %s", kEventHandlerClassPathName);
    150         return;
    151     }
    152     mClass = (jclass)env->NewGlobalRef(clazz);
    153 
    154     // We use a weak reference so the SoundTriggerModule object can be garbage collected.
    155     // The reference is only used as a proxy for callbacks.
    156     mObject  = env->NewGlobalRef(weak_thiz);
    157 }
    158 
    159 JNIAudioPortCallback::~JNIAudioPortCallback()
    160 {
    161     // remove global references
    162     JNIEnv *env = AndroidRuntime::getJNIEnv();
    163     env->DeleteGlobalRef(mObject);
    164     env->DeleteGlobalRef(mClass);
    165 }
    166 
    167 void JNIAudioPortCallback::sendEvent(int event)
    168 {
    169     JNIEnv *env = AndroidRuntime::getJNIEnv();
    170 
    171     env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
    172                               event, 0, 0, NULL);
    173     if (env->ExceptionCheck()) {
    174         ALOGW("An exception occurred while notifying an event.");
    175         env->ExceptionClear();
    176     }
    177 }
    178 
    179 void JNIAudioPortCallback::onAudioPortListUpdate()
    180 {
    181     sendEvent(AUDIOPORT_EVENT_PORT_LIST_UPDATED);
    182 }
    183 
    184 void JNIAudioPortCallback::onAudioPatchListUpdate()
    185 {
    186     sendEvent(AUDIOPORT_EVENT_PATCH_LIST_UPDATED);
    187 }
    188 
    189 void JNIAudioPortCallback::onServiceDied()
    190 {
    191     sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
    192 }
    193 
    194 static int check_AudioSystem_Command(status_t status)
    195 {
    196     switch (status) {
    197     case DEAD_OBJECT:
    198         return kAudioStatusMediaServerDied;
    199     case NO_ERROR:
    200         return kAudioStatusOk;
    201     default:
    202         break;
    203     }
    204     return kAudioStatusError;
    205 }
    206 
    207 static jint
    208 android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
    209 {
    210     return (jint) check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
    211 }
    212 
    213 static jboolean
    214 android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
    215 {
    216     bool state = false;
    217     AudioSystem::isMicrophoneMuted(&state);
    218     return state;
    219 }
    220 
    221 static jboolean
    222 android_media_AudioSystem_isStreamActive(JNIEnv *env, jobject thiz, jint stream, jint inPastMs)
    223 {
    224     bool state = false;
    225     AudioSystem::isStreamActive((audio_stream_type_t) stream, &state, inPastMs);
    226     return state;
    227 }
    228 
    229 static jboolean
    230 android_media_AudioSystem_isStreamActiveRemotely(JNIEnv *env, jobject thiz, jint stream,
    231         jint inPastMs)
    232 {
    233     bool state = false;
    234     AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
    235     return state;
    236 }
    237 
    238 static jboolean
    239 android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
    240 {
    241     bool state = false;
    242     AudioSystem::isSourceActive((audio_source_t) source, &state);
    243     return state;
    244 }
    245 
    246 static jint
    247 android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
    248 {
    249     return AudioSystem::newAudioUniqueId();
    250 }
    251 
    252 static jint
    253 android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
    254 {
    255     const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
    256     String8 c_keyValuePairs8;
    257     if (keyValuePairs) {
    258         c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
    259         env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
    260     }
    261     int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
    262     return (jint) status;
    263 }
    264 
    265 static jstring
    266 android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
    267 {
    268     const jchar* c_keys = env->GetStringCritical(keys, 0);
    269     String8 c_keys8;
    270     if (keys) {
    271         c_keys8 = String8(c_keys, env->GetStringLength(keys));
    272         env->ReleaseStringCritical(keys, c_keys);
    273     }
    274     return env->NewStringUTF(AudioSystem::getParameters(c_keys8).string());
    275 }
    276 
    277 static void
    278 android_media_AudioSystem_error_callback(status_t err)
    279 {
    280     JNIEnv *env = AndroidRuntime::getJNIEnv();
    281     if (env == NULL) {
    282         return;
    283     }
    284 
    285     jclass clazz = env->FindClass(kClassPathName);
    286 
    287     env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
    288                               "errorCallbackFromNative","(I)V"),
    289                               check_AudioSystem_Command(err));
    290 
    291     env->DeleteLocalRef(clazz);
    292 }
    293 
    294 static jint
    295 android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
    296 {
    297     const char *c_address = env->GetStringUTFChars(device_address, NULL);
    298     int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
    299                                           static_cast <audio_policy_dev_state_t>(state),
    300                                           c_address));
    301     env->ReleaseStringUTFChars(device_address, c_address);
    302     return (jint) status;
    303 }
    304 
    305 static jint
    306 android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
    307 {
    308     const char *c_address = env->GetStringUTFChars(device_address, NULL);
    309     int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
    310                                           c_address));
    311     env->ReleaseStringUTFChars(device_address, c_address);
    312     return (jint) state;
    313 }
    314 
    315 static jint
    316 android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
    317 {
    318     return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
    319 }
    320 
    321 static jint
    322 android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
    323 {
    324     return (jint) check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
    325                                                            static_cast <audio_policy_forced_cfg_t>(config)));
    326 }
    327 
    328 static jint
    329 android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
    330 {
    331     return static_cast <jint>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
    332 }
    333 
    334 static jint
    335 android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
    336 {
    337     return (jint) check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
    338                                                                    indexMin,
    339                                                                    indexMax));
    340 }
    341 
    342 static jint
    343 android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
    344                                                jobject thiz,
    345                                                jint stream,
    346                                                jint index,
    347                                                jint device)
    348 {
    349     return (jint) check_AudioSystem_Command(
    350             AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
    351                                               index,
    352                                               (audio_devices_t)device));
    353 }
    354 
    355 static jint
    356 android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env,
    357                                                jobject thiz,
    358                                                jint stream,
    359                                                jint device)
    360 {
    361     int index;
    362     if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
    363                                           &index,
    364                                           (audio_devices_t)device)
    365             != NO_ERROR) {
    366         index = -1;
    367     }
    368     return (jint) index;
    369 }
    370 
    371 static jint
    372 android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
    373 {
    374     return (jint) check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
    375 }
    376 
    377 static jfloat
    378 android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
    379 {
    380     float value;
    381     if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
    382         value = -1.0;
    383     }
    384     return value;
    385 }
    386 
    387 static jint
    388 android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
    389 {
    390     return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
    391 }
    392 
    393 static jfloat
    394 android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
    395 {
    396     bool mute;
    397     if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
    398         mute = false;
    399     }
    400     return mute;
    401 }
    402 
    403 static jint
    404 android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
    405 {
    406     return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
    407 }
    408 
    409 static jint
    410 android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
    411 {
    412     return (jint) AudioSystem::getPrimaryOutputSamplingRate();
    413 }
    414 
    415 static jint
    416 android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
    417 {
    418     return (jint) AudioSystem::getPrimaryOutputFrameCount();
    419 }
    420 
    421 static jint
    422 android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
    423 {
    424     uint32_t afLatency;
    425     if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
    426             != NO_ERROR) {
    427         afLatency = -1;
    428     }
    429     return (jint) afLatency;
    430 }
    431 
    432 static jint
    433 android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
    434 {
    435     return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
    436 }
    437 
    438 static jint
    439 android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
    440 {
    441     return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
    442 }
    443 
    444 
    445 static bool useInChannelMask(audio_port_type_t type, audio_port_role_t role)
    446 {
    447     return ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
    448                 ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
    449 }
    450 
    451 static void convertAudioGainConfigToNative(JNIEnv *env,
    452                                                struct audio_gain_config *nAudioGainConfig,
    453                                                const jobject jAudioGainConfig,
    454                                                bool useInMask)
    455 {
    456     nAudioGainConfig->index = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mIndex);
    457     nAudioGainConfig->mode = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
    458     ALOGV("convertAudioGainConfigToNative got gain index %d", nAudioGainConfig->index);
    459     jint jMask = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mChannelMask);
    460     audio_channel_mask_t nMask;
    461     if (useInMask) {
    462         nMask = inChannelMaskToNative(jMask);
    463         ALOGV("convertAudioGainConfigToNative IN mask java %x native %x", jMask, nMask);
    464     } else {
    465         nMask = outChannelMaskToNative(jMask);
    466         ALOGV("convertAudioGainConfigToNative OUT mask java %x native %x", jMask, nMask);
    467     }
    468     nAudioGainConfig->channel_mask = nMask;
    469     nAudioGainConfig->ramp_duration_ms = env->GetIntField(jAudioGainConfig,
    470                                                        gAudioGainConfigFields.mRampDurationMs);
    471     jintArray jValues = (jintArray)env->GetObjectField(jAudioGainConfig,
    472                                                        gAudioGainConfigFields.mValues);
    473     int *nValues = env->GetIntArrayElements(jValues, NULL);
    474     size_t size = env->GetArrayLength(jValues);
    475     memcpy(nAudioGainConfig->values, nValues, size * sizeof(int));
    476     env->DeleteLocalRef(jValues);
    477 }
    478 
    479 
    480 static jint convertAudioPortConfigToNative(JNIEnv *env,
    481                                                struct audio_port_config *nAudioPortConfig,
    482                                                const jobject jAudioPortConfig)
    483 {
    484     jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
    485     jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
    486     nAudioPortConfig->id = env->GetIntField(jHandle, gAudioHandleFields.mId);
    487     nAudioPortConfig->role = (audio_port_role_t)env->GetIntField(jAudioPort,
    488                                                                  gAudioPortFields.mRole);
    489     if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
    490         nAudioPortConfig->type = AUDIO_PORT_TYPE_DEVICE;
    491     } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
    492         nAudioPortConfig->type = AUDIO_PORT_TYPE_MIX;
    493     } else {
    494         env->DeleteLocalRef(jAudioPort);
    495         env->DeleteLocalRef(jHandle);
    496         return (jint)AUDIO_JAVA_ERROR;
    497     }
    498     ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
    499           nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
    500 
    501     nAudioPortConfig->sample_rate = env->GetIntField(jAudioPortConfig,
    502                                                      gAudioPortConfigFields.mSamplingRate);
    503 
    504     bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
    505     audio_channel_mask_t nMask;
    506     jint jMask = env->GetIntField(jAudioPortConfig,
    507                                    gAudioPortConfigFields.mChannelMask);
    508     if (useInMask) {
    509         nMask = inChannelMaskToNative(jMask);
    510         ALOGV("convertAudioPortConfigToNative IN mask java %x native %x", jMask, nMask);
    511     } else {
    512         nMask = outChannelMaskToNative(jMask);
    513         ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
    514     }
    515     nAudioPortConfig->channel_mask = nMask;
    516 
    517     jint jFormat = env->GetIntField(jAudioPortConfig, gAudioPortConfigFields.mFormat);
    518     audio_format_t nFormat = audioFormatToNative(jFormat);
    519     ALOGV("convertAudioPortConfigToNative format %d native %d", jFormat, nFormat);
    520     nAudioPortConfig->format = nFormat;
    521     jobject jGain = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mGain);
    522     if (jGain != NULL) {
    523         convertAudioGainConfigToNative(env, &nAudioPortConfig->gain, jGain, useInMask);
    524         env->DeleteLocalRef(jGain);
    525     } else {
    526         ALOGV("convertAudioPortConfigToNative no gain");
    527         nAudioPortConfig->gain.index = -1;
    528     }
    529     nAudioPortConfig->config_mask = env->GetIntField(jAudioPortConfig,
    530                                                      gAudioPortConfigFields.mConfigMask);
    531 
    532     env->DeleteLocalRef(jAudioPort);
    533     env->DeleteLocalRef(jHandle);
    534     return (jint)AUDIO_JAVA_SUCCESS;
    535 }
    536 
    537 static jint convertAudioPortConfigFromNative(JNIEnv *env,
    538                                                  jobject jAudioPort,
    539                                                  jobject *jAudioPortConfig,
    540                                                  const struct audio_port_config *nAudioPortConfig)
    541 {
    542     jint jStatus = AUDIO_JAVA_SUCCESS;
    543     jobject jAudioGainConfig = NULL;
    544     jobject jAudioGain = NULL;
    545     jintArray jGainValues;
    546     bool audioportCreated = false;
    547 
    548     ALOGV("convertAudioPortConfigFromNative jAudioPort %p", jAudioPort);
    549 
    550     if (jAudioPort == NULL) {
    551         jobject jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
    552                                                  nAudioPortConfig->id);
    553 
    554         ALOGV("convertAudioPortConfigFromNative handle %d is a %s", nAudioPortConfig->id,
    555               nAudioPortConfig->type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix");
    556 
    557         if (jHandle == NULL) {
    558             return (jint)AUDIO_JAVA_ERROR;
    559         }
    560         // create dummy port and port config objects with just the correct handle
    561         // and configuration data. The actual AudioPortConfig objects will be
    562         // constructed by java code with correct class type (device, mix etc...)
    563         // and reference to AudioPort instance in this client
    564         jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
    565                                            jHandle,
    566                                            0,
    567                                            NULL,
    568                                            NULL,
    569                                            NULL,
    570                                            NULL);
    571         env->DeleteLocalRef(jHandle);
    572         if (jAudioPort == NULL) {
    573             return (jint)AUDIO_JAVA_ERROR;
    574         }
    575         ALOGV("convertAudioPortConfigFromNative jAudioPort created for handle %d",
    576               nAudioPortConfig->id);
    577 
    578         audioportCreated = true;
    579     }
    580 
    581     bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
    582 
    583     audio_channel_mask_t nMask;
    584     jint jMask;
    585 
    586     int gainIndex = nAudioPortConfig->gain.index;
    587     if (gainIndex >= 0) {
    588         ALOGV("convertAudioPortConfigFromNative gain found with index %d mode %x",
    589               gainIndex, nAudioPortConfig->gain.mode);
    590         if (audioportCreated) {
    591             ALOGV("convertAudioPortConfigFromNative creating gain");
    592             jAudioGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
    593                                                gainIndex,
    594                                                0,
    595                                                0,
    596                                                0,
    597                                                0,
    598                                                0,
    599                                                0,
    600                                                0,
    601                                                0);
    602             if (jAudioGain == NULL) {
    603                 ALOGV("convertAudioPortConfigFromNative creating gain FAILED");
    604                 jStatus = (jint)AUDIO_JAVA_ERROR;
    605                 goto exit;
    606             }
    607         } else {
    608             ALOGV("convertAudioPortConfigFromNative reading gain from port");
    609             jobjectArray jGains = (jobjectArray)env->GetObjectField(jAudioPort,
    610                                                                       gAudioPortFields.mGains);
    611             if (jGains == NULL) {
    612                 ALOGV("convertAudioPortConfigFromNative could not get gains from port");
    613                 jStatus = (jint)AUDIO_JAVA_ERROR;
    614                 goto exit;
    615             }
    616             jAudioGain = env->GetObjectArrayElement(jGains, gainIndex);
    617             env->DeleteLocalRef(jGains);
    618             if (jAudioGain == NULL) {
    619                 ALOGV("convertAudioPortConfigFromNative could not get gain at index %d", gainIndex);
    620                 jStatus = (jint)AUDIO_JAVA_ERROR;
    621                 goto exit;
    622             }
    623         }
    624         int numValues;
    625         if (useInMask) {
    626             numValues = audio_channel_count_from_in_mask(nAudioPortConfig->gain.channel_mask);
    627         } else {
    628             numValues = audio_channel_count_from_out_mask(nAudioPortConfig->gain.channel_mask);
    629         }
    630         jGainValues = env->NewIntArray(numValues);
    631         if (jGainValues == NULL) {
    632             ALOGV("convertAudioPortConfigFromNative could not create gain values %d", numValues);
    633             jStatus = (jint)AUDIO_JAVA_ERROR;
    634             goto exit;
    635         }
    636         env->SetIntArrayRegion(jGainValues, 0, numValues,
    637                                nAudioPortConfig->gain.values);
    638 
    639         nMask = nAudioPortConfig->gain.channel_mask;
    640         if (useInMask) {
    641             jMask = inChannelMaskFromNative(nMask);
    642             ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
    643         } else {
    644             jMask = outChannelMaskFromNative(nMask);
    645             ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
    646         }
    647 
    648         jAudioGainConfig = env->NewObject(gAudioGainConfigClass,
    649                                         gAudioGainConfigCstor,
    650                                         gainIndex,
    651                                         jAudioGain,
    652                                         nAudioPortConfig->gain.mode,
    653                                         jMask,
    654                                         jGainValues,
    655                                         nAudioPortConfig->gain.ramp_duration_ms);
    656         env->DeleteLocalRef(jGainValues);
    657         if (jAudioGainConfig == NULL) {
    658             ALOGV("convertAudioPortConfigFromNative could not create gain config");
    659             jStatus = (jint)AUDIO_JAVA_ERROR;
    660             goto exit;
    661         }
    662     }
    663     jclass clazz;
    664     jmethodID methodID;
    665     if (audioportCreated) {
    666         clazz = gAudioPortConfigClass;
    667         methodID = gAudioPortConfigCstor;
    668         ALOGV("convertAudioPortConfigFromNative building a generic port config");
    669     } else {
    670         if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
    671             clazz = gAudioDevicePortConfigClass;
    672             methodID = gAudioDevicePortConfigCstor;
    673             ALOGV("convertAudioPortConfigFromNative building a device config");
    674         } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
    675             clazz = gAudioMixPortConfigClass;
    676             methodID = gAudioMixPortConfigCstor;
    677             ALOGV("convertAudioPortConfigFromNative building a mix config");
    678         } else {
    679             jStatus = (jint)AUDIO_JAVA_ERROR;
    680             goto exit;
    681         }
    682     }
    683     nMask = nAudioPortConfig->channel_mask;
    684     if (useInMask) {
    685         jMask = inChannelMaskFromNative(nMask);
    686         ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
    687     } else {
    688         jMask = outChannelMaskFromNative(nMask);
    689         ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
    690     }
    691 
    692     *jAudioPortConfig = env->NewObject(clazz, methodID,
    693                                        jAudioPort,
    694                                        nAudioPortConfig->sample_rate,
    695                                        jMask,
    696                                        audioFormatFromNative(nAudioPortConfig->format),
    697                                        jAudioGainConfig);
    698     if (*jAudioPortConfig == NULL) {
    699         ALOGV("convertAudioPortConfigFromNative could not create new port config");
    700         jStatus = (jint)AUDIO_JAVA_ERROR;
    701     } else {
    702         ALOGV("convertAudioPortConfigFromNative OK");
    703     }
    704 
    705 exit:
    706     if (audioportCreated) {
    707         env->DeleteLocalRef(jAudioPort);
    708         if (jAudioGain != NULL) {
    709             env->DeleteLocalRef(jAudioGain);
    710         }
    711     }
    712     if (jAudioGainConfig != NULL) {
    713         env->DeleteLocalRef(jAudioGainConfig);
    714     }
    715     return jStatus;
    716 }
    717 
    718 static jint convertAudioPortFromNative(JNIEnv *env,
    719                                            jobject *jAudioPort, const struct audio_port *nAudioPort)
    720 {
    721     jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
    722     jintArray jSamplingRates = NULL;
    723     jintArray jChannelMasks = NULL;
    724     jintArray jFormats = NULL;
    725     jobjectArray jGains = NULL;
    726     jobject jHandle = NULL;
    727     bool useInMask;
    728 
    729     ALOGV("convertAudioPortFromNative id %d role %d type %d",
    730                                   nAudioPort->id, nAudioPort->role, nAudioPort->type);
    731 
    732     jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
    733     if (jSamplingRates == NULL) {
    734         jStatus = (jint)AUDIO_JAVA_ERROR;
    735         goto exit;
    736     }
    737     if (nAudioPort->num_sample_rates) {
    738         env->SetIntArrayRegion(jSamplingRates, 0, nAudioPort->num_sample_rates,
    739                                (jint *)nAudioPort->sample_rates);
    740     }
    741 
    742     jChannelMasks = env->NewIntArray(nAudioPort->num_channel_masks);
    743     if (jChannelMasks == NULL) {
    744         jStatus = (jint)AUDIO_JAVA_ERROR;
    745         goto exit;
    746     }
    747     useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
    748 
    749     jint jMask;
    750     for (size_t j = 0; j < nAudioPort->num_channel_masks; j++) {
    751         if (useInMask) {
    752             jMask = inChannelMaskFromNative(nAudioPort->channel_masks[j]);
    753         } else {
    754             jMask = outChannelMaskFromNative(nAudioPort->channel_masks[j]);
    755         }
    756         env->SetIntArrayRegion(jChannelMasks, j, 1, &jMask);
    757     }
    758 
    759     jFormats = env->NewIntArray(nAudioPort->num_formats);
    760     if (jFormats == NULL) {
    761         jStatus = (jint)AUDIO_JAVA_ERROR;
    762         goto exit;
    763     }
    764     for (size_t j = 0; j < nAudioPort->num_formats; j++) {
    765         jint jFormat = audioFormatFromNative(nAudioPort->formats[j]);
    766         env->SetIntArrayRegion(jFormats, j, 1, &jFormat);
    767     }
    768 
    769     jGains = env->NewObjectArray(nAudioPort->num_gains,
    770                                           gAudioGainClass, NULL);
    771     if (jGains == NULL) {
    772         jStatus = (jint)AUDIO_JAVA_ERROR;
    773         goto exit;
    774     }
    775     for (size_t j = 0; j < nAudioPort->num_gains; j++) {
    776         audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
    777         if (useInMask) {
    778             jMask = inChannelMaskFromNative(nMask);
    779             ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
    780         } else {
    781             jMask = outChannelMaskFromNative(nMask);
    782             ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
    783         }
    784 
    785         jobject jGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
    786                                                  j,
    787                                                  nAudioPort->gains[j].mode,
    788                                                  jMask,
    789                                                  nAudioPort->gains[j].min_value,
    790                                                  nAudioPort->gains[j].max_value,
    791                                                  nAudioPort->gains[j].default_value,
    792                                                  nAudioPort->gains[j].step_value,
    793                                                  nAudioPort->gains[j].min_ramp_ms,
    794                                                  nAudioPort->gains[j].max_ramp_ms);
    795         if (jGain == NULL) {
    796             jStatus = (jint)AUDIO_JAVA_ERROR;
    797             goto exit;
    798         }
    799         env->SetObjectArrayElement(jGains, j, jGain);
    800         env->DeleteLocalRef(jGain);
    801     }
    802 
    803     jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
    804                                              nAudioPort->id);
    805     if (jHandle == NULL) {
    806         jStatus = (jint)AUDIO_JAVA_ERROR;
    807         goto exit;
    808     }
    809 
    810     if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
    811         ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
    812         jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
    813         *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
    814                                      jHandle, jSamplingRates, jChannelMasks, jFormats, jGains,
    815                                      nAudioPort->ext.device.type, jAddress);
    816         env->DeleteLocalRef(jAddress);
    817     } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
    818         ALOGV("convertAudioPortFromNative is a mix");
    819         *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
    820                                      jHandle, nAudioPort->role, jSamplingRates, jChannelMasks,
    821                                      jFormats, jGains);
    822     } else {
    823         ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
    824         jStatus = (jint)AUDIO_JAVA_ERROR;
    825         goto exit;
    826     }
    827     if (*jAudioPort == NULL) {
    828         jStatus = (jint)AUDIO_JAVA_ERROR;
    829         goto exit;
    830     }
    831 
    832     jobject jAudioPortConfig;
    833     jStatus = convertAudioPortConfigFromNative(env,
    834                                                        *jAudioPort,
    835                                                        &jAudioPortConfig,
    836                                                        &nAudioPort->active_config);
    837     if (jStatus != AUDIO_JAVA_SUCCESS) {
    838         return jStatus;
    839     }
    840 
    841     env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
    842 
    843 exit:
    844     if (jSamplingRates != NULL) {
    845         env->DeleteLocalRef(jSamplingRates);
    846     }
    847     if (jChannelMasks != NULL) {
    848         env->DeleteLocalRef(jChannelMasks);
    849     }
    850     if (jFormats != NULL) {
    851         env->DeleteLocalRef(jFormats);
    852     }
    853     if (jGains != NULL) {
    854         env->DeleteLocalRef(jGains);
    855     }
    856     if (jHandle != NULL) {
    857         env->DeleteLocalRef(jHandle);
    858     }
    859 
    860     return jStatus;
    861 }
    862 
    863 
    864 static jint
    865 android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
    866                                          jobject jPorts, jintArray jGeneration)
    867 {
    868     ALOGV("listAudioPorts");
    869 
    870     if (jPorts == NULL) {
    871         ALOGE("listAudioPorts NULL AudioPort ArrayList");
    872         return (jint)AUDIO_JAVA_BAD_VALUE;
    873     }
    874     if (!env->IsInstanceOf(jPorts, gArrayListClass)) {
    875         ALOGE("listAudioPorts not an arraylist");
    876         return (jint)AUDIO_JAVA_BAD_VALUE;
    877     }
    878 
    879     if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
    880         return (jint)AUDIO_JAVA_BAD_VALUE;
    881     }
    882 
    883     status_t status;
    884     unsigned int generation1;
    885     unsigned int generation;
    886     unsigned int numPorts;
    887     jint *nGeneration;
    888     struct audio_port *nPorts = NULL;
    889     int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
    890 
    891     // get the port count and all the ports until they both return the same generation
    892     do {
    893         if (attempts-- < 0) {
    894             status = TIMED_OUT;
    895             break;
    896         }
    897 
    898         numPorts = 0;
    899         status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
    900                                              AUDIO_PORT_TYPE_NONE,
    901                                                       &numPorts,
    902                                                       NULL,
    903                                                       &generation1);
    904         if (status != NO_ERROR || numPorts == 0) {
    905             ALOGE_IF(status != NO_ERROR, "AudioSystem::listAudioPorts error %d", status);
    906             break;
    907         }
    908         nPorts = (struct audio_port *)realloc(nPorts, numPorts * sizeof(struct audio_port));
    909 
    910         status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
    911                                              AUDIO_PORT_TYPE_NONE,
    912                                                       &numPorts,
    913                                                       nPorts,
    914                                                       &generation);
    915         ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
    916               numPorts, generation, generation1);
    917     } while (generation1 != generation && status == NO_ERROR);
    918 
    919     jint jStatus = nativeToJavaStatus(status);
    920     if (jStatus != AUDIO_JAVA_SUCCESS) {
    921         goto exit;
    922     }
    923 
    924     nGeneration = env->GetIntArrayElements(jGeneration, NULL);
    925     if (nGeneration == NULL) {
    926         jStatus = (jint)AUDIO_JAVA_ERROR;
    927         goto exit;
    928     }
    929     nGeneration[0] = generation1;
    930     env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
    931 
    932     for (size_t i = 0; i < numPorts; i++) {
    933         jobject jAudioPort;
    934         jStatus = convertAudioPortFromNative(env, &jAudioPort, &nPorts[i]);
    935         if (jStatus != AUDIO_JAVA_SUCCESS) {
    936             goto exit;
    937         }
    938         env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort);
    939     }
    940 
    941 exit:
    942     free(nPorts);
    943     return jStatus;
    944 }
    945 
    946 static int
    947 android_media_AudioSystem_createAudioPatch(JNIEnv *env, jobject clazz,
    948                                  jobjectArray jPatches, jobjectArray jSources, jobjectArray jSinks)
    949 {
    950     status_t status;
    951     jint jStatus;
    952 
    953     ALOGV("createAudioPatch");
    954     if (jPatches == NULL || jSources == NULL || jSinks == NULL) {
    955         return (jint)AUDIO_JAVA_BAD_VALUE;
    956     }
    957 
    958     if (env->GetArrayLength(jPatches) != 1) {
    959         return (jint)AUDIO_JAVA_BAD_VALUE;
    960     }
    961     jint numSources = env->GetArrayLength(jSources);
    962     if (numSources == 0 || numSources > AUDIO_PATCH_PORTS_MAX) {
    963         return (jint)AUDIO_JAVA_BAD_VALUE;
    964     }
    965 
    966     jint numSinks = env->GetArrayLength(jSinks);
    967     if (numSinks == 0 || numSinks > AUDIO_PATCH_PORTS_MAX) {
    968         return (jint)AUDIO_JAVA_BAD_VALUE;
    969     }
    970 
    971     audio_patch_handle_t handle = (audio_patch_handle_t)0;
    972     jobject jPatch = env->GetObjectArrayElement(jPatches, 0);
    973     jobject jPatchHandle = NULL;
    974     if (jPatch != NULL) {
    975         if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
    976             return (jint)AUDIO_JAVA_BAD_VALUE;
    977         }
    978         jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
    979         handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
    980     }
    981 
    982     struct audio_patch nPatch;
    983 
    984     nPatch.id = handle;
    985     nPatch.num_sources = 0;
    986     nPatch.num_sinks = 0;
    987     jobject jSource = NULL;
    988     jobject jSink = NULL;
    989 
    990     for (jint i = 0; i < numSources; i++) {
    991         jSource = env->GetObjectArrayElement(jSources, i);
    992         if (!env->IsInstanceOf(jSource, gAudioPortConfigClass)) {
    993             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
    994             goto exit;
    995         }
    996         jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource);
    997         env->DeleteLocalRef(jSource);
    998         jSource = NULL;
    999         if (jStatus != AUDIO_JAVA_SUCCESS) {
   1000             goto exit;
   1001         }
   1002         nPatch.num_sources++;
   1003     }
   1004 
   1005     for (jint i = 0; i < numSinks; i++) {
   1006         jSink = env->GetObjectArrayElement(jSinks, i);
   1007         if (!env->IsInstanceOf(jSink, gAudioPortConfigClass)) {
   1008             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
   1009             goto exit;
   1010         }
   1011         jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink);
   1012         env->DeleteLocalRef(jSink);
   1013         jSink = NULL;
   1014         if (jStatus != AUDIO_JAVA_SUCCESS) {
   1015             goto exit;
   1016         }
   1017         nPatch.num_sinks++;
   1018     }
   1019 
   1020     ALOGV("AudioSystem::createAudioPatch");
   1021     status = AudioSystem::createAudioPatch(&nPatch, &handle);
   1022     ALOGV("AudioSystem::createAudioPatch() returned %d hande %d", status, handle);
   1023 
   1024     jStatus = nativeToJavaStatus(status);
   1025     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1026         goto exit;
   1027     }
   1028 
   1029     if (jPatchHandle == NULL) {
   1030         jPatchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
   1031                                            handle);
   1032         if (jPatchHandle == NULL) {
   1033             jStatus = (jint)AUDIO_JAVA_ERROR;
   1034             goto exit;
   1035         }
   1036         jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle, jSources, jSinks);
   1037         if (jPatch == NULL) {
   1038             jStatus = (jint)AUDIO_JAVA_ERROR;
   1039             goto exit;
   1040         }
   1041         env->SetObjectArrayElement(jPatches, 0, jPatch);
   1042     } else {
   1043         env->SetIntField(jPatchHandle, gAudioHandleFields.mId, handle);
   1044     }
   1045 
   1046 exit:
   1047     if (jPatchHandle != NULL) {
   1048         env->DeleteLocalRef(jPatchHandle);
   1049     }
   1050     if (jPatch != NULL) {
   1051         env->DeleteLocalRef(jPatch);
   1052     }
   1053     if (jSource != NULL) {
   1054         env->DeleteLocalRef(jSource);
   1055     }
   1056     if (jSink != NULL) {
   1057         env->DeleteLocalRef(jSink);
   1058     }
   1059     return jStatus;
   1060 }
   1061 
   1062 static int
   1063 android_media_AudioSystem_releaseAudioPatch(JNIEnv *env, jobject clazz,
   1064                                                jobject jPatch)
   1065 {
   1066     ALOGV("releaseAudioPatch");
   1067     if (jPatch == NULL) {
   1068         return (jint)AUDIO_JAVA_BAD_VALUE;
   1069     }
   1070 
   1071     audio_patch_handle_t handle = (audio_patch_handle_t)0;
   1072     jobject jPatchHandle = NULL;
   1073     if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
   1074         return (jint)AUDIO_JAVA_BAD_VALUE;
   1075     }
   1076     jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
   1077     handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
   1078     env->DeleteLocalRef(jPatchHandle);
   1079 
   1080     ALOGV("AudioSystem::releaseAudioPatch");
   1081     status_t status = AudioSystem::releaseAudioPatch(handle);
   1082     ALOGV("AudioSystem::releaseAudioPatch() returned %d", status);
   1083     jint jStatus = nativeToJavaStatus(status);
   1084     return status;
   1085 }
   1086 
   1087 static jint
   1088 android_media_AudioSystem_listAudioPatches(JNIEnv *env, jobject clazz,
   1089                                            jobject jPatches, jintArray jGeneration)
   1090 {
   1091     ALOGV("listAudioPatches");
   1092     if (jPatches == NULL) {
   1093         ALOGE("listAudioPatches NULL AudioPatch ArrayList");
   1094         return (jint)AUDIO_JAVA_BAD_VALUE;
   1095     }
   1096     if (!env->IsInstanceOf(jPatches, gArrayListClass)) {
   1097         ALOGE("listAudioPatches not an arraylist");
   1098         return (jint)AUDIO_JAVA_BAD_VALUE;
   1099     }
   1100 
   1101     if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
   1102         return (jint)AUDIO_JAVA_BAD_VALUE;
   1103     }
   1104 
   1105     status_t status;
   1106     unsigned int generation1;
   1107     unsigned int generation;
   1108     unsigned int numPatches;
   1109     jint *nGeneration;
   1110     struct audio_patch *nPatches = NULL;
   1111     jobjectArray jSources = NULL;
   1112     jobject jSource = NULL;
   1113     jobjectArray jSinks = NULL;
   1114     jobject jSink = NULL;
   1115     jobject jPatch = NULL;
   1116     int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
   1117 
   1118     // get the patch count and all the patches until they both return the same generation
   1119     do {
   1120         if (attempts-- < 0) {
   1121             status = TIMED_OUT;
   1122             break;
   1123         }
   1124 
   1125         numPatches = 0;
   1126         status = AudioSystem::listAudioPatches(&numPatches,
   1127                                                NULL,
   1128                                                &generation1);
   1129         if (status != NO_ERROR || numPatches == 0) {
   1130             ALOGE_IF(status != NO_ERROR, "listAudioPatches AudioSystem::listAudioPatches error %d",
   1131                                       status);
   1132             break;
   1133         }
   1134         nPatches = (struct audio_patch *)realloc(nPatches, numPatches * sizeof(struct audio_patch));
   1135 
   1136         status = AudioSystem::listAudioPatches(&numPatches,
   1137                                                nPatches,
   1138                                                &generation);
   1139         ALOGV("listAudioPatches AudioSystem::listAudioPatches numPatches %d generation %d generation1 %d",
   1140               numPatches, generation, generation1);
   1141 
   1142     } while (generation1 != generation && status == NO_ERROR);
   1143 
   1144     jint jStatus = nativeToJavaStatus(status);
   1145     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1146         goto exit;
   1147     }
   1148 
   1149     nGeneration = env->GetIntArrayElements(jGeneration, NULL);
   1150     if (nGeneration == NULL) {
   1151         jStatus = AUDIO_JAVA_ERROR;
   1152         goto exit;
   1153     }
   1154     nGeneration[0] = generation1;
   1155     env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
   1156 
   1157     for (size_t i = 0; i < numPatches; i++) {
   1158         jobject patchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
   1159                                                  nPatches[i].id);
   1160         if (patchHandle == NULL) {
   1161             jStatus = AUDIO_JAVA_ERROR;
   1162             goto exit;
   1163         }
   1164         ALOGV("listAudioPatches patch %d num_sources %d num_sinks %d",
   1165               i, nPatches[i].num_sources, nPatches[i].num_sinks);
   1166 
   1167         env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
   1168 
   1169         // load sources
   1170         jSources = env->NewObjectArray(nPatches[i].num_sources,
   1171                                        gAudioPortConfigClass, NULL);
   1172         if (jSources == NULL) {
   1173             jStatus = AUDIO_JAVA_ERROR;
   1174             goto exit;
   1175         }
   1176 
   1177         for (size_t j = 0; j < nPatches[i].num_sources; j++) {
   1178             jStatus = convertAudioPortConfigFromNative(env,
   1179                                                       NULL,
   1180                                                       &jSource,
   1181                                                       &nPatches[i].sources[j]);
   1182             if (jStatus != AUDIO_JAVA_SUCCESS) {
   1183                 goto exit;
   1184             }
   1185             env->SetObjectArrayElement(jSources, j, jSource);
   1186             env->DeleteLocalRef(jSource);
   1187             jSource = NULL;
   1188             ALOGV("listAudioPatches patch %d source %d is a %s handle %d",
   1189                   i, j,
   1190                   nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
   1191                   nPatches[i].sources[j].id);
   1192         }
   1193         // load sinks
   1194         jSinks = env->NewObjectArray(nPatches[i].num_sinks,
   1195                                      gAudioPortConfigClass, NULL);
   1196         if (jSinks == NULL) {
   1197             jStatus = AUDIO_JAVA_ERROR;
   1198             goto exit;
   1199         }
   1200 
   1201         for (size_t j = 0; j < nPatches[i].num_sinks; j++) {
   1202             jStatus = convertAudioPortConfigFromNative(env,
   1203                                                       NULL,
   1204                                                       &jSink,
   1205                                                       &nPatches[i].sinks[j]);
   1206 
   1207             if (jStatus != AUDIO_JAVA_SUCCESS) {
   1208                 goto exit;
   1209             }
   1210             env->SetObjectArrayElement(jSinks, j, jSink);
   1211             env->DeleteLocalRef(jSink);
   1212             jSink = NULL;
   1213             ALOGV("listAudioPatches patch %d sink %d is a %s handle %d",
   1214                   i, j,
   1215                   nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
   1216                   nPatches[i].sinks[j].id);
   1217         }
   1218 
   1219         jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor,
   1220                                        patchHandle, jSources, jSinks);
   1221         env->DeleteLocalRef(jSources);
   1222         jSources = NULL;
   1223         env->DeleteLocalRef(jSinks);
   1224         jSinks = NULL;
   1225         if (jPatch == NULL) {
   1226             jStatus = AUDIO_JAVA_ERROR;
   1227             goto exit;
   1228         }
   1229         env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch);
   1230         env->DeleteLocalRef(jPatch);
   1231         jPatch = NULL;
   1232     }
   1233 
   1234 exit:
   1235     if (jSources != NULL) {
   1236         env->DeleteLocalRef(jSources);
   1237     }
   1238     if (jSource != NULL) {
   1239         env->DeleteLocalRef(jSource);
   1240     }
   1241     if (jSinks != NULL) {
   1242         env->DeleteLocalRef(jSinks);
   1243     }
   1244     if (jSink != NULL) {
   1245         env->DeleteLocalRef(jSink);
   1246     }
   1247     if (jPatch != NULL) {
   1248         env->DeleteLocalRef(jPatch);
   1249     }
   1250     free(nPatches);
   1251     return jStatus;
   1252 }
   1253 
   1254 static jint
   1255 android_media_AudioSystem_setAudioPortConfig(JNIEnv *env, jobject clazz,
   1256                                  jobject jAudioPortConfig)
   1257 {
   1258     ALOGV("setAudioPortConfig");
   1259     if (jAudioPortConfig == NULL) {
   1260         return AUDIO_JAVA_BAD_VALUE;
   1261     }
   1262     if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
   1263         return AUDIO_JAVA_BAD_VALUE;
   1264     }
   1265     struct audio_port_config nAudioPortConfig;
   1266     jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig);
   1267     if (jStatus != AUDIO_JAVA_SUCCESS) {
   1268         return jStatus;
   1269     }
   1270     status_t status = AudioSystem::setAudioPortConfig(&nAudioPortConfig);
   1271     ALOGV("AudioSystem::setAudioPortConfig() returned %d", status);
   1272     jStatus = nativeToJavaStatus(status);
   1273     return jStatus;
   1274 }
   1275 
   1276 static void
   1277 android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this)
   1278 {
   1279     ALOGV("eventHandlerSetup");
   1280 
   1281     sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
   1282 
   1283     AudioSystem::setAudioPortCallback(callback);
   1284 }
   1285 
   1286 static void
   1287 android_media_AudioSystem_eventHandlerFinalize(JNIEnv *env, jobject thiz)
   1288 {
   1289     ALOGV("eventHandlerFinalize");
   1290 
   1291     sp<JNIAudioPortCallback> callback;
   1292 
   1293     AudioSystem::setAudioPortCallback(callback);
   1294 }
   1295 
   1296 static jint
   1297 android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
   1298 {
   1299     return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId);
   1300 }
   1301 
   1302 // ----------------------------------------------------------------------------
   1303 
   1304 static JNINativeMethod gMethods[] = {
   1305     {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
   1306     {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
   1307     {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
   1308     {"isMicrophoneMuted",   "()Z",      (void *)android_media_AudioSystem_isMicrophoneMuted},
   1309     {"isStreamActive",      "(II)Z",    (void *)android_media_AudioSystem_isStreamActive},
   1310     {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
   1311     {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
   1312     {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
   1313     {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
   1314     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
   1315     {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
   1316     {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
   1317     {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
   1318     {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
   1319     {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
   1320     {"getStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_getStreamVolumeIndex},
   1321     {"setMasterVolume",     "(F)I",     (void *)android_media_AudioSystem_setMasterVolume},
   1322     {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
   1323     {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
   1324     {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
   1325     {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
   1326     {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
   1327     {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
   1328     {"getOutputLatency",    "(I)I",     (void *)android_media_AudioSystem_getOutputLatency},
   1329     {"setLowRamDevice",     "(Z)I",     (void *)android_media_AudioSystem_setLowRamDevice},
   1330     {"checkAudioFlinger",    "()I",     (void *)android_media_AudioSystem_checkAudioFlinger},
   1331     {"listAudioPorts",      "(Ljava/util/ArrayList;[I)I",
   1332                                                 (void *)android_media_AudioSystem_listAudioPorts},
   1333     {"createAudioPatch",    "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
   1334                                             (void *)android_media_AudioSystem_createAudioPatch},
   1335     {"releaseAudioPatch",   "(Landroid/media/AudioPatch;)I",
   1336                                             (void *)android_media_AudioSystem_releaseAudioPatch},
   1337     {"listAudioPatches",    "(Ljava/util/ArrayList;[I)I",
   1338                                                 (void *)android_media_AudioSystem_listAudioPatches},
   1339     {"setAudioPortConfig",   "(Landroid/media/AudioPortConfig;)I",
   1340                                             (void *)android_media_AudioSystem_setAudioPortConfig},
   1341     {"getAudioHwSyncForSession", "(I)I",
   1342                                     (void *)android_media_AudioSystem_getAudioHwSyncForSession},
   1343 };
   1344 
   1345 
   1346 static JNINativeMethod gEventHandlerMethods[] = {
   1347     {"native_setup",
   1348         "(Ljava/lang/Object;)V",
   1349         (void *)android_media_AudioSystem_eventHandlerSetup},
   1350     {"native_finalize",
   1351         "()V",
   1352         (void *)android_media_AudioSystem_eventHandlerFinalize},
   1353 };
   1354 
   1355 int register_android_media_AudioSystem(JNIEnv *env)
   1356 {
   1357 
   1358     jclass arrayListClass = env->FindClass("java/util/ArrayList");
   1359     gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
   1360     gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
   1361 
   1362     jclass audioHandleClass = env->FindClass("android/media/AudioHandle");
   1363     gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass);
   1364     gAudioHandleCstor = env->GetMethodID(audioHandleClass, "<init>", "(I)V");
   1365     gAudioHandleFields.mId = env->GetFieldID(audioHandleClass, "mId", "I");
   1366 
   1367     jclass audioPortClass = env->FindClass("android/media/AudioPort");
   1368     gAudioPortClass = (jclass) env->NewGlobalRef(audioPortClass);
   1369     gAudioPortCstor = env->GetMethodID(audioPortClass, "<init>",
   1370                                "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
   1371     gAudioPortFields.mHandle = env->GetFieldID(audioPortClass, "mHandle",
   1372                                                "Landroid/media/AudioHandle;");
   1373     gAudioPortFields.mRole = env->GetFieldID(audioPortClass, "mRole", "I");
   1374     gAudioPortFields.mGains = env->GetFieldID(audioPortClass, "mGains",
   1375                                               "[Landroid/media/AudioGain;");
   1376     gAudioPortFields.mActiveConfig = env->GetFieldID(audioPortClass, "mActiveConfig",
   1377                                               "Landroid/media/AudioPortConfig;");
   1378 
   1379     jclass audioPortConfigClass = env->FindClass("android/media/AudioPortConfig");
   1380     gAudioPortConfigClass = (jclass) env->NewGlobalRef(audioPortConfigClass);
   1381     gAudioPortConfigCstor = env->GetMethodID(audioPortConfigClass, "<init>",
   1382                                  "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
   1383     gAudioPortConfigFields.mPort = env->GetFieldID(audioPortConfigClass, "mPort",
   1384                                                    "Landroid/media/AudioPort;");
   1385     gAudioPortConfigFields.mSamplingRate = env->GetFieldID(audioPortConfigClass,
   1386                                                            "mSamplingRate", "I");
   1387     gAudioPortConfigFields.mChannelMask = env->GetFieldID(audioPortConfigClass,
   1388                                                           "mChannelMask", "I");
   1389     gAudioPortConfigFields.mFormat = env->GetFieldID(audioPortConfigClass, "mFormat", "I");
   1390     gAudioPortConfigFields.mGain = env->GetFieldID(audioPortConfigClass, "mGain",
   1391                                                    "Landroid/media/AudioGainConfig;");
   1392     gAudioPortConfigFields.mConfigMask = env->GetFieldID(audioPortConfigClass, "mConfigMask", "I");
   1393 
   1394     jclass audioDevicePortConfigClass = env->FindClass("android/media/AudioDevicePortConfig");
   1395     gAudioDevicePortConfigClass = (jclass) env->NewGlobalRef(audioDevicePortConfigClass);
   1396     gAudioDevicePortConfigCstor = env->GetMethodID(audioDevicePortConfigClass, "<init>",
   1397                          "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
   1398 
   1399     jclass audioMixPortConfigClass = env->FindClass("android/media/AudioMixPortConfig");
   1400     gAudioMixPortConfigClass = (jclass) env->NewGlobalRef(audioMixPortConfigClass);
   1401     gAudioMixPortConfigCstor = env->GetMethodID(audioMixPortConfigClass, "<init>",
   1402                          "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
   1403 
   1404     jclass audioDevicePortClass = env->FindClass("android/media/AudioDevicePort");
   1405     gAudioDevicePortClass = (jclass) env->NewGlobalRef(audioDevicePortClass);
   1406     gAudioDevicePortCstor = env->GetMethodID(audioDevicePortClass, "<init>",
   1407              "(Landroid/media/AudioHandle;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
   1408 
   1409     jclass audioMixPortClass = env->FindClass("android/media/AudioMixPort");
   1410     gAudioMixPortClass = (jclass) env->NewGlobalRef(audioMixPortClass);
   1411     gAudioMixPortCstor = env->GetMethodID(audioMixPortClass, "<init>",
   1412                               "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
   1413 
   1414     jclass audioGainClass = env->FindClass("android/media/AudioGain");
   1415     gAudioGainClass = (jclass) env->NewGlobalRef(audioGainClass);
   1416     gAudioGainCstor = env->GetMethodID(audioGainClass, "<init>", "(IIIIIIIII)V");
   1417 
   1418     jclass audioGainConfigClass = env->FindClass("android/media/AudioGainConfig");
   1419     gAudioGainConfigClass = (jclass) env->NewGlobalRef(audioGainConfigClass);
   1420     gAudioGainConfigCstor = env->GetMethodID(audioGainConfigClass, "<init>",
   1421                                              "(ILandroid/media/AudioGain;II[II)V");
   1422     gAudioGainConfigFields.mIndex = env->GetFieldID(gAudioGainConfigClass, "mIndex", "I");
   1423     gAudioGainConfigFields.mMode = env->GetFieldID(audioGainConfigClass, "mMode", "I");
   1424     gAudioGainConfigFields.mChannelMask = env->GetFieldID(audioGainConfigClass, "mChannelMask",
   1425                                                           "I");
   1426     gAudioGainConfigFields.mValues = env->GetFieldID(audioGainConfigClass, "mValues", "[I");
   1427     gAudioGainConfigFields.mRampDurationMs = env->GetFieldID(audioGainConfigClass,
   1428                                                              "mRampDurationMs", "I");
   1429 
   1430     jclass audioPatchClass = env->FindClass("android/media/AudioPatch");
   1431     gAudioPatchClass = (jclass) env->NewGlobalRef(audioPatchClass);
   1432     gAudioPatchCstor = env->GetMethodID(audioPatchClass, "<init>",
   1433 "(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V");
   1434     gAudioPatchFields.mHandle = env->GetFieldID(audioPatchClass, "mHandle",
   1435                                                 "Landroid/media/AudioHandle;");
   1436 
   1437     jclass eventHandlerClass = env->FindClass(kEventHandlerClassPathName);
   1438     gPostEventFromNative = env->GetStaticMethodID(eventHandlerClass, "postEventFromNative",
   1439                                             "(Ljava/lang/Object;IIILjava/lang/Object;)V");
   1440 
   1441 
   1442     AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
   1443 
   1444     int status = AndroidRuntime::registerNativeMethods(env,
   1445                 kClassPathName, gMethods, NELEM(gMethods));
   1446 
   1447     if (status == 0) {
   1448         status = AndroidRuntime::registerNativeMethods(env,
   1449                 kEventHandlerClassPathName, gEventHandlerMethods, NELEM(gEventHandlerMethods));
   1450     }
   1451     return status;
   1452 }
   1453