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