android_media_AudioSystem.cpp revision 8a21f5dd79e93aa4e4b08ab4f33b9255d7c06961
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_newAudioSessionId(JNIEnv *env, jobject thiz)
248{
249    return AudioSystem::newAudioSessionId();
250}
251
252static jint
253android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
254{
255    const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
256    String8 c_keyValuePairs8;
257    if (keyValuePairs) {
258        c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
259        env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
260    }
261    int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
262    return (jint) status;
263}
264
265static jstring
266android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
267{
268    const jchar* c_keys = env->GetStringCritical(keys, 0);
269    String8 c_keys8;
270    if (keys) {
271        c_keys8 = String8(c_keys, env->GetStringLength(keys));
272        env->ReleaseStringCritical(keys, c_keys);
273    }
274    return env->NewStringUTF(AudioSystem::getParameters(c_keys8).string());
275}
276
277static void
278android_media_AudioSystem_error_callback(status_t err)
279{
280    JNIEnv *env = AndroidRuntime::getJNIEnv();
281    if (env == NULL) {
282        return;
283    }
284
285    jclass clazz = env->FindClass(kClassPathName);
286
287    env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
288                              "errorCallbackFromNative","(I)V"),
289                              check_AudioSystem_Command(err));
290}
291
292static jint
293android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
294{
295    const char *c_address = env->GetStringUTFChars(device_address, NULL);
296    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
297                                          static_cast <audio_policy_dev_state_t>(state),
298                                          c_address));
299    env->ReleaseStringUTFChars(device_address, c_address);
300    return (jint) status;
301}
302
303static jint
304android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
305{
306    const char *c_address = env->GetStringUTFChars(device_address, NULL);
307    int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
308                                          c_address));
309    env->ReleaseStringUTFChars(device_address, c_address);
310    return (jint) state;
311}
312
313static jint
314android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
315{
316    return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
317}
318
319static jint
320android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
321{
322    return (jint) check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
323                                                           static_cast <audio_policy_forced_cfg_t>(config)));
324}
325
326static jint
327android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
328{
329    return static_cast <jint>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
330}
331
332static jint
333android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
334{
335    return (jint) check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
336                                                                   indexMin,
337                                                                   indexMax));
338}
339
340static jint
341android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
342                                               jobject thiz,
343                                               jint stream,
344                                               jint index,
345                                               jint device)
346{
347    return (jint) check_AudioSystem_Command(
348            AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
349                                              index,
350                                              (audio_devices_t)device));
351}
352
353static jint
354android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env,
355                                               jobject thiz,
356                                               jint stream,
357                                               jint device)
358{
359    int index;
360    if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
361                                          &index,
362                                          (audio_devices_t)device)
363            != NO_ERROR) {
364        index = -1;
365    }
366    return (jint) index;
367}
368
369static jint
370android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
371{
372    return (jint) check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
373}
374
375static jfloat
376android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
377{
378    float value;
379    if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
380        value = -1.0;
381    }
382    return value;
383}
384
385static jint
386android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
387{
388    return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
389}
390
391static jfloat
392android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
393{
394    bool mute;
395    if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
396        mute = false;
397    }
398    return mute;
399}
400
401static jint
402android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
403{
404    return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
405}
406
407static jint
408android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
409{
410    return (jint) AudioSystem::getPrimaryOutputSamplingRate();
411}
412
413static jint
414android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
415{
416    return (jint) AudioSystem::getPrimaryOutputFrameCount();
417}
418
419static jint
420android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
421{
422    uint32_t afLatency;
423    if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
424            != NO_ERROR) {
425        afLatency = -1;
426    }
427    return (jint) afLatency;
428}
429
430static jint
431android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
432{
433    return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
434}
435
436static jint
437android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
438{
439    return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
440}
441
442
443static bool useInChannelMask(audio_port_type_t type, audio_port_role_t role)
444{
445    return ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
446                ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
447}
448
449static void convertAudioGainConfigToNative(JNIEnv *env,
450                                               struct audio_gain_config *nAudioGainConfig,
451                                               const jobject jAudioGainConfig,
452                                               bool useInMask)
453{
454    nAudioGainConfig->index = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mIndex);
455    nAudioGainConfig->mode = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
456    ALOGV("convertAudioGainConfigToNative got gain index %d", nAudioGainConfig->index);
457    jint jMask = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mChannelMask);
458    audio_channel_mask_t nMask;
459    if (useInMask) {
460        nMask = inChannelMaskToNative(jMask);
461        ALOGV("convertAudioGainConfigToNative IN mask java %x native %x", jMask, nMask);
462    } else {
463        nMask = outChannelMaskToNative(jMask);
464        ALOGV("convertAudioGainConfigToNative OUT mask java %x native %x", jMask, nMask);
465    }
466    nAudioGainConfig->channel_mask = nMask;
467    nAudioGainConfig->ramp_duration_ms = env->GetIntField(jAudioGainConfig,
468                                                       gAudioGainConfigFields.mRampDurationMs);
469    jintArray jValues = (jintArray)env->GetObjectField(jAudioGainConfig,
470                                                       gAudioGainConfigFields.mValues);
471    int *nValues = env->GetIntArrayElements(jValues, NULL);
472    size_t size = env->GetArrayLength(jValues);
473    memcpy(nAudioGainConfig->values, nValues, size * sizeof(int));
474    env->DeleteLocalRef(jValues);
475}
476
477
478static jint convertAudioPortConfigToNative(JNIEnv *env,
479                                               struct audio_port_config *nAudioPortConfig,
480                                               const jobject jAudioPortConfig)
481{
482    jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
483    jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
484    nAudioPortConfig->id = env->GetIntField(jHandle, gAudioHandleFields.mId);
485    nAudioPortConfig->role = (audio_port_role_t)env->GetIntField(jAudioPort,
486                                                                 gAudioPortFields.mRole);
487    if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
488        nAudioPortConfig->type = AUDIO_PORT_TYPE_DEVICE;
489    } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
490        nAudioPortConfig->type = AUDIO_PORT_TYPE_MIX;
491    } else {
492        env->DeleteLocalRef(jAudioPort);
493        env->DeleteLocalRef(jHandle);
494        return (jint)AUDIO_JAVA_ERROR;
495    }
496    ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
497          nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
498
499    nAudioPortConfig->sample_rate = env->GetIntField(jAudioPortConfig,
500                                                     gAudioPortConfigFields.mSamplingRate);
501
502    bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
503    audio_channel_mask_t nMask;
504    jint jMask = env->GetIntField(jAudioPortConfig,
505                                   gAudioPortConfigFields.mChannelMask);
506    if (useInMask) {
507        nMask = inChannelMaskToNative(jMask);
508        ALOGV("convertAudioPortConfigToNative IN mask java %x native %x", jMask, nMask);
509    } else {
510        nMask = outChannelMaskToNative(jMask);
511        ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
512    }
513    nAudioPortConfig->channel_mask = nMask;
514
515    jint jFormat = env->GetIntField(jAudioPortConfig, gAudioPortConfigFields.mFormat);
516    audio_format_t nFormat = audioFormatToNative(jFormat);
517    ALOGV("convertAudioPortConfigToNative format %d native %d", jFormat, nFormat);
518    nAudioPortConfig->format = nFormat;
519    jobject jGain = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mGain);
520    if (jGain != NULL) {
521        convertAudioGainConfigToNative(env, &nAudioPortConfig->gain, jGain, useInMask);
522        env->DeleteLocalRef(jGain);
523    } else {
524        ALOGV("convertAudioPortConfigToNative no gain");
525        nAudioPortConfig->gain.index = -1;
526    }
527    nAudioPortConfig->config_mask = env->GetIntField(jAudioPortConfig,
528                                                     gAudioPortConfigFields.mConfigMask);
529
530    env->DeleteLocalRef(jAudioPort);
531    env->DeleteLocalRef(jHandle);
532    return (jint)AUDIO_JAVA_SUCCESS;
533}
534
535static jint convertAudioPortConfigFromNative(JNIEnv *env,
536                                                 jobject jAudioPort,
537                                                 jobject *jAudioPortConfig,
538                                                 const struct audio_port_config *nAudioPortConfig)
539{
540    jint jStatus = AUDIO_JAVA_SUCCESS;
541    jobject jAudioGainConfig = NULL;
542    jobject jAudioGain = NULL;
543    jintArray jGainValues;
544    bool audioportCreated = false;
545
546    ALOGV("convertAudioPortConfigFromNative jAudioPort %p", jAudioPort);
547
548    if (jAudioPort == NULL) {
549        jobject jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
550                                                 nAudioPortConfig->id);
551
552        ALOGV("convertAudioPortConfigFromNative handle %d is a %s", nAudioPortConfig->id,
553              nAudioPortConfig->type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix");
554
555        if (jHandle == NULL) {
556            return (jint)AUDIO_JAVA_ERROR;
557        }
558        // create dummy port and port config objects with just the correct handle
559        // and configuration data. The actual AudioPortConfig objects will be
560        // constructed by java code with correct class type (device, mix etc...)
561        // and reference to AudioPort instance in this client
562        jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
563                                           jHandle,
564                                           0,
565                                           NULL,
566                                           NULL,
567                                           NULL,
568                                           NULL);
569        env->DeleteLocalRef(jHandle);
570        if (jAudioPort == NULL) {
571            return (jint)AUDIO_JAVA_ERROR;
572        }
573        ALOGV("convertAudioPortConfigFromNative jAudioPort created for handle %d",
574              nAudioPortConfig->id);
575
576        audioportCreated = true;
577    }
578
579    bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
580
581    audio_channel_mask_t nMask;
582    jint jMask;
583
584    int gainIndex = nAudioPortConfig->gain.index;
585    if (gainIndex >= 0) {
586        ALOGV("convertAudioPortConfigFromNative gain found with index %d mode %x",
587              gainIndex, nAudioPortConfig->gain.mode);
588        if (audioportCreated) {
589            ALOGV("convertAudioPortConfigFromNative creating gain");
590            jAudioGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
591                                               gainIndex,
592                                               0,
593                                               0,
594                                               0,
595                                               0,
596                                               0,
597                                               0,
598                                               0,
599                                               0);
600            if (jAudioGain == NULL) {
601                ALOGV("convertAudioPortConfigFromNative creating gain FAILED");
602                jStatus = (jint)AUDIO_JAVA_ERROR;
603                goto exit;
604            }
605        } else {
606            ALOGV("convertAudioPortConfigFromNative reading gain from port");
607            jobjectArray jGains = (jobjectArray)env->GetObjectField(jAudioPort,
608                                                                      gAudioPortFields.mGains);
609            if (jGains == NULL) {
610                ALOGV("convertAudioPortConfigFromNative could not get gains from port");
611                jStatus = (jint)AUDIO_JAVA_ERROR;
612                goto exit;
613            }
614            jAudioGain = env->GetObjectArrayElement(jGains, gainIndex);
615            env->DeleteLocalRef(jGains);
616            if (jAudioGain == NULL) {
617                ALOGV("convertAudioPortConfigFromNative could not get gain at index %d", gainIndex);
618                jStatus = (jint)AUDIO_JAVA_ERROR;
619                goto exit;
620            }
621        }
622        int numValues;
623        if (useInMask) {
624            numValues = audio_channel_count_from_in_mask(nAudioPortConfig->gain.channel_mask);
625        } else {
626            numValues = audio_channel_count_from_out_mask(nAudioPortConfig->gain.channel_mask);
627        }
628        jGainValues = env->NewIntArray(numValues);
629        if (jGainValues == NULL) {
630            ALOGV("convertAudioPortConfigFromNative could not create gain values %d", numValues);
631            jStatus = (jint)AUDIO_JAVA_ERROR;
632            goto exit;
633        }
634        env->SetIntArrayRegion(jGainValues, 0, numValues,
635                               nAudioPortConfig->gain.values);
636
637        nMask = nAudioPortConfig->gain.channel_mask;
638        if (useInMask) {
639            jMask = inChannelMaskFromNative(nMask);
640            ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
641        } else {
642            jMask = outChannelMaskFromNative(nMask);
643            ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
644        }
645
646        jAudioGainConfig = env->NewObject(gAudioGainConfigClass,
647                                        gAudioGainConfigCstor,
648                                        gainIndex,
649                                        jAudioGain,
650                                        nAudioPortConfig->gain.mode,
651                                        jMask,
652                                        jGainValues,
653                                        nAudioPortConfig->gain.ramp_duration_ms);
654        env->DeleteLocalRef(jGainValues);
655        if (jAudioGainConfig == NULL) {
656            ALOGV("convertAudioPortConfigFromNative could not create gain config");
657            jStatus = (jint)AUDIO_JAVA_ERROR;
658            goto exit;
659        }
660    }
661    jclass clazz;
662    jmethodID methodID;
663    if (audioportCreated) {
664        clazz = gAudioPortConfigClass;
665        methodID = gAudioPortConfigCstor;
666        ALOGV("convertAudioPortConfigFromNative building a generic port config");
667    } else {
668        if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
669            clazz = gAudioDevicePortConfigClass;
670            methodID = gAudioDevicePortConfigCstor;
671            ALOGV("convertAudioPortConfigFromNative building a device config");
672        } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
673            clazz = gAudioMixPortConfigClass;
674            methodID = gAudioMixPortConfigCstor;
675            ALOGV("convertAudioPortConfigFromNative building a mix config");
676        } else {
677            jStatus = (jint)AUDIO_JAVA_ERROR;
678            goto exit;
679        }
680    }
681    nMask = nAudioPortConfig->channel_mask;
682    if (useInMask) {
683        jMask = inChannelMaskFromNative(nMask);
684        ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
685    } else {
686        jMask = outChannelMaskFromNative(nMask);
687        ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
688    }
689
690    *jAudioPortConfig = env->NewObject(clazz, methodID,
691                                       jAudioPort,
692                                       nAudioPortConfig->sample_rate,
693                                       jMask,
694                                       audioFormatFromNative(nAudioPortConfig->format),
695                                       jAudioGainConfig);
696    if (*jAudioPortConfig == NULL) {
697        ALOGV("convertAudioPortConfigFromNative could not create new port config");
698        jStatus = (jint)AUDIO_JAVA_ERROR;
699    } else {
700        ALOGV("convertAudioPortConfigFromNative OK");
701    }
702
703exit:
704    if (audioportCreated) {
705        env->DeleteLocalRef(jAudioPort);
706        if (jAudioGain != NULL) {
707            env->DeleteLocalRef(jAudioGain);
708        }
709    }
710    if (jAudioGainConfig != NULL) {
711        env->DeleteLocalRef(jAudioGainConfig);
712    }
713    return jStatus;
714}
715
716static jint convertAudioPortFromNative(JNIEnv *env,
717                                           jobject *jAudioPort, const struct audio_port *nAudioPort)
718{
719    jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
720    jintArray jSamplingRates = NULL;
721    jintArray jChannelMasks = NULL;
722    jintArray jFormats = NULL;
723    jobjectArray jGains = NULL;
724    jobject jHandle = NULL;
725    bool useInMask;
726
727    ALOGV("convertAudioPortFromNative id %d role %d type %d",
728                                  nAudioPort->id, nAudioPort->role, nAudioPort->type);
729
730    jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
731    if (jSamplingRates == NULL) {
732        jStatus = (jint)AUDIO_JAVA_ERROR;
733        goto exit;
734    }
735    if (nAudioPort->num_sample_rates) {
736        env->SetIntArrayRegion(jSamplingRates, 0, nAudioPort->num_sample_rates,
737                               (jint *)nAudioPort->sample_rates);
738    }
739
740    jChannelMasks = env->NewIntArray(nAudioPort->num_channel_masks);
741    if (jChannelMasks == NULL) {
742        jStatus = (jint)AUDIO_JAVA_ERROR;
743        goto exit;
744    }
745    useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
746
747    jint jMask;
748    for (size_t j = 0; j < nAudioPort->num_channel_masks; j++) {
749        if (useInMask) {
750            jMask = inChannelMaskFromNative(nAudioPort->channel_masks[j]);
751        } else {
752            jMask = outChannelMaskFromNative(nAudioPort->channel_masks[j]);
753        }
754        env->SetIntArrayRegion(jChannelMasks, j, 1, &jMask);
755    }
756
757    jFormats = env->NewIntArray(nAudioPort->num_formats);
758    if (jFormats == NULL) {
759        jStatus = (jint)AUDIO_JAVA_ERROR;
760        goto exit;
761    }
762    for (size_t j = 0; j < nAudioPort->num_formats; j++) {
763        jint jFormat = audioFormatFromNative(nAudioPort->formats[j]);
764        env->SetIntArrayRegion(jFormats, j, 1, &jFormat);
765    }
766
767    jGains = env->NewObjectArray(nAudioPort->num_gains,
768                                          gAudioGainClass, NULL);
769    if (jGains == NULL) {
770        jStatus = (jint)AUDIO_JAVA_ERROR;
771        goto exit;
772    }
773    for (size_t j = 0; j < nAudioPort->num_gains; j++) {
774        audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
775        if (useInMask) {
776            jMask = inChannelMaskFromNative(nMask);
777            ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
778        } else {
779            jMask = outChannelMaskFromNative(nMask);
780            ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
781        }
782
783        jobject jGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
784                                                 j,
785                                                 nAudioPort->gains[j].mode,
786                                                 jMask,
787                                                 nAudioPort->gains[j].min_value,
788                                                 nAudioPort->gains[j].max_value,
789                                                 nAudioPort->gains[j].default_value,
790                                                 nAudioPort->gains[j].step_value,
791                                                 nAudioPort->gains[j].min_ramp_ms,
792                                                 nAudioPort->gains[j].max_ramp_ms);
793        if (jGain == NULL) {
794            jStatus = (jint)AUDIO_JAVA_ERROR;
795            goto exit;
796        }
797        env->SetObjectArrayElement(jGains, j, jGain);
798        env->DeleteLocalRef(jGain);
799    }
800
801    jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
802                                             nAudioPort->id);
803    if (jHandle == NULL) {
804        jStatus = (jint)AUDIO_JAVA_ERROR;
805        goto exit;
806    }
807
808    if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
809        ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
810        jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
811        *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
812                                     jHandle, jSamplingRates, jChannelMasks, jFormats, jGains,
813                                     nAudioPort->ext.device.type, jAddress);
814        env->DeleteLocalRef(jAddress);
815    } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
816        ALOGV("convertAudioPortFromNative is a mix");
817        *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
818                                     jHandle, nAudioPort->role, jSamplingRates, jChannelMasks,
819                                     jFormats, jGains);
820    } else {
821        ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
822        jStatus = (jint)AUDIO_JAVA_ERROR;
823        goto exit;
824    }
825    if (*jAudioPort == NULL) {
826        jStatus = (jint)AUDIO_JAVA_ERROR;
827        goto exit;
828    }
829
830    jobject jAudioPortConfig;
831    jStatus = convertAudioPortConfigFromNative(env,
832                                                       *jAudioPort,
833                                                       &jAudioPortConfig,
834                                                       &nAudioPort->active_config);
835    if (jStatus != AUDIO_JAVA_SUCCESS) {
836        return jStatus;
837    }
838
839    env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
840
841exit:
842    if (jSamplingRates != NULL) {
843        env->DeleteLocalRef(jSamplingRates);
844    }
845    if (jChannelMasks != NULL) {
846        env->DeleteLocalRef(jChannelMasks);
847    }
848    if (jFormats != NULL) {
849        env->DeleteLocalRef(jFormats);
850    }
851    if (jGains != NULL) {
852        env->DeleteLocalRef(jGains);
853    }
854    if (jHandle != NULL) {
855        env->DeleteLocalRef(jHandle);
856    }
857
858    return jStatus;
859}
860
861
862static jint
863android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
864                                         jobject jPorts, jintArray jGeneration)
865{
866    ALOGV("listAudioPorts");
867
868    if (jPorts == NULL) {
869        ALOGE("listAudioPorts NULL AudioPort ArrayList");
870        return (jint)AUDIO_JAVA_BAD_VALUE;
871    }
872    if (!env->IsInstanceOf(jPorts, gArrayListClass)) {
873        ALOGE("listAudioPorts not an arraylist");
874        return (jint)AUDIO_JAVA_BAD_VALUE;
875    }
876
877    if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
878        return (jint)AUDIO_JAVA_BAD_VALUE;
879    }
880
881    status_t status;
882    unsigned int generation1;
883    unsigned int generation;
884    unsigned int numPorts;
885    jint *nGeneration;
886    struct audio_port *nPorts = NULL;
887    int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
888
889    // get the port count and all the ports until they both return the same generation
890    do {
891        if (attempts-- < 0) {
892            status = TIMED_OUT;
893            break;
894        }
895
896        numPorts = 0;
897        status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
898                                             AUDIO_PORT_TYPE_NONE,
899                                                      &numPorts,
900                                                      NULL,
901                                                      &generation1);
902        if (status != NO_ERROR || numPorts == 0) {
903            ALOGE_IF(status != NO_ERROR, "AudioSystem::listAudioPorts error %d", status);
904            break;
905        }
906        nPorts = (struct audio_port *)realloc(nPorts, numPorts * sizeof(struct audio_port));
907
908        status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
909                                             AUDIO_PORT_TYPE_NONE,
910                                                      &numPorts,
911                                                      nPorts,
912                                                      &generation);
913        ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
914              numPorts, generation, generation1);
915    } while (generation1 != generation && status == NO_ERROR);
916
917    jint jStatus = nativeToJavaStatus(status);
918    if (jStatus != AUDIO_JAVA_SUCCESS) {
919        goto exit;
920    }
921
922    nGeneration = env->GetIntArrayElements(jGeneration, NULL);
923    if (nGeneration == NULL) {
924        jStatus = (jint)AUDIO_JAVA_ERROR;
925        goto exit;
926    }
927    nGeneration[0] = generation1;
928    env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
929
930    for (size_t i = 0; i < numPorts; i++) {
931        jobject jAudioPort;
932        jStatus = convertAudioPortFromNative(env, &jAudioPort, &nPorts[i]);
933        if (jStatus != AUDIO_JAVA_SUCCESS) {
934            goto exit;
935        }
936        env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort);
937    }
938
939exit:
940    free(nPorts);
941    return jStatus;
942}
943
944static int
945android_media_AudioSystem_createAudioPatch(JNIEnv *env, jobject clazz,
946                                 jobjectArray jPatches, jobjectArray jSources, jobjectArray jSinks)
947{
948    status_t status;
949    jint jStatus;
950
951    ALOGV("createAudioPatch");
952    if (jPatches == NULL || jSources == NULL || jSinks == NULL) {
953        return (jint)AUDIO_JAVA_BAD_VALUE;
954    }
955
956    if (env->GetArrayLength(jPatches) != 1) {
957        return (jint)AUDIO_JAVA_BAD_VALUE;
958    }
959    jint numSources = env->GetArrayLength(jSources);
960    if (numSources == 0 || numSources > AUDIO_PATCH_PORTS_MAX) {
961        return (jint)AUDIO_JAVA_BAD_VALUE;
962    }
963
964    jint numSinks = env->GetArrayLength(jSinks);
965    if (numSinks == 0 || numSinks > AUDIO_PATCH_PORTS_MAX) {
966        return (jint)AUDIO_JAVA_BAD_VALUE;
967    }
968
969    audio_patch_handle_t handle = (audio_patch_handle_t)0;
970    jobject jPatch = env->GetObjectArrayElement(jPatches, 0);
971    jobject jPatchHandle = NULL;
972    if (jPatch != NULL) {
973        if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
974            return (jint)AUDIO_JAVA_BAD_VALUE;
975        }
976        jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
977        handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
978    }
979
980    struct audio_patch nPatch;
981
982    nPatch.id = handle;
983    nPatch.num_sources = 0;
984    nPatch.num_sinks = 0;
985    jobject jSource = NULL;
986    jobject jSink = NULL;
987
988    for (jint i = 0; i < numSources; i++) {
989        jSource = env->GetObjectArrayElement(jSources, i);
990        if (!env->IsInstanceOf(jSource, gAudioPortConfigClass)) {
991            jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
992            goto exit;
993        }
994        jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource);
995        env->DeleteLocalRef(jSource);
996        jSource = NULL;
997        if (jStatus != AUDIO_JAVA_SUCCESS) {
998            goto exit;
999        }
1000        nPatch.num_sources++;
1001    }
1002
1003    for (jint i = 0; i < numSinks; i++) {
1004        jSink = env->GetObjectArrayElement(jSinks, i);
1005        if (!env->IsInstanceOf(jSink, gAudioPortConfigClass)) {
1006            jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
1007            goto exit;
1008        }
1009        jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink);
1010        env->DeleteLocalRef(jSink);
1011        jSink = NULL;
1012        if (jStatus != AUDIO_JAVA_SUCCESS) {
1013            goto exit;
1014        }
1015        nPatch.num_sinks++;
1016    }
1017
1018    ALOGV("AudioSystem::createAudioPatch");
1019    status = AudioSystem::createAudioPatch(&nPatch, &handle);
1020    ALOGV("AudioSystem::createAudioPatch() returned %d hande %d", status, handle);
1021
1022    jStatus = nativeToJavaStatus(status);
1023    if (jStatus != AUDIO_JAVA_SUCCESS) {
1024        goto exit;
1025    }
1026
1027    if (jPatchHandle == NULL) {
1028        jPatchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1029                                           handle);
1030        if (jPatchHandle == NULL) {
1031            jStatus = (jint)AUDIO_JAVA_ERROR;
1032            goto exit;
1033        }
1034        jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle, jSources, jSinks);
1035        if (jPatch == NULL) {
1036            jStatus = (jint)AUDIO_JAVA_ERROR;
1037            goto exit;
1038        }
1039        env->SetObjectArrayElement(jPatches, 0, jPatch);
1040    } else {
1041        env->SetIntField(jPatchHandle, gAudioHandleFields.mId, handle);
1042    }
1043
1044exit:
1045    if (jPatchHandle != NULL) {
1046        env->DeleteLocalRef(jPatchHandle);
1047    }
1048    if (jPatch != NULL) {
1049        env->DeleteLocalRef(jPatch);
1050    }
1051    if (jSource != NULL) {
1052        env->DeleteLocalRef(jSource);
1053    }
1054    if (jSink != NULL) {
1055        env->DeleteLocalRef(jSink);
1056    }
1057    return jStatus;
1058}
1059
1060static int
1061android_media_AudioSystem_releaseAudioPatch(JNIEnv *env, jobject clazz,
1062                                               jobject jPatch)
1063{
1064    ALOGV("releaseAudioPatch");
1065    if (jPatch == NULL) {
1066        return (jint)AUDIO_JAVA_BAD_VALUE;
1067    }
1068
1069    audio_patch_handle_t handle = (audio_patch_handle_t)0;
1070    jobject jPatchHandle = NULL;
1071    if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
1072        return (jint)AUDIO_JAVA_BAD_VALUE;
1073    }
1074    jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
1075    handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
1076    env->DeleteLocalRef(jPatchHandle);
1077
1078    ALOGV("AudioSystem::releaseAudioPatch");
1079    status_t status = AudioSystem::releaseAudioPatch(handle);
1080    ALOGV("AudioSystem::releaseAudioPatch() returned %d", status);
1081    jint jStatus = nativeToJavaStatus(status);
1082    return status;
1083}
1084
1085static jint
1086android_media_AudioSystem_listAudioPatches(JNIEnv *env, jobject clazz,
1087                                           jobject jPatches, jintArray jGeneration)
1088{
1089    ALOGV("listAudioPatches");
1090    if (jPatches == NULL) {
1091        ALOGE("listAudioPatches NULL AudioPatch ArrayList");
1092        return (jint)AUDIO_JAVA_BAD_VALUE;
1093    }
1094    if (!env->IsInstanceOf(jPatches, gArrayListClass)) {
1095        ALOGE("listAudioPatches not an arraylist");
1096        return (jint)AUDIO_JAVA_BAD_VALUE;
1097    }
1098
1099    if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
1100        return (jint)AUDIO_JAVA_BAD_VALUE;
1101    }
1102
1103    status_t status;
1104    unsigned int generation1;
1105    unsigned int generation;
1106    unsigned int numPatches;
1107    jint *nGeneration;
1108    struct audio_patch *nPatches = NULL;
1109    jobjectArray jSources = NULL;
1110    jobject jSource = NULL;
1111    jobjectArray jSinks = NULL;
1112    jobject jSink = NULL;
1113    jobject jPatch = NULL;
1114    int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
1115
1116    // get the patch count and all the patches until they both return the same generation
1117    do {
1118        if (attempts-- < 0) {
1119            status = TIMED_OUT;
1120            break;
1121        }
1122
1123        numPatches = 0;
1124        status = AudioSystem::listAudioPatches(&numPatches,
1125                                               NULL,
1126                                               &generation1);
1127        if (status != NO_ERROR || numPatches == 0) {
1128            ALOGE_IF(status != NO_ERROR, "listAudioPatches AudioSystem::listAudioPatches error %d",
1129                                      status);
1130            break;
1131        }
1132        nPatches = (struct audio_patch *)realloc(nPatches, numPatches * sizeof(struct audio_patch));
1133
1134        status = AudioSystem::listAudioPatches(&numPatches,
1135                                               nPatches,
1136                                               &generation);
1137        ALOGV("listAudioPatches AudioSystem::listAudioPatches numPatches %d generation %d generation1 %d",
1138              numPatches, generation, generation1);
1139
1140    } while (generation1 != generation && status == NO_ERROR);
1141
1142    jint jStatus = nativeToJavaStatus(status);
1143    if (jStatus != AUDIO_JAVA_SUCCESS) {
1144        goto exit;
1145    }
1146
1147    nGeneration = env->GetIntArrayElements(jGeneration, NULL);
1148    if (nGeneration == NULL) {
1149        jStatus = AUDIO_JAVA_ERROR;
1150        goto exit;
1151    }
1152    nGeneration[0] = generation1;
1153    env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
1154
1155    for (size_t i = 0; i < numPatches; i++) {
1156        jobject patchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1157                                                 nPatches[i].id);
1158        if (patchHandle == NULL) {
1159            jStatus = AUDIO_JAVA_ERROR;
1160            goto exit;
1161        }
1162        ALOGV("listAudioPatches patch %d num_sources %d num_sinks %d",
1163              i, nPatches[i].num_sources, nPatches[i].num_sinks);
1164
1165        env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
1166
1167        // load sources
1168        jSources = env->NewObjectArray(nPatches[i].num_sources,
1169                                       gAudioPortConfigClass, NULL);
1170        if (jSources == NULL) {
1171            jStatus = AUDIO_JAVA_ERROR;
1172            goto exit;
1173        }
1174
1175        for (size_t j = 0; j < nPatches[i].num_sources; j++) {
1176            jStatus = convertAudioPortConfigFromNative(env,
1177                                                      NULL,
1178                                                      &jSource,
1179                                                      &nPatches[i].sources[j]);
1180            if (jStatus != AUDIO_JAVA_SUCCESS) {
1181                goto exit;
1182            }
1183            env->SetObjectArrayElement(jSources, j, jSource);
1184            env->DeleteLocalRef(jSource);
1185            jSource = NULL;
1186            ALOGV("listAudioPatches patch %d source %d is a %s handle %d",
1187                  i, j,
1188                  nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
1189                  nPatches[i].sources[j].id);
1190        }
1191        // load sinks
1192        jSinks = env->NewObjectArray(nPatches[i].num_sinks,
1193                                     gAudioPortConfigClass, NULL);
1194        if (jSinks == NULL) {
1195            jStatus = AUDIO_JAVA_ERROR;
1196            goto exit;
1197        }
1198
1199        for (size_t j = 0; j < nPatches[i].num_sinks; j++) {
1200            jStatus = convertAudioPortConfigFromNative(env,
1201                                                      NULL,
1202                                                      &jSink,
1203                                                      &nPatches[i].sinks[j]);
1204
1205            if (jStatus != AUDIO_JAVA_SUCCESS) {
1206                goto exit;
1207            }
1208            env->SetObjectArrayElement(jSinks, j, jSink);
1209            env->DeleteLocalRef(jSink);
1210            jSink = NULL;
1211            ALOGV("listAudioPatches patch %d sink %d is a %s handle %d",
1212                  i, j,
1213                  nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
1214                  nPatches[i].sinks[j].id);
1215        }
1216
1217        jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor,
1218                                       patchHandle, jSources, jSinks);
1219        env->DeleteLocalRef(jSources);
1220        jSources = NULL;
1221        env->DeleteLocalRef(jSinks);
1222        jSinks = NULL;
1223        if (jPatch == NULL) {
1224            jStatus = AUDIO_JAVA_ERROR;
1225            goto exit;
1226        }
1227        env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch);
1228        env->DeleteLocalRef(jPatch);
1229        jPatch = NULL;
1230    }
1231
1232exit:
1233    if (jSources != NULL) {
1234        env->DeleteLocalRef(jSources);
1235    }
1236    if (jSource != NULL) {
1237        env->DeleteLocalRef(jSource);
1238    }
1239    if (jSinks != NULL) {
1240        env->DeleteLocalRef(jSinks);
1241    }
1242    if (jSink != NULL) {
1243        env->DeleteLocalRef(jSink);
1244    }
1245    if (jPatch != NULL) {
1246        env->DeleteLocalRef(jPatch);
1247    }
1248    free(nPatches);
1249    return jStatus;
1250}
1251
1252static jint
1253android_media_AudioSystem_setAudioPortConfig(JNIEnv *env, jobject clazz,
1254                                 jobject jAudioPortConfig)
1255{
1256    ALOGV("setAudioPortConfig");
1257    if (jAudioPortConfig == NULL) {
1258        return AUDIO_JAVA_BAD_VALUE;
1259    }
1260    if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
1261        return AUDIO_JAVA_BAD_VALUE;
1262    }
1263    struct audio_port_config nAudioPortConfig;
1264    jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig);
1265    if (jStatus != AUDIO_JAVA_SUCCESS) {
1266        return jStatus;
1267    }
1268    status_t status = AudioSystem::setAudioPortConfig(&nAudioPortConfig);
1269    ALOGV("AudioSystem::setAudioPortConfig() returned %d", status);
1270    jStatus = nativeToJavaStatus(status);
1271    return jStatus;
1272}
1273
1274static void
1275android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this)
1276{
1277    ALOGV("eventHandlerSetup");
1278
1279    sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
1280
1281    AudioSystem::setAudioPortCallback(callback);
1282}
1283
1284static void
1285android_media_AudioSystem_eventHandlerFinalize(JNIEnv *env, jobject thiz)
1286{
1287    ALOGV("eventHandlerFinalize");
1288
1289    sp<JNIAudioPortCallback> callback;
1290
1291    AudioSystem::setAudioPortCallback(callback);
1292}
1293
1294// ----------------------------------------------------------------------------
1295
1296static JNINativeMethod gMethods[] = {
1297    {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
1298    {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
1299    {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
1300    {"isMicrophoneMuted",   "()Z",      (void *)android_media_AudioSystem_isMicrophoneMuted},
1301    {"isStreamActive",      "(II)Z",    (void *)android_media_AudioSystem_isStreamActive},
1302    {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
1303    {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
1304    {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
1305    {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
1306    {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
1307    {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
1308    {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
1309    {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
1310    {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
1311    {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
1312    {"getStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_getStreamVolumeIndex},
1313    {"setMasterVolume",     "(F)I",     (void *)android_media_AudioSystem_setMasterVolume},
1314    {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
1315    {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
1316    {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
1317    {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
1318    {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
1319    {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
1320    {"getOutputLatency",    "(I)I",     (void *)android_media_AudioSystem_getOutputLatency},
1321    {"setLowRamDevice",     "(Z)I",     (void *)android_media_AudioSystem_setLowRamDevice},
1322    {"checkAudioFlinger",    "()I",     (void *)android_media_AudioSystem_checkAudioFlinger},
1323    {"listAudioPorts",      "(Ljava/util/ArrayList;[I)I",
1324                                                (void *)android_media_AudioSystem_listAudioPorts},
1325    {"createAudioPatch",    "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
1326                                            (void *)android_media_AudioSystem_createAudioPatch},
1327    {"releaseAudioPatch",   "(Landroid/media/AudioPatch;)I",
1328                                            (void *)android_media_AudioSystem_releaseAudioPatch},
1329    {"listAudioPatches",    "(Ljava/util/ArrayList;[I)I",
1330                                                (void *)android_media_AudioSystem_listAudioPatches},
1331    {"setAudioPortConfig",   "(Landroid/media/AudioPortConfig;)I",
1332                                            (void *)android_media_AudioSystem_setAudioPortConfig},
1333};
1334
1335
1336static JNINativeMethod gEventHandlerMethods[] = {
1337    {"native_setup",
1338        "(Ljava/lang/Object;)V",
1339        (void *)android_media_AudioSystem_eventHandlerSetup},
1340    {"native_finalize",
1341        "()V",
1342        (void *)android_media_AudioSystem_eventHandlerFinalize},
1343};
1344
1345int register_android_media_AudioSystem(JNIEnv *env)
1346{
1347
1348    jclass arrayListClass = env->FindClass("java/util/ArrayList");
1349    gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
1350    gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
1351
1352    jclass audioHandleClass = env->FindClass("android/media/AudioHandle");
1353    gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass);
1354    gAudioHandleCstor = env->GetMethodID(audioHandleClass, "<init>", "(I)V");
1355    gAudioHandleFields.mId = env->GetFieldID(audioHandleClass, "mId", "I");
1356
1357    jclass audioPortClass = env->FindClass("android/media/AudioPort");
1358    gAudioPortClass = (jclass) env->NewGlobalRef(audioPortClass);
1359    gAudioPortCstor = env->GetMethodID(audioPortClass, "<init>",
1360                               "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
1361    gAudioPortFields.mHandle = env->GetFieldID(audioPortClass, "mHandle",
1362                                               "Landroid/media/AudioHandle;");
1363    gAudioPortFields.mRole = env->GetFieldID(audioPortClass, "mRole", "I");
1364    gAudioPortFields.mGains = env->GetFieldID(audioPortClass, "mGains",
1365                                              "[Landroid/media/AudioGain;");
1366    gAudioPortFields.mActiveConfig = env->GetFieldID(audioPortClass, "mActiveConfig",
1367                                              "Landroid/media/AudioPortConfig;");
1368
1369    jclass audioPortConfigClass = env->FindClass("android/media/AudioPortConfig");
1370    gAudioPortConfigClass = (jclass) env->NewGlobalRef(audioPortConfigClass);
1371    gAudioPortConfigCstor = env->GetMethodID(audioPortConfigClass, "<init>",
1372                                 "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
1373    gAudioPortConfigFields.mPort = env->GetFieldID(audioPortConfigClass, "mPort",
1374                                                   "Landroid/media/AudioPort;");
1375    gAudioPortConfigFields.mSamplingRate = env->GetFieldID(audioPortConfigClass,
1376                                                           "mSamplingRate", "I");
1377    gAudioPortConfigFields.mChannelMask = env->GetFieldID(audioPortConfigClass,
1378                                                          "mChannelMask", "I");
1379    gAudioPortConfigFields.mFormat = env->GetFieldID(audioPortConfigClass, "mFormat", "I");
1380    gAudioPortConfigFields.mGain = env->GetFieldID(audioPortConfigClass, "mGain",
1381                                                   "Landroid/media/AudioGainConfig;");
1382    gAudioPortConfigFields.mConfigMask = env->GetFieldID(audioPortConfigClass, "mConfigMask", "I");
1383
1384    jclass audioDevicePortConfigClass = env->FindClass("android/media/AudioDevicePortConfig");
1385    gAudioDevicePortConfigClass = (jclass) env->NewGlobalRef(audioDevicePortConfigClass);
1386    gAudioDevicePortConfigCstor = env->GetMethodID(audioDevicePortConfigClass, "<init>",
1387                         "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
1388
1389    jclass audioMixPortConfigClass = env->FindClass("android/media/AudioMixPortConfig");
1390    gAudioMixPortConfigClass = (jclass) env->NewGlobalRef(audioMixPortConfigClass);
1391    gAudioMixPortConfigCstor = env->GetMethodID(audioMixPortConfigClass, "<init>",
1392                         "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
1393
1394    jclass audioDevicePortClass = env->FindClass("android/media/AudioDevicePort");
1395    gAudioDevicePortClass = (jclass) env->NewGlobalRef(audioDevicePortClass);
1396    gAudioDevicePortCstor = env->GetMethodID(audioDevicePortClass, "<init>",
1397             "(Landroid/media/AudioHandle;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
1398
1399    jclass audioMixPortClass = env->FindClass("android/media/AudioMixPort");
1400    gAudioMixPortClass = (jclass) env->NewGlobalRef(audioMixPortClass);
1401    gAudioMixPortCstor = env->GetMethodID(audioMixPortClass, "<init>",
1402                              "(Landroid/media/AudioHandle;I[I[I[I[Landroid/media/AudioGain;)V");
1403
1404    jclass audioGainClass = env->FindClass("android/media/AudioGain");
1405    gAudioGainClass = (jclass) env->NewGlobalRef(audioGainClass);
1406    gAudioGainCstor = env->GetMethodID(audioGainClass, "<init>", "(IIIIIIIII)V");
1407
1408    jclass audioGainConfigClass = env->FindClass("android/media/AudioGainConfig");
1409    gAudioGainConfigClass = (jclass) env->NewGlobalRef(audioGainConfigClass);
1410    gAudioGainConfigCstor = env->GetMethodID(audioGainConfigClass, "<init>",
1411                                             "(ILandroid/media/AudioGain;II[II)V");
1412    gAudioGainConfigFields.mIndex = env->GetFieldID(gAudioGainConfigClass, "mIndex", "I");
1413    gAudioGainConfigFields.mMode = env->GetFieldID(audioGainConfigClass, "mMode", "I");
1414    gAudioGainConfigFields.mChannelMask = env->GetFieldID(audioGainConfigClass, "mChannelMask",
1415                                                          "I");
1416    gAudioGainConfigFields.mValues = env->GetFieldID(audioGainConfigClass, "mValues", "[I");
1417    gAudioGainConfigFields.mRampDurationMs = env->GetFieldID(audioGainConfigClass,
1418                                                             "mRampDurationMs", "I");
1419
1420    jclass audioPatchClass = env->FindClass("android/media/AudioPatch");
1421    gAudioPatchClass = (jclass) env->NewGlobalRef(audioPatchClass);
1422    gAudioPatchCstor = env->GetMethodID(audioPatchClass, "<init>",
1423"(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V");
1424    gAudioPatchFields.mHandle = env->GetFieldID(audioPatchClass, "mHandle",
1425                                                "Landroid/media/AudioHandle;");
1426
1427    jclass eventHandlerClass = env->FindClass(kEventHandlerClassPathName);
1428    gPostEventFromNative = env->GetStaticMethodID(eventHandlerClass, "postEventFromNative",
1429                                            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1430
1431
1432    AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
1433
1434    int status = AndroidRuntime::registerNativeMethods(env,
1435                kClassPathName, gMethods, NELEM(gMethods));
1436
1437    if (status == 0) {
1438        status = AndroidRuntime::registerNativeMethods(env,
1439                kEventHandlerClassPathName, gEventHandlerMethods, NELEM(gEventHandlerMethods));
1440    }
1441    return status;
1442}
1443