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