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