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