android_media_AudioSystem.cpp revision 3a24199a0fe9479802ff6096d82cb3745efa1f1f
1/*
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19
20#define LOG_TAG "AudioSystem-JNI"
21#include <utils/Log.h>
22
23#include <jni.h>
24#include <JNIHelp.h>
25#include <android_runtime/AndroidRuntime.h>
26
27#include <media/AudioSystem.h>
28
29#include <system/audio.h>
30#include <system/audio_policy.h>
31#include "android_media_AudioFormat.h"
32#include "android_media_AudioErrors.h"
33
34// ----------------------------------------------------------------------------
35
36using namespace android;
37
38static const char* const kClassPathName = "android/media/AudioSystem";
39
40static jclass gArrayListClass;
41static struct {
42    jmethodID    add;
43} gArrayListMethods;
44
45static jclass gAudioHandleClass;
46static jmethodID gAudioHandleCstor;
47static struct {
48    jfieldID    mId;
49} gAudioHandleFields;
50
51static jclass gAudioPortClass;
52static jmethodID gAudioPortCstor;
53static struct {
54    jfieldID    mHandle;
55    jfieldID    mRole;
56    jfieldID    mGains;
57    jfieldID    mActiveConfig;
58    // other fields unused by JNI
59} gAudioPortFields;
60
61static jclass gAudioPortConfigClass;
62static jmethodID gAudioPortConfigCstor;
63static struct {
64    jfieldID    mPort;
65    jfieldID    mSamplingRate;
66    jfieldID    mChannelMask;
67    jfieldID    mFormat;
68    jfieldID    mGain;
69    jfieldID    mConfigMask;
70} gAudioPortConfigFields;
71
72static jclass gAudioDevicePortClass;
73static jmethodID gAudioDevicePortCstor;
74
75static jclass gAudioDevicePortConfigClass;
76static jmethodID gAudioDevicePortConfigCstor;
77
78static jclass gAudioMixPortClass;
79static jmethodID gAudioMixPortCstor;
80
81static jclass gAudioMixPortConfigClass;
82static jmethodID gAudioMixPortConfigCstor;
83
84static jclass gAudioGainClass;
85static jmethodID gAudioGainCstor;
86
87static jclass gAudioGainConfigClass;
88static jmethodID gAudioGainConfigCstor;
89static struct {
90    jfieldID mIndex;
91    jfieldID mMode;
92    jfieldID mChannelMask;
93    jfieldID mValues;
94    jfieldID mRampDurationMs;
95    // other fields unused by JNI
96} gAudioGainConfigFields;
97
98static jclass gAudioPatchClass;
99static jmethodID gAudioPatchCstor;
100static struct {
101    jfieldID    mHandle;
102    // other fields unused by JNI
103} gAudioPatchFields;
104
105static const char* const kEventHandlerClassPathName =
106        "android/media/AudioPortEventHandler";
107static jmethodID gPostEventFromNative;
108
109enum AudioError {
110    kAudioStatusOk = 0,
111    kAudioStatusError = 1,
112    kAudioStatusMediaServerDied = 100
113};
114
115enum  {
116    AUDIOPORT_EVENT_PORT_LIST_UPDATED = 1,
117    AUDIOPORT_EVENT_PATCH_LIST_UPDATED = 2,
118    AUDIOPORT_EVENT_SERVICE_DIED = 3,
119};
120
121#define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
122
123// ----------------------------------------------------------------------------
124// ref-counted object for callbacks
125class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
126{
127public:
128    JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
129    ~JNIAudioPortCallback();
130
131    virtual void onAudioPortListUpdate();
132    virtual void onAudioPatchListUpdate();
133    virtual void onServiceDied();
134
135private:
136    void sendEvent(int event);
137
138    jclass      mClass;     // Reference to AudioPortEventHandlerDelegate class
139    jobject     mObject;    // Weak ref to AudioPortEventHandlerDelegate Java object to call on
140};
141
142JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
143{
144
145    // Hold onto the SoundTriggerModule class for use in calling the static method
146    // that posts events to the application thread.
147    jclass clazz = env->GetObjectClass(thiz);
148    if (clazz == NULL) {
149        ALOGE("Can't find class %s", kEventHandlerClassPathName);
150        return;
151    }
152    mClass = (jclass)env->NewGlobalRef(clazz);
153
154    // We use a weak reference so the SoundTriggerModule object can be garbage collected.
155    // The reference is only used as a proxy for callbacks.
156    mObject  = env->NewGlobalRef(weak_thiz);
157}
158
159JNIAudioPortCallback::~JNIAudioPortCallback()
160{
161    // remove global references
162    JNIEnv *env = AndroidRuntime::getJNIEnv();
163    env->DeleteGlobalRef(mObject);
164    env->DeleteGlobalRef(mClass);
165}
166
167void JNIAudioPortCallback::sendEvent(int event)
168{
169    JNIEnv *env = AndroidRuntime::getJNIEnv();
170
171    env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
172                              event, 0, 0, NULL);
173    if (env->ExceptionCheck()) {
174        ALOGW("An exception occurred while notifying an event.");
175        env->ExceptionClear();
176    }
177}
178
179void JNIAudioPortCallback::onAudioPortListUpdate()
180{
181    sendEvent(AUDIOPORT_EVENT_PORT_LIST_UPDATED);
182}
183
184void JNIAudioPortCallback::onAudioPatchListUpdate()
185{
186    sendEvent(AUDIOPORT_EVENT_PATCH_LIST_UPDATED);
187}
188
189void JNIAudioPortCallback::onServiceDied()
190{
191    sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
192}
193
194static int check_AudioSystem_Command(status_t status)
195{
196    switch (status) {
197    case DEAD_OBJECT:
198        return kAudioStatusMediaServerDied;
199    case NO_ERROR:
200        return kAudioStatusOk;
201    default:
202        break;
203    }
204    return kAudioStatusError;
205}
206
207static jint
208android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
209{
210    return (jint) check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
211}
212
213static jboolean
214android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
215{
216    bool state = false;
217    AudioSystem::isMicrophoneMuted(&state);
218    return state;
219}
220
221static jboolean
222android_media_AudioSystem_isStreamActive(JNIEnv *env, jobject thiz, jint stream, jint inPastMs)
223{
224    bool state = false;
225    AudioSystem::isStreamActive((audio_stream_type_t) stream, &state, inPastMs);
226    return state;
227}
228
229static jboolean
230android_media_AudioSystem_isStreamActiveRemotely(JNIEnv *env, jobject thiz, jint stream,
231        jint inPastMs)
232{
233    bool state = false;
234    AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
235    return state;
236}
237
238static jboolean
239android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
240{
241    bool state = false;
242    AudioSystem::isSourceActive((audio_source_t) source, &state);
243    return state;
244}
245
246static jint
247android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
248{
249    const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
250    String8 c_keyValuePairs8;
251    if (keyValuePairs) {
252        c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
253        env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
254    }
255    int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
256    return (jint) status;
257}
258
259static jstring
260android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
261{
262    const jchar* c_keys = env->GetStringCritical(keys, 0);
263    String8 c_keys8;
264    if (keys) {
265        c_keys8 = String8(c_keys, env->GetStringLength(keys));
266        env->ReleaseStringCritical(keys, c_keys);
267    }
268    return env->NewStringUTF(AudioSystem::getParameters(c_keys8).string());
269}
270
271static void
272android_media_AudioSystem_error_callback(status_t err)
273{
274    JNIEnv *env = AndroidRuntime::getJNIEnv();
275    if (env == NULL) {
276        return;
277    }
278
279    jclass clazz = env->FindClass(kClassPathName);
280
281    env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
282                              "errorCallbackFromNative","(I)V"),
283                              check_AudioSystem_Command(err));
284}
285
286static jint
287android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
288{
289    const char *c_address = env->GetStringUTFChars(device_address, NULL);
290    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
291                                          static_cast <audio_policy_dev_state_t>(state),
292                                          c_address));
293    env->ReleaseStringUTFChars(device_address, c_address);
294    return (jint) status;
295}
296
297static jint
298android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
299{
300    const char *c_address = env->GetStringUTFChars(device_address, NULL);
301    int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
302                                          c_address));
303    env->ReleaseStringUTFChars(device_address, c_address);
304    return (jint) state;
305}
306
307static jint
308android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
309{
310    return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
311}
312
313static jint
314android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
315{
316    return (jint) check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
317                                                           static_cast <audio_policy_forced_cfg_t>(config)));
318}
319
320static jint
321android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
322{
323    return static_cast <jint>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
324}
325
326static jint
327android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
328{
329    return (jint) check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
330                                                                   indexMin,
331                                                                   indexMax));
332}
333
334static jint
335android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
336                                               jobject thiz,
337                                               jint stream,
338                                               jint index,
339                                               jint device)
340{
341    return (jint) check_AudioSystem_Command(
342            AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
343                                              index,
344                                              (audio_devices_t)device));
345}
346
347static jint
348android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env,
349                                               jobject thiz,
350                                               jint stream,
351                                               jint device)
352{
353    int index;
354    if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
355                                          &index,
356                                          (audio_devices_t)device)
357            != NO_ERROR) {
358        index = -1;
359    }
360    return (jint) index;
361}
362
363static jint
364android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
365{
366    return (jint) check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
367}
368
369static jfloat
370android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
371{
372    float value;
373    if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
374        value = -1.0;
375    }
376    return value;
377}
378
379static jint
380android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
381{
382    return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
383}
384
385static jfloat
386android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
387{
388    bool mute;
389    if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
390        mute = false;
391    }
392    return mute;
393}
394
395static jint
396android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
397{
398    return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
399}
400
401static jint
402android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
403{
404    return (jint) AudioSystem::getPrimaryOutputSamplingRate();
405}
406
407static jint
408android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
409{
410    return (jint) AudioSystem::getPrimaryOutputFrameCount();
411}
412
413static jint
414android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
415{
416    uint32_t afLatency;
417    if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
418            != NO_ERROR) {
419        afLatency = -1;
420    }
421    return (jint) afLatency;
422}
423
424static jint
425android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
426{
427    return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
428}
429
430static jint
431android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
432{
433    return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
434}
435
436
437static bool useInChannelMask(audio_port_type_t type, audio_port_role_t role)
438{
439    return ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
440                ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
441}
442
443static void convertAudioGainConfigToNative(JNIEnv *env,
444                                               struct audio_gain_config *nAudioGainConfig,
445                                               const jobject jAudioGainConfig,
446                                               bool useInMask)
447{
448    nAudioGainConfig->index = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mIndex);
449    nAudioGainConfig->mode = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
450    ALOGV("convertAudioGainConfigToNative got gain index %d", nAudioGainConfig->index);
451    jint jMask = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mChannelMask);
452    audio_channel_mask_t nMask;
453    if (useInMask) {
454        nMask = inChannelMaskToNative(jMask);
455        ALOGV("convertAudioGainConfigToNative IN mask java %x native %x", jMask, nMask);
456    } else {
457        nMask = outChannelMaskToNative(jMask);
458        ALOGV("convertAudioGainConfigToNative OUT mask java %x native %x", jMask, nMask);
459    }
460    nAudioGainConfig->channel_mask = nMask;
461    nAudioGainConfig->ramp_duration_ms = env->GetIntField(jAudioGainConfig,
462                                                       gAudioGainConfigFields.mRampDurationMs);
463    jintArray jValues = (jintArray)env->GetObjectField(jAudioGainConfig,
464                                                       gAudioGainConfigFields.mValues);
465    int *nValues = env->GetIntArrayElements(jValues, NULL);
466    size_t size = env->GetArrayLength(jValues);
467    memcpy(nAudioGainConfig->values, nValues, size * sizeof(int));
468    env->DeleteLocalRef(jValues);
469}
470
471
472static jint convertAudioPortConfigToNative(JNIEnv *env,
473                                               struct audio_port_config *nAudioPortConfig,
474                                               const jobject jAudioPortConfig)
475{
476    jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
477    jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
478    nAudioPortConfig->id = env->GetIntField(jHandle, gAudioHandleFields.mId);
479    nAudioPortConfig->role = (audio_port_role_t)env->GetIntField(jAudioPort,
480                                                                 gAudioPortFields.mRole);
481    if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
482        nAudioPortConfig->type = AUDIO_PORT_TYPE_DEVICE;
483    } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
484        nAudioPortConfig->type = AUDIO_PORT_TYPE_MIX;
485    } else {
486        env->DeleteLocalRef(jAudioPort);
487        env->DeleteLocalRef(jHandle);
488        return (jint)AUDIO_JAVA_ERROR;
489    }
490    ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
491          nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
492
493    nAudioPortConfig->sample_rate = env->GetIntField(jAudioPortConfig,
494                                                     gAudioPortConfigFields.mSamplingRate);
495
496    bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
497    audio_channel_mask_t nMask;
498    jint jMask = env->GetIntField(jAudioPortConfig,
499                                   gAudioPortConfigFields.mChannelMask);
500    if (useInMask) {
501        nMask = inChannelMaskToNative(jMask);
502        ALOGV("convertAudioPortConfigToNative IN mask java %x native %x", jMask, nMask);
503    } else {
504        nMask = outChannelMaskToNative(jMask);
505        ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
506    }
507    nAudioPortConfig->channel_mask = nMask;
508
509    jint jFormat = env->GetIntField(jAudioPortConfig, gAudioPortConfigFields.mFormat);
510    audio_format_t nFormat = audioFormatToNative(jFormat);
511    ALOGV("convertAudioPortConfigToNative format %d native %d", jFormat, nFormat);
512    nAudioPortConfig->format = nFormat;
513    jobject jGain = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mGain);
514    if (jGain != NULL) {
515        convertAudioGainConfigToNative(env, &nAudioPortConfig->gain, jGain, useInMask);
516        env->DeleteLocalRef(jGain);
517    } else {
518        ALOGV("convertAudioPortConfigToNative no gain");
519        nAudioPortConfig->gain.index = -1;
520    }
521    nAudioPortConfig->config_mask = env->GetIntField(jAudioPortConfig,
522                                                     gAudioPortConfigFields.mConfigMask);
523
524    env->DeleteLocalRef(jAudioPort);
525    env->DeleteLocalRef(jHandle);
526    return (jint)AUDIO_JAVA_SUCCESS;
527}
528
529static jint convertAudioPortConfigFromNative(JNIEnv *env,
530                                                 jobject jAudioPort,
531                                                 jobject *jAudioPortConfig,
532                                                 const struct audio_port_config *nAudioPortConfig)
533{
534    jint jStatus = AUDIO_JAVA_SUCCESS;
535    jobject jAudioGainConfig = NULL;
536    jobject jAudioGain = NULL;
537    jintArray jGainValues;
538    bool audioportCreated = false;
539
540    ALOGV("convertAudioPortConfigFromNative jAudioPort %p", jAudioPort);
541
542    if (jAudioPort == NULL) {
543        jobject jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
544                                                 nAudioPortConfig->id);
545
546        ALOGV("convertAudioPortConfigFromNative handle %d is a %s", nAudioPortConfig->id,
547              nAudioPortConfig->type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix");
548
549        if (jHandle == NULL) {
550            return (jint)AUDIO_JAVA_ERROR;
551        }
552        // create dummy port and port config objects with just the correct handle
553        // and configuration data. The actual AudioPortConfig objects will be
554        // constructed by java code with correct class type (device, mix etc...)
555        // and reference to AudioPort instance in this client
556        jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
557                                           jHandle,
558                                           0,
559                                           NULL,
560                                           NULL,
561                                           NULL,
562                                           NULL);
563        env->DeleteLocalRef(jHandle);
564        if (jAudioPort == NULL) {
565            return (jint)AUDIO_JAVA_ERROR;
566        }
567        ALOGV("convertAudioPortConfigFromNative jAudioPort created for handle %d",
568              nAudioPortConfig->id);
569
570        audioportCreated = true;
571    }
572
573    bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
574
575    audio_channel_mask_t nMask;
576    jint jMask;
577
578    int gainIndex = nAudioPortConfig->gain.index;
579    if (gainIndex >= 0) {
580        ALOGV("convertAudioPortConfigFromNative gain found with index %d mode %x",
581              gainIndex, nAudioPortConfig->gain.mode);
582        if (audioportCreated) {
583            ALOGV("convertAudioPortConfigFromNative creating gain");
584            jAudioGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
585                                               gainIndex,
586                                               0,
587                                               0,
588                                               0,
589                                               0,
590                                               0,
591                                               0,
592                                               0,
593                                               0);
594            if (jAudioGain == NULL) {
595                ALOGV("convertAudioPortConfigFromNative creating gain FAILED");
596                jStatus = (jint)AUDIO_JAVA_ERROR;
597                goto exit;
598            }
599        } else {
600            ALOGV("convertAudioPortConfigFromNative reading gain from port");
601            jobjectArray jGains = (jobjectArray)env->GetObjectField(jAudioPort,
602                                                                      gAudioPortFields.mGains);
603            if (jGains == NULL) {
604                ALOGV("convertAudioPortConfigFromNative could not get gains from port");
605                jStatus = (jint)AUDIO_JAVA_ERROR;
606                goto exit;
607            }
608            jAudioGain = env->GetObjectArrayElement(jGains, gainIndex);
609            env->DeleteLocalRef(jGains);
610            if (jAudioGain == NULL) {
611                ALOGV("convertAudioPortConfigFromNative could not get gain at index %d", gainIndex);
612                jStatus = (jint)AUDIO_JAVA_ERROR;
613                goto exit;
614            }
615        }
616        //TODO: replace popcount by audio utils function mask to count
617        int numValues = popcount(nAudioPortConfig->gain.channel_mask);
618        jGainValues = env->NewIntArray(numValues);
619        if (jGainValues == NULL) {
620            ALOGV("convertAudioPortConfigFromNative could not create gain values %d", numValues);
621            jStatus = (jint)AUDIO_JAVA_ERROR;
622            goto exit;
623        }
624        env->SetIntArrayRegion(jGainValues, 0, numValues,
625                               nAudioPortConfig->gain.values);
626
627        nMask = nAudioPortConfig->gain.channel_mask;
628        if (useInMask) {
629            jMask = inChannelMaskFromNative(nMask);
630            ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
631        } else {
632            jMask = outChannelMaskFromNative(nMask);
633            ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
634        }
635
636        jAudioGainConfig = env->NewObject(gAudioGainConfigClass,
637                                        gAudioGainConfigCstor,
638                                        gainIndex,
639                                        jAudioGain,
640                                        nAudioPortConfig->gain.mode,
641                                        jMask,
642                                        jGainValues,
643                                        nAudioPortConfig->gain.ramp_duration_ms);
644        env->DeleteLocalRef(jGainValues);
645        if (jAudioGainConfig == NULL) {
646            ALOGV("convertAudioPortConfigFromNative could not create gain config");
647            jStatus = (jint)AUDIO_JAVA_ERROR;
648            goto exit;
649        }
650    }
651    jclass clazz;
652    jmethodID methodID;
653    if (audioportCreated) {
654        clazz = gAudioPortConfigClass;
655        methodID = gAudioPortConfigCstor;
656        ALOGV("convertAudioPortConfigFromNative building a generic port config");
657    } else {
658        if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
659            clazz = gAudioDevicePortConfigClass;
660            methodID = gAudioDevicePortConfigCstor;
661            ALOGV("convertAudioPortConfigFromNative building a device config");
662        } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
663            clazz = gAudioMixPortConfigClass;
664            methodID = gAudioMixPortConfigCstor;
665            ALOGV("convertAudioPortConfigFromNative building a mix config");
666        } else {
667            jStatus = (jint)AUDIO_JAVA_ERROR;
668            goto exit;
669        }
670    }
671    nMask = nAudioPortConfig->channel_mask;
672    if (useInMask) {
673        jMask = inChannelMaskFromNative(nMask);
674        ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
675    } else {
676        jMask = outChannelMaskFromNative(nMask);
677        ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
678    }
679
680    *jAudioPortConfig = env->NewObject(clazz, methodID,
681                                       jAudioPort,
682                                       nAudioPortConfig->sample_rate,
683                                       jMask,
684                                       audioFormatFromNative(nAudioPortConfig->format),
685                                       jAudioGainConfig);
686    if (*jAudioPortConfig == NULL) {
687        ALOGV("convertAudioPortConfigFromNative could not create new port config");
688        jStatus = (jint)AUDIO_JAVA_ERROR;
689    } else {
690        ALOGV("convertAudioPortConfigFromNative OK");
691    }
692
693exit:
694    if (audioportCreated) {
695        env->DeleteLocalRef(jAudioPort);
696        if (jAudioGain != NULL) {
697            env->DeleteLocalRef(jAudioGain);
698        }
699    }
700    if (jAudioGainConfig != NULL) {
701        env->DeleteLocalRef(jAudioGainConfig);
702    }
703    return jStatus;
704}
705
706static jint convertAudioPortFromNative(JNIEnv *env,
707                                           jobject *jAudioPort, const struct audio_port *nAudioPort)
708{
709    jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
710    jintArray jSamplingRates = NULL;
711    jintArray jChannelMasks = NULL;
712    jintArray jFormats = NULL;
713    jobjectArray jGains = NULL;
714    jobject jHandle = NULL;
715    bool useInMask;
716
717    ALOGV("convertAudioPortFromNative id %d role %d type %d",
718                                  nAudioPort->id, nAudioPort->role, nAudioPort->type);
719
720    jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
721    if (jSamplingRates == NULL) {
722        jStatus = (jint)AUDIO_JAVA_ERROR;
723        goto exit;
724    }
725    if (nAudioPort->num_sample_rates) {
726        env->SetIntArrayRegion(jSamplingRates, 0, nAudioPort->num_sample_rates,
727                               (jint *)nAudioPort->sample_rates);
728    }
729
730    jChannelMasks = env->NewIntArray(nAudioPort->num_channel_masks);
731    if (jChannelMasks == NULL) {
732        jStatus = (jint)AUDIO_JAVA_ERROR;
733        goto exit;
734    }
735    useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
736
737    jint jMask;
738    for (size_t j = 0; j < nAudioPort->num_channel_masks; j++) {
739        if (useInMask) {
740            jMask = inChannelMaskFromNative(nAudioPort->channel_masks[j]);
741        } else {
742            jMask = outChannelMaskFromNative(nAudioPort->channel_masks[j]);
743        }
744        env->SetIntArrayRegion(jChannelMasks, j, 1, &jMask);
745    }
746
747    jFormats = env->NewIntArray(nAudioPort->num_formats);
748    if (jFormats == NULL) {
749        jStatus = (jint)AUDIO_JAVA_ERROR;
750        goto exit;
751    }
752    for (size_t j = 0; j < nAudioPort->num_formats; j++) {
753        jint jFormat = audioFormatFromNative(nAudioPort->formats[j]);
754        env->SetIntArrayRegion(jFormats, j, 1, &jFormat);
755    }
756
757    jGains = env->NewObjectArray(nAudioPort->num_gains,
758                                          gAudioGainClass, NULL);
759    if (jGains == NULL) {
760        jStatus = (jint)AUDIO_JAVA_ERROR;
761        goto exit;
762    }
763    for (size_t j = 0; j < nAudioPort->num_gains; j++) {
764        audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
765        if (useInMask) {
766            jMask = inChannelMaskFromNative(nMask);
767            ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
768        } else {
769            jMask = outChannelMaskFromNative(nMask);
770            ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
771        }
772
773        jobject jGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
774                                                 j,
775                                                 nAudioPort->gains[j].mode,
776                                                 jMask,
777                                                 nAudioPort->gains[j].min_value,
778                                                 nAudioPort->gains[j].max_value,
779                                                 nAudioPort->gains[j].default_value,
780                                                 nAudioPort->gains[j].step_value,
781                                                 nAudioPort->gains[j].min_ramp_ms,
782                                                 nAudioPort->gains[j].max_ramp_ms);
783        if (jGain == NULL) {
784            jStatus = (jint)AUDIO_JAVA_ERROR;
785            goto exit;
786        }
787        env->SetObjectArrayElement(jGains, j, jGain);
788        env->DeleteLocalRef(jGain);
789    }
790
791    jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
792                                             nAudioPort->id);
793    if (jHandle == NULL) {
794        jStatus = (jint)AUDIO_JAVA_ERROR;
795        goto exit;
796    }
797
798    if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
799        ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
800        jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
801        *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
802                                     jHandle, jSamplingRates, jChannelMasks, jFormats, jGains,
803                                     nAudioPort->ext.device.type, jAddress);
804        env->DeleteLocalRef(jAddress);
805    } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
806        ALOGV("convertAudioPortFromNative is a mix");
807        *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
808                                     jHandle, nAudioPort->role, jSamplingRates, jChannelMasks,
809                                     jFormats, jGains);
810    } else {
811        ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
812        jStatus = (jint)AUDIO_JAVA_ERROR;
813        goto exit;
814    }
815    if (*jAudioPort == NULL) {
816        jStatus = (jint)AUDIO_JAVA_ERROR;
817        goto exit;
818    }
819
820    jobject jAudioPortConfig;
821    jStatus = convertAudioPortConfigFromNative(env,
822                                                       *jAudioPort,
823                                                       &jAudioPortConfig,
824                                                       &nAudioPort->active_config);
825    if (jStatus != AUDIO_JAVA_SUCCESS) {
826        return jStatus;
827    }
828
829    env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
830
831exit:
832    if (jSamplingRates != NULL) {
833        env->DeleteLocalRef(jSamplingRates);
834    }
835    if (jChannelMasks != NULL) {
836        env->DeleteLocalRef(jChannelMasks);
837    }
838    if (jFormats != NULL) {
839        env->DeleteLocalRef(jFormats);
840    }
841    if (jGains != NULL) {
842        env->DeleteLocalRef(jGains);
843    }
844    if (jHandle != NULL) {
845        env->DeleteLocalRef(jHandle);
846    }
847
848    return jStatus;
849}
850
851
852static jint
853android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
854                                         jobject jPorts, jintArray jGeneration)
855{
856    ALOGV("listAudioPorts");
857
858    if (jPorts == NULL) {
859        ALOGE("listAudioPorts NULL AudioPort ArrayList");
860        return (jint)AUDIO_JAVA_BAD_VALUE;
861    }
862    if (!env->IsInstanceOf(jPorts, gArrayListClass)) {
863        ALOGE("listAudioPorts not an arraylist");
864        return (jint)AUDIO_JAVA_BAD_VALUE;
865    }
866
867    if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
868        return (jint)AUDIO_JAVA_BAD_VALUE;
869    }
870
871    status_t status;
872    unsigned int generation1;
873    unsigned int generation;
874    unsigned int numPorts;
875    jint *nGeneration;
876    struct audio_port *nPorts = NULL;
877    int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
878
879    // get the port count and all the ports until they both return the same generation
880    do {
881        if (attempts-- < 0) {
882            status = TIMED_OUT;
883            break;
884        }
885
886        numPorts = 0;
887        status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
888                                             AUDIO_PORT_TYPE_NONE,
889                                                      &numPorts,
890                                                      NULL,
891                                                      &generation1);
892        if (status != NO_ERROR || numPorts == 0) {
893            ALOGE_IF(status != NO_ERROR, "AudioSystem::listAudioPorts error %d", status);
894            break;
895        }
896        nPorts = (struct audio_port *)realloc(nPorts, numPorts * sizeof(struct audio_port));
897
898        status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
899                                             AUDIO_PORT_TYPE_NONE,
900                                                      &numPorts,
901                                                      nPorts,
902                                                      &generation);
903        ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
904              numPorts, generation, generation1);
905    } while (generation1 != generation && status == NO_ERROR);
906
907    jint jStatus = nativeToJavaStatus(status);
908    if (jStatus != AUDIO_JAVA_SUCCESS) {
909        goto exit;
910    }
911
912    nGeneration = env->GetIntArrayElements(jGeneration, NULL);
913    if (nGeneration == NULL) {
914        jStatus = (jint)AUDIO_JAVA_ERROR;
915        goto exit;
916    }
917    nGeneration[0] = generation1;
918    env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
919
920    for (size_t i = 0; i < numPorts; i++) {
921        jobject jAudioPort;
922        jStatus = convertAudioPortFromNative(env, &jAudioPort, &nPorts[i]);
923        if (jStatus != AUDIO_JAVA_SUCCESS) {
924            goto exit;
925        }
926        env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort);
927    }
928
929exit:
930    free(nPorts);
931    return jStatus;
932}
933
934static int
935android_media_AudioSystem_createAudioPatch(JNIEnv *env, jobject clazz,
936                                 jobjectArray jPatches, jobjectArray jSources, jobjectArray jSinks)
937{
938    status_t status;
939    jint jStatus;
940
941    ALOGV("createAudioPatch");
942    if (jPatches == NULL || jSources == NULL || jSinks == NULL) {
943        return (jint)AUDIO_JAVA_BAD_VALUE;
944    }
945
946    if (env->GetArrayLength(jPatches) != 1) {
947        return (jint)AUDIO_JAVA_BAD_VALUE;
948    }
949    jint numSources = env->GetArrayLength(jSources);
950    if (numSources == 0 || numSources > AUDIO_PATCH_PORTS_MAX) {
951        return (jint)AUDIO_JAVA_BAD_VALUE;
952    }
953
954    jint numSinks = env->GetArrayLength(jSinks);
955    if (numSinks == 0 || numSinks > AUDIO_PATCH_PORTS_MAX) {
956        return (jint)AUDIO_JAVA_BAD_VALUE;
957    }
958
959    audio_patch_handle_t handle = (audio_patch_handle_t)0;
960    jobject jPatch = env->GetObjectArrayElement(jPatches, 0);
961    jobject jPatchHandle = NULL;
962    if (jPatch != NULL) {
963        if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
964            return (jint)AUDIO_JAVA_BAD_VALUE;
965        }
966        jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
967        handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
968    }
969
970    struct audio_patch nPatch;
971
972    nPatch.id = handle;
973    nPatch.num_sources = 0;
974    nPatch.num_sinks = 0;
975    jobject jSource = NULL;
976    jobject jSink = NULL;
977
978    for (jint i = 0; i < numSources; i++) {
979        jSource = env->GetObjectArrayElement(jSources, i);
980        if (!env->IsInstanceOf(jSource, gAudioPortConfigClass)) {
981            jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
982            goto exit;
983        }
984        jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource);
985        env->DeleteLocalRef(jSource);
986        jSource = NULL;
987        if (jStatus != AUDIO_JAVA_SUCCESS) {
988            goto exit;
989        }
990        nPatch.num_sources++;
991    }
992
993    for (jint i = 0; i < numSinks; i++) {
994        jSink = env->GetObjectArrayElement(jSinks, i);
995        if (!env->IsInstanceOf(jSink, gAudioPortConfigClass)) {
996            jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
997            goto exit;
998        }
999        jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink);
1000        env->DeleteLocalRef(jSink);
1001        jSink = NULL;
1002        if (jStatus != AUDIO_JAVA_SUCCESS) {
1003            goto exit;
1004        }
1005        nPatch.num_sinks++;
1006    }
1007
1008    ALOGV("AudioSystem::createAudioPatch");
1009    status = AudioSystem::createAudioPatch(&nPatch, &handle);
1010    ALOGV("AudioSystem::createAudioPatch() returned %d hande %d", status, handle);
1011
1012    jStatus = nativeToJavaStatus(status);
1013    if (jStatus != AUDIO_JAVA_SUCCESS) {
1014        goto exit;
1015    }
1016
1017    if (jPatchHandle == NULL) {
1018        jPatchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1019                                           handle);
1020        if (jPatchHandle == NULL) {
1021            jStatus = (jint)AUDIO_JAVA_ERROR;
1022            goto exit;
1023        }
1024        jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle, jSources, jSinks);
1025        if (jPatch == NULL) {
1026            jStatus = (jint)AUDIO_JAVA_ERROR;
1027            goto exit;
1028        }
1029        env->SetObjectArrayElement(jPatches, 0, jPatch);
1030    } else {
1031        env->SetIntField(jPatchHandle, gAudioHandleFields.mId, handle);
1032    }
1033
1034exit:
1035    if (jPatchHandle != NULL) {
1036        env->DeleteLocalRef(jPatchHandle);
1037    }
1038    if (jPatch != NULL) {
1039        env->DeleteLocalRef(jPatch);
1040    }
1041    if (jSource != NULL) {
1042        env->DeleteLocalRef(jSource);
1043    }
1044    if (jSink != NULL) {
1045        env->DeleteLocalRef(jSink);
1046    }
1047    return jStatus;
1048}
1049
1050static int
1051android_media_AudioSystem_releaseAudioPatch(JNIEnv *env, jobject clazz,
1052                                               jobject jPatch)
1053{
1054    ALOGV("releaseAudioPatch");
1055    if (jPatch == NULL) {
1056        return (jint)AUDIO_JAVA_BAD_VALUE;
1057    }
1058
1059    audio_patch_handle_t handle = (audio_patch_handle_t)0;
1060    jobject jPatchHandle = NULL;
1061    if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
1062        return (jint)AUDIO_JAVA_BAD_VALUE;
1063    }
1064    jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
1065    handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
1066    env->DeleteLocalRef(jPatchHandle);
1067
1068    ALOGV("AudioSystem::releaseAudioPatch");
1069    status_t status = AudioSystem::releaseAudioPatch(handle);
1070    ALOGV("AudioSystem::releaseAudioPatch() returned %d", status);
1071    jint jStatus = nativeToJavaStatus(status);
1072    return status;
1073}
1074
1075static jint
1076android_media_AudioSystem_listAudioPatches(JNIEnv *env, jobject clazz,
1077                                           jobject jPatches, jintArray jGeneration)
1078{
1079    ALOGV("listAudioPatches");
1080    if (jPatches == NULL) {
1081        ALOGE("listAudioPatches NULL AudioPatch ArrayList");
1082        return (jint)AUDIO_JAVA_BAD_VALUE;
1083    }
1084    if (!env->IsInstanceOf(jPatches, gArrayListClass)) {
1085        ALOGE("listAudioPatches not an arraylist");
1086        return (jint)AUDIO_JAVA_BAD_VALUE;
1087    }
1088
1089    if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
1090        return (jint)AUDIO_JAVA_BAD_VALUE;
1091    }
1092
1093    status_t status;
1094    unsigned int generation1;
1095    unsigned int generation;
1096    unsigned int numPatches;
1097    jint *nGeneration;
1098    struct audio_patch *nPatches = NULL;
1099    jobjectArray jSources = NULL;
1100    jobject jSource = NULL;
1101    jobjectArray jSinks = NULL;
1102    jobject jSink = NULL;
1103    jobject jPatch = NULL;
1104    int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
1105
1106    // get the patch count and all the patches until they both return the same generation
1107    do {
1108        if (attempts-- < 0) {
1109            status = TIMED_OUT;
1110            break;
1111        }
1112
1113        numPatches = 0;
1114        status = AudioSystem::listAudioPatches(&numPatches,
1115                                               NULL,
1116                                               &generation1);
1117        if (status != NO_ERROR || numPatches == 0) {
1118            ALOGE_IF(status != NO_ERROR, "listAudioPatches AudioSystem::listAudioPatches error %d",
1119                                      status);
1120            break;
1121        }
1122        nPatches = (struct audio_patch *)realloc(nPatches, numPatches * sizeof(struct audio_patch));
1123
1124        status = AudioSystem::listAudioPatches(&numPatches,
1125                                               nPatches,
1126                                               &generation);
1127        ALOGV("listAudioPatches AudioSystem::listAudioPatches numPatches %d generation %d generation1 %d",
1128              numPatches, generation, generation1);
1129
1130    } while (generation1 != generation && status == NO_ERROR);
1131
1132    jint jStatus = nativeToJavaStatus(status);
1133    if (jStatus != AUDIO_JAVA_SUCCESS) {
1134        goto exit;
1135    }
1136
1137    nGeneration = env->GetIntArrayElements(jGeneration, NULL);
1138    if (nGeneration == NULL) {
1139        jStatus = AUDIO_JAVA_ERROR;
1140        goto exit;
1141    }
1142    nGeneration[0] = generation1;
1143    env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
1144
1145    for (size_t i = 0; i < numPatches; i++) {
1146        jobject patchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1147                                                 nPatches[i].id);
1148        if (patchHandle == NULL) {
1149            jStatus = AUDIO_JAVA_ERROR;
1150            goto exit;
1151        }
1152        ALOGV("listAudioPatches patch %d num_sources %d num_sinks %d",
1153              i, nPatches[i].num_sources, nPatches[i].num_sinks);
1154
1155        env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
1156
1157        // load sources
1158        jSources = env->NewObjectArray(nPatches[i].num_sources,
1159                                       gAudioPortConfigClass, NULL);
1160        if (jSources == NULL) {
1161            jStatus = AUDIO_JAVA_ERROR;
1162            goto exit;
1163        }
1164
1165        for (size_t j = 0; j < nPatches[i].num_sources; j++) {
1166            jStatus = convertAudioPortConfigFromNative(env,
1167                                                      NULL,
1168                                                      &jSource,
1169                                                      &nPatches[i].sources[j]);
1170            if (jStatus != AUDIO_JAVA_SUCCESS) {
1171                goto exit;
1172            }
1173            env->SetObjectArrayElement(jSources, j, jSource);
1174            env->DeleteLocalRef(jSource);
1175            jSource = NULL;
1176            ALOGV("listAudioPatches patch %d source %d is a %s handle %d",
1177                  i, j,
1178                  nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
1179                  nPatches[i].sources[j].id);
1180        }
1181        // load sinks
1182        jSinks = env->NewObjectArray(nPatches[i].num_sinks,
1183                                     gAudioPortConfigClass, NULL);
1184        if (jSinks == NULL) {
1185            jStatus = AUDIO_JAVA_ERROR;
1186            goto exit;
1187        }
1188
1189        for (size_t j = 0; j < nPatches[i].num_sinks; j++) {
1190            jStatus = convertAudioPortConfigFromNative(env,
1191                                                      NULL,
1192                                                      &jSink,
1193                                                      &nPatches[i].sinks[j]);
1194
1195            if (jStatus != AUDIO_JAVA_SUCCESS) {
1196                goto exit;
1197            }
1198            env->SetObjectArrayElement(jSinks, j, jSink);
1199            env->DeleteLocalRef(jSink);
1200            jSink = NULL;
1201            ALOGV("listAudioPatches patch %d sink %d is a %s handle %d",
1202                  i, j,
1203                  nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
1204                  nPatches[i].sinks[j].id);
1205        }
1206
1207        jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor,
1208                                       patchHandle, jSources, jSinks);
1209        env->DeleteLocalRef(jSources);
1210        jSources = NULL;
1211        env->DeleteLocalRef(jSinks);
1212        jSinks = NULL;
1213        if (jPatch == NULL) {
1214            jStatus = AUDIO_JAVA_ERROR;
1215            goto exit;
1216        }
1217        env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch);
1218        env->DeleteLocalRef(jPatch);
1219        jPatch = NULL;
1220    }
1221
1222exit:
1223    if (jSources != NULL) {
1224        env->DeleteLocalRef(jSources);
1225    }
1226    if (jSource != NULL) {
1227        env->DeleteLocalRef(jSource);
1228    }
1229    if (jSinks != NULL) {
1230        env->DeleteLocalRef(jSinks);
1231    }
1232    if (jSink != NULL) {
1233        env->DeleteLocalRef(jSink);
1234    }
1235    if (jPatch != NULL) {
1236        env->DeleteLocalRef(jPatch);
1237    }
1238    free(nPatches);
1239    return jStatus;
1240}
1241
1242static jint
1243android_media_AudioSystem_setAudioPortConfig(JNIEnv *env, jobject clazz,
1244                                 jobject jAudioPortConfig)
1245{
1246    ALOGV("setAudioPortConfig");
1247    if (jAudioPortConfig == NULL) {
1248        return AUDIO_JAVA_BAD_VALUE;
1249    }
1250    if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
1251        return AUDIO_JAVA_BAD_VALUE;
1252    }
1253    struct audio_port_config nAudioPortConfig;
1254    jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig);
1255    if (jStatus != AUDIO_JAVA_SUCCESS) {
1256        return jStatus;
1257    }
1258    status_t status = AudioSystem::setAudioPortConfig(&nAudioPortConfig);
1259    ALOGV("AudioSystem::setAudioPortConfig() returned %d", status);
1260    jStatus = nativeToJavaStatus(status);
1261    return jStatus;
1262}
1263
1264static void
1265android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this)
1266{
1267    ALOGV("eventHandlerSetup");
1268
1269    sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
1270
1271    AudioSystem::setAudioPortCallback(callback);
1272}
1273
1274static void
1275android_media_AudioSystem_eventHandlerFinalize(JNIEnv *env, jobject thiz)
1276{
1277    ALOGV("eventHandlerFinalize");
1278
1279    sp<JNIAudioPortCallback> callback;
1280
1281    AudioSystem::setAudioPortCallback(callback);
1282}
1283
1284// ----------------------------------------------------------------------------
1285
1286static JNINativeMethod gMethods[] = {
1287    {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
1288    {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
1289    {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
1290    {"isMicrophoneMuted",   "()Z",      (void *)android_media_AudioSystem_isMicrophoneMuted},
1291    {"isStreamActive",      "(II)Z",    (void *)android_media_AudioSystem_isStreamActive},
1292    {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
1293    {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
1294    {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
1295    {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
1296    {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
1297    {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
1298    {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
1299    {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
1300    {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
1301    {"getStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_getStreamVolumeIndex},
1302    {"setMasterVolume",     "(F)I",     (void *)android_media_AudioSystem_setMasterVolume},
1303    {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
1304    {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
1305    {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
1306    {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
1307    {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
1308    {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
1309    {"getOutputLatency",    "(I)I",     (void *)android_media_AudioSystem_getOutputLatency},
1310    {"setLowRamDevice",     "(Z)I",     (void *)android_media_AudioSystem_setLowRamDevice},
1311    {"checkAudioFlinger",    "()I",     (void *)android_media_AudioSystem_checkAudioFlinger},
1312    {"listAudioPorts",      "(Ljava/util/ArrayList;[I)I",
1313                                                (void *)android_media_AudioSystem_listAudioPorts},
1314    {"createAudioPatch",    "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
1315                                            (void *)android_media_AudioSystem_createAudioPatch},
1316    {"releaseAudioPatch",   "(Landroid/media/AudioPatch;)I",
1317                                            (void *)android_media_AudioSystem_releaseAudioPatch},
1318    {"listAudioPatches",    "(Ljava/util/ArrayList;[I)I",
1319                                                (void *)android_media_AudioSystem_listAudioPatches},
1320    {"setAudioPortConfig",   "(Landroid/media/AudioPortConfig;)I",
1321                                            (void *)android_media_AudioSystem_setAudioPortConfig},
1322};
1323
1324
1325static JNINativeMethod gEventHandlerMethods[] = {
1326    {"native_setup",
1327        "(Ljava/lang/Object;)V",
1328        (void *)android_media_AudioSystem_eventHandlerSetup},
1329    {"native_finalize",
1330        "()V",
1331        (void *)android_media_AudioSystem_eventHandlerFinalize},
1332};
1333
1334int register_android_media_AudioSystem(JNIEnv *env)
1335{
1336
1337    jclass arrayListClass = env->FindClass("java/util/ArrayList");
1338    gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
1339    gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
1340
1341    jclass audioHandleClass = env->FindClass("android/media/AudioHandle");
1342    gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass);
1343    gAudioHandleCstor = env->GetMethodID(audioHandleClass, "<init>", "(I)V");
1344    gAudioHandleFields.mId = env->GetFieldID(audioHandleClass, "mId", "I");
1345
1346    jclass audioPortClass = env->FindClass("android/media/AudioPort");
1347    gAudioPortClass = (jclass) env->NewGlobalRef(audioPortClass);
1348    gAudioPortCstor = env->GetMethodID(audioPortClass, "<init>",
1349                               "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
1350    gAudioPortFields.mHandle = env->GetFieldID(audioPortClass, "mHandle",
1351                                               "Landroid/media/AudioHandle;");
1352    gAudioPortFields.mRole = env->GetFieldID(audioPortClass, "mRole", "I");
1353    gAudioPortFields.mGains = env->GetFieldID(audioPortClass, "mGains",
1354                                              "[Landroid/media/AudioGain;");
1355    gAudioPortFields.mActiveConfig = env->GetFieldID(audioPortClass, "mActiveConfig",
1356                                              "Landroid/media/AudioPortConfig;");
1357
1358    jclass audioPortConfigClass = env->FindClass("android/media/AudioPortConfig");
1359    gAudioPortConfigClass = (jclass) env->NewGlobalRef(audioPortConfigClass);
1360    gAudioPortConfigCstor = env->GetMethodID(audioPortConfigClass, "<init>",
1361                                 "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
1362    gAudioPortConfigFields.mPort = env->GetFieldID(audioPortConfigClass, "mPort",
1363                                                   "Landroid/media/AudioPort;");
1364    gAudioPortConfigFields.mSamplingRate = env->GetFieldID(audioPortConfigClass,
1365                                                           "mSamplingRate", "I");
1366    gAudioPortConfigFields.mChannelMask = env->GetFieldID(audioPortConfigClass,
1367                                                          "mChannelMask", "I");
1368    gAudioPortConfigFields.mFormat = env->GetFieldID(audioPortConfigClass, "mFormat", "I");
1369    gAudioPortConfigFields.mGain = env->GetFieldID(audioPortConfigClass, "mGain",
1370                                                   "Landroid/media/AudioGainConfig;");
1371    gAudioPortConfigFields.mConfigMask = env->GetFieldID(audioPortConfigClass, "mConfigMask", "I");
1372
1373    jclass audioDevicePortConfigClass = env->FindClass("android/media/AudioDevicePortConfig");
1374    gAudioDevicePortConfigClass = (jclass) env->NewGlobalRef(audioDevicePortConfigClass);
1375    gAudioDevicePortConfigCstor = env->GetMethodID(audioDevicePortConfigClass, "<init>",
1376                         "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
1377
1378    jclass audioMixPortConfigClass = env->FindClass("android/media/AudioMixPortConfig");
1379    gAudioMixPortConfigClass = (jclass) env->NewGlobalRef(audioMixPortConfigClass);
1380    gAudioMixPortConfigCstor = env->GetMethodID(audioMixPortConfigClass, "<init>",
1381                         "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
1382
1383    jclass audioDevicePortClass = env->FindClass("android/media/AudioDevicePort");
1384    gAudioDevicePortClass = (jclass) env->NewGlobalRef(audioDevicePortClass);
1385    gAudioDevicePortCstor = env->GetMethodID(audioDevicePortClass, "<init>",
1386             "(Landroid/media/AudioHandle;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
1387
1388    jclass audioMixPortClass = env->FindClass("android/media/AudioMixPort");
1389    gAudioMixPortClass = (jclass) env->NewGlobalRef(audioMixPortClass);
1390    gAudioMixPortCstor = env->GetMethodID(audioMixPortClass, "<init>",
1391                              "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
1392
1393    jclass audioGainClass = env->FindClass("android/media/AudioGain");
1394    gAudioGainClass = (jclass) env->NewGlobalRef(audioGainClass);
1395    gAudioGainCstor = env->GetMethodID(audioGainClass, "<init>", "(IIIIIIIII)V");
1396
1397    jclass audioGainConfigClass = env->FindClass("android/media/AudioGainConfig");
1398    gAudioGainConfigClass = (jclass) env->NewGlobalRef(audioGainConfigClass);
1399    gAudioGainConfigCstor = env->GetMethodID(audioGainConfigClass, "<init>",
1400                                             "(ILandroid/media/AudioGain;II[II)V");
1401    gAudioGainConfigFields.mIndex = env->GetFieldID(gAudioGainConfigClass, "mIndex", "I");
1402    gAudioGainConfigFields.mMode = env->GetFieldID(audioGainConfigClass, "mMode", "I");
1403    gAudioGainConfigFields.mChannelMask = env->GetFieldID(audioGainConfigClass, "mChannelMask",
1404                                                          "I");
1405    gAudioGainConfigFields.mValues = env->GetFieldID(audioGainConfigClass, "mValues", "[I");
1406    gAudioGainConfigFields.mRampDurationMs = env->GetFieldID(audioGainConfigClass,
1407                                                             "mRampDurationMs", "I");
1408
1409    jclass audioPatchClass = env->FindClass("android/media/AudioPatch");
1410    gAudioPatchClass = (jclass) env->NewGlobalRef(audioPatchClass);
1411    gAudioPatchCstor = env->GetMethodID(audioPatchClass, "<init>",
1412"(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V");
1413    gAudioPatchFields.mHandle = env->GetFieldID(audioPatchClass, "mHandle",
1414                                                "Landroid/media/AudioHandle;");
1415
1416    jclass eventHandlerClass = env->FindClass(kEventHandlerClassPathName);
1417    gPostEventFromNative = env->GetStaticMethodID(eventHandlerClass, "postEventFromNative",
1418                                            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1419
1420
1421    AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
1422
1423    int status = AndroidRuntime::registerNativeMethods(env,
1424                kClassPathName, gMethods, NELEM(gMethods));
1425
1426    if (status == 0) {
1427        status = AndroidRuntime::registerNativeMethods(env,
1428                kEventHandlerClassPathName, gEventHandlerMethods, NELEM(gEventHandlerMethods));
1429    }
1430    return status;
1431}
1432