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