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