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