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