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