• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 using namespace android;
37 
38 static const char* const kClassPathName = "android/media/AudioSystem";
39 
40 static jclass gArrayListClass;
41 static struct {
42     jmethodID    add;
43 } gArrayListMethods;
44 
45 static jclass gAudioHandleClass;
46 static jmethodID gAudioHandleCstor;
47 static struct {
48     jfieldID    mId;
49 } gAudioHandleFields;
50 
51 static jclass gAudioPortClass;
52 static jmethodID gAudioPortCstor;
53 static struct {
54     jfieldID    mHandle;
55     jfieldID    mRole;
56     jfieldID    mGains;
57     jfieldID    mActiveConfig;
58     // other fields unused by JNI
59 } gAudioPortFields;
60 
61 static jclass gAudioPortConfigClass;
62 static jmethodID gAudioPortConfigCstor;
63 static struct {
64     jfieldID    mPort;
65     jfieldID    mSamplingRate;
66     jfieldID    mChannelMask;
67     jfieldID    mFormat;
68     jfieldID    mGain;
69     jfieldID    mConfigMask;
70 } gAudioPortConfigFields;
71 
72 static jclass gAudioDevicePortClass;
73 static jmethodID gAudioDevicePortCstor;
74 
75 static jclass gAudioDevicePortConfigClass;
76 static jmethodID gAudioDevicePortConfigCstor;
77 
78 static jclass gAudioMixPortClass;
79 static jmethodID gAudioMixPortCstor;
80 
81 static jclass gAudioMixPortConfigClass;
82 static jmethodID gAudioMixPortConfigCstor;
83 
84 static jclass gAudioGainClass;
85 static jmethodID gAudioGainCstor;
86 
87 static jclass gAudioGainConfigClass;
88 static jmethodID gAudioGainConfigCstor;
89 static 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 
98 static jclass gAudioPatchClass;
99 static jmethodID gAudioPatchCstor;
100 static struct {
101     jfieldID    mHandle;
102     // other fields unused by JNI
103 } gAudioPatchFields;
104 
105 static const char* const kEventHandlerClassPathName =
106         "android/media/AudioPortEventHandler";
107 static jmethodID gPostEventFromNative;
108 
109 enum AudioError {
110     kAudioStatusOk = 0,
111     kAudioStatusError = 1,
112     kAudioStatusMediaServerDied = 100
113 };
114 
115 enum  {
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
125 class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
126 {
127 public:
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 
135 private:
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 
JNIAudioPortCallback(JNIEnv * env,jobject thiz,jobject weak_thiz)142 JNIAudioPortCallback::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 
~JNIAudioPortCallback()159 JNIAudioPortCallback::~JNIAudioPortCallback()
160 {
161     // remove global references
162     JNIEnv *env = AndroidRuntime::getJNIEnv();
163     env->DeleteGlobalRef(mObject);
164     env->DeleteGlobalRef(mClass);
165 }
166 
sendEvent(int event)167 void 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 
onAudioPortListUpdate()179 void JNIAudioPortCallback::onAudioPortListUpdate()
180 {
181     sendEvent(AUDIOPORT_EVENT_PORT_LIST_UPDATED);
182 }
183 
onAudioPatchListUpdate()184 void JNIAudioPortCallback::onAudioPatchListUpdate()
185 {
186     sendEvent(AUDIOPORT_EVENT_PATCH_LIST_UPDATED);
187 }
188 
onServiceDied()189 void JNIAudioPortCallback::onServiceDied()
190 {
191     sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
192 }
193 
check_AudioSystem_Command(status_t status)194 static 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 
207 static jint
android_media_AudioSystem_muteMicrophone(JNIEnv * env,jobject thiz,jboolean on)208 android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
209 {
210     return (jint) check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
211 }
212 
213 static jboolean
android_media_AudioSystem_isMicrophoneMuted(JNIEnv * env,jobject thiz)214 android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
215 {
216     bool state = false;
217     AudioSystem::isMicrophoneMuted(&state);
218     return state;
219 }
220 
221 static jboolean
android_media_AudioSystem_isStreamActive(JNIEnv * env,jobject thiz,jint stream,jint inPastMs)222 android_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 
229 static jboolean
android_media_AudioSystem_isStreamActiveRemotely(JNIEnv * env,jobject thiz,jint stream,jint inPastMs)230 android_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 
238 static jboolean
android_media_AudioSystem_isSourceActive(JNIEnv * env,jobject thiz,jint source)239 android_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 
246 static jint
android_media_AudioSystem_newAudioSessionId(JNIEnv * env,jobject thiz)247 android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
248 {
249     return AudioSystem::newAudioUniqueId();
250 }
251 
252 static jint
android_media_AudioSystem_setParameters(JNIEnv * env,jobject thiz,jstring keyValuePairs)253 android_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 
265 static jstring
android_media_AudioSystem_getParameters(JNIEnv * env,jobject thiz,jstring keys)266 android_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 
277 static void
android_media_AudioSystem_error_callback(status_t err)278 android_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 
294 static jint
android_media_AudioSystem_setDeviceConnectionState(JNIEnv * env,jobject thiz,jint device,jint state,jstring device_address)295 android_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 
305 static jint
android_media_AudioSystem_getDeviceConnectionState(JNIEnv * env,jobject thiz,jint device,jstring device_address)306 android_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 
315 static jint
android_media_AudioSystem_setPhoneState(JNIEnv * env,jobject thiz,jint state)316 android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
317 {
318     return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
319 }
320 
321 static jint
android_media_AudioSystem_setForceUse(JNIEnv * env,jobject thiz,jint usage,jint config)322 android_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 
328 static jint
android_media_AudioSystem_getForceUse(JNIEnv * env,jobject thiz,jint usage)329 android_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 
334 static jint
android_media_AudioSystem_initStreamVolume(JNIEnv * env,jobject thiz,jint stream,jint indexMin,jint indexMax)335 android_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 
342 static jint
android_media_AudioSystem_setStreamVolumeIndex(JNIEnv * env,jobject thiz,jint stream,jint index,jint device)343 android_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 
355 static jint
android_media_AudioSystem_getStreamVolumeIndex(JNIEnv * env,jobject thiz,jint stream,jint device)356 android_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 
371 static jint
android_media_AudioSystem_setMasterVolume(JNIEnv * env,jobject thiz,jfloat value)372 android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
373 {
374     return (jint) check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
375 }
376 
377 static jfloat
android_media_AudioSystem_getMasterVolume(JNIEnv * env,jobject thiz)378 android_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 
387 static jint
android_media_AudioSystem_setMasterMute(JNIEnv * env,jobject thiz,jboolean mute)388 android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
389 {
390     return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
391 }
392 
393 static jfloat
android_media_AudioSystem_getMasterMute(JNIEnv * env,jobject thiz)394 android_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 
403 static jint
android_media_AudioSystem_getDevicesForStream(JNIEnv * env,jobject thiz,jint stream)404 android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
405 {
406     return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
407 }
408 
409 static jint
android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv * env,jobject clazz)410 android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
411 {
412     return (jint) AudioSystem::getPrimaryOutputSamplingRate();
413 }
414 
415 static jint
android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv * env,jobject clazz)416 android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
417 {
418     return (jint) AudioSystem::getPrimaryOutputFrameCount();
419 }
420 
421 static jint
android_media_AudioSystem_getOutputLatency(JNIEnv * env,jobject clazz,jint stream)422 android_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 
432 static jint
android_media_AudioSystem_setLowRamDevice(JNIEnv * env,jobject clazz,jboolean isLowRamDevice)433 android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
434 {
435     return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
436 }
437 
438 static jint
android_media_AudioSystem_checkAudioFlinger(JNIEnv * env,jobject clazz)439 android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
440 {
441     return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
442 }
443 
444 
useInChannelMask(audio_port_type_t type,audio_port_role_t role)445 static 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 
convertAudioGainConfigToNative(JNIEnv * env,struct audio_gain_config * nAudioGainConfig,const jobject jAudioGainConfig,bool useInMask)451 static 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 
convertAudioPortConfigToNative(JNIEnv * env,struct audio_port_config * nAudioPortConfig,const jobject jAudioPortConfig)480 static 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 
convertAudioPortConfigFromNative(JNIEnv * env,jobject jAudioPort,jobject * jAudioPortConfig,const struct audio_port_config * nAudioPortConfig)537 static 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 
705 exit:
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 
convertAudioPortFromNative(JNIEnv * env,jobject * jAudioPort,const struct audio_port * nAudioPort)718 static 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 
843 exit:
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 
864 static jint
android_media_AudioSystem_listAudioPorts(JNIEnv * env,jobject clazz,jobject jPorts,jintArray jGeneration)865 android_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 
941 exit:
942     free(nPorts);
943     return jStatus;
944 }
945 
946 static int
android_media_AudioSystem_createAudioPatch(JNIEnv * env,jobject clazz,jobjectArray jPatches,jobjectArray jSources,jobjectArray jSinks)947 android_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 
1046 exit:
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 
1062 static int
android_media_AudioSystem_releaseAudioPatch(JNIEnv * env,jobject clazz,jobject jPatch)1063 android_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 
1087 static jint
android_media_AudioSystem_listAudioPatches(JNIEnv * env,jobject clazz,jobject jPatches,jintArray jGeneration)1088 android_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 
1234 exit:
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 
1254 static jint
android_media_AudioSystem_setAudioPortConfig(JNIEnv * env,jobject clazz,jobject jAudioPortConfig)1255 android_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 
1276 static void
android_media_AudioSystem_eventHandlerSetup(JNIEnv * env,jobject thiz,jobject weak_this)1277 android_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 
1286 static void
android_media_AudioSystem_eventHandlerFinalize(JNIEnv * env,jobject thiz)1287 android_media_AudioSystem_eventHandlerFinalize(JNIEnv *env, jobject thiz)
1288 {
1289     ALOGV("eventHandlerFinalize");
1290 
1291     sp<JNIAudioPortCallback> callback;
1292 
1293     AudioSystem::setAudioPortCallback(callback);
1294 }
1295 
1296 static jint
android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv * env,jobject thiz,jint sessionId)1297 android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
1298 {
1299     return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId);
1300 }
1301 
1302 // ----------------------------------------------------------------------------
1303 
1304 static 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 
1346 static 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 
register_android_media_AudioSystem(JNIEnv * env)1355 int 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