• 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 <sstream>
24 #include <jni.h>
25 #include <JNIHelp.h>
26 #include "core_jni_helpers.h"
27 
28 #include <media/AudioSystem.h>
29 #include <media/AudioPolicy.h>
30 #include <nativehelper/ScopedLocalRef.h>
31 #include <system/audio.h>
32 #include <system/audio_policy.h>
33 #include "android_media_AudioFormat.h"
34 #include "android_media_AudioErrors.h"
35 
36 // ----------------------------------------------------------------------------
37 
38 using namespace android;
39 
40 static const char* const kClassPathName = "android/media/AudioSystem";
41 
42 static jclass gArrayListClass;
43 static struct {
44     jmethodID    add;
45     jmethodID    toArray;
46 } gArrayListMethods;
47 
48 static jclass gAudioHandleClass;
49 static jmethodID gAudioHandleCstor;
50 static struct {
51     jfieldID    mId;
52 } gAudioHandleFields;
53 
54 static jclass gAudioPortClass;
55 static jmethodID gAudioPortCstor;
56 static struct {
57     jfieldID    mHandle;
58     jfieldID    mRole;
59     jfieldID    mGains;
60     jfieldID    mActiveConfig;
61     // other fields unused by JNI
62 } gAudioPortFields;
63 
64 static jclass gAudioPortConfigClass;
65 static jmethodID gAudioPortConfigCstor;
66 static struct {
67     jfieldID    mPort;
68     jfieldID    mSamplingRate;
69     jfieldID    mChannelMask;
70     jfieldID    mFormat;
71     jfieldID    mGain;
72     jfieldID    mConfigMask;
73 } gAudioPortConfigFields;
74 
75 static jclass gAudioDevicePortClass;
76 static jmethodID gAudioDevicePortCstor;
77 
78 static jclass gAudioDevicePortConfigClass;
79 static jmethodID gAudioDevicePortConfigCstor;
80 
81 static jclass gAudioMixPortClass;
82 static jmethodID gAudioMixPortCstor;
83 
84 static jclass gAudioMixPortConfigClass;
85 static jmethodID gAudioMixPortConfigCstor;
86 
87 static jclass gAudioGainClass;
88 static jmethodID gAudioGainCstor;
89 
90 static jclass gAudioGainConfigClass;
91 static jmethodID gAudioGainConfigCstor;
92 static struct {
93     jfieldID mIndex;
94     jfieldID mMode;
95     jfieldID mChannelMask;
96     jfieldID mValues;
97     jfieldID mRampDurationMs;
98     // other fields unused by JNI
99 } gAudioGainConfigFields;
100 
101 static jclass gAudioPatchClass;
102 static jmethodID gAudioPatchCstor;
103 static struct {
104     jfieldID    mHandle;
105     // other fields unused by JNI
106 } gAudioPatchFields;
107 
108 static jclass gAudioMixClass;
109 static struct {
110     jfieldID    mRule;
111     jfieldID    mFormat;
112     jfieldID    mRouteFlags;
113     jfieldID    mDeviceType;
114     jfieldID    mDeviceAddress;
115     jfieldID    mMixType;
116     jfieldID    mCallbackFlags;
117 } gAudioMixFields;
118 
119 static jclass gAudioFormatClass;
120 static struct {
121     jfieldID    mEncoding;
122     jfieldID    mSampleRate;
123     jfieldID    mChannelMask;
124     // other fields unused by JNI
125 } gAudioFormatFields;
126 
127 static jclass gAudioMixingRuleClass;
128 static struct {
129     jfieldID    mCriteria;
130     // other fields unused by JNI
131 } gAudioMixingRuleFields;
132 
133 static jclass gAudioMixMatchCriterionClass;
134 static struct {
135     jfieldID    mAttr;
136     jfieldID    mIntProp;
137     jfieldID    mRule;
138 } gAudioMixMatchCriterionFields;
139 
140 static jclass gAudioAttributesClass;
141 static struct {
142     jfieldID    mUsage;
143     jfieldID    mSource;
144 } gAudioAttributesFields;
145 
146 
147 static const char* const kEventHandlerClassPathName =
148         "android/media/AudioPortEventHandler";
149 static struct {
150     jfieldID    mJniCallback;
151 } gEventHandlerFields;
152 static struct {
153     jmethodID    postEventFromNative;
154 } gAudioPortEventHandlerMethods;
155 
156 static struct {
157     jmethodID postDynPolicyEventFromNative;
158     jmethodID postRecordConfigEventFromNative;
159 } gAudioPolicyEventHandlerMethods;
160 
161 static Mutex gLock;
162 
163 enum AudioError {
164     kAudioStatusOk = 0,
165     kAudioStatusError = 1,
166     kAudioStatusMediaServerDied = 100
167 };
168 
169 enum  {
170     AUDIOPORT_EVENT_PORT_LIST_UPDATED = 1,
171     AUDIOPORT_EVENT_PATCH_LIST_UPDATED = 2,
172     AUDIOPORT_EVENT_SERVICE_DIED = 3,
173 };
174 
175 #define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
176 
177 // ----------------------------------------------------------------------------
178 // ref-counted object for audio port callbacks
179 class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
180 {
181 public:
182     JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz);
183     ~JNIAudioPortCallback();
184 
185     virtual void onAudioPortListUpdate();
186     virtual void onAudioPatchListUpdate();
187     virtual void onServiceDied();
188 
189 private:
190     void sendEvent(int event);
191 
192     jclass      mClass;     // Reference to AudioPortEventHandler class
193     jobject     mObject;    // Weak ref to AudioPortEventHandler Java object to call on
194 };
195 
JNIAudioPortCallback(JNIEnv * env,jobject thiz,jobject weak_thiz)196 JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
197 {
198 
199     // Hold onto the AudioPortEventHandler class for use in calling the static method
200     // that posts events to the application thread.
201     jclass clazz = env->GetObjectClass(thiz);
202     if (clazz == NULL) {
203         ALOGE("Can't find class %s", kEventHandlerClassPathName);
204         return;
205     }
206     mClass = (jclass)env->NewGlobalRef(clazz);
207 
208     // We use a weak reference so the AudioPortEventHandler object can be garbage collected.
209     // The reference is only used as a proxy for callbacks.
210     mObject  = env->NewGlobalRef(weak_thiz);
211 }
212 
~JNIAudioPortCallback()213 JNIAudioPortCallback::~JNIAudioPortCallback()
214 {
215     // remove global references
216     JNIEnv *env = AndroidRuntime::getJNIEnv();
217     if (env == NULL) {
218         return;
219     }
220     env->DeleteGlobalRef(mObject);
221     env->DeleteGlobalRef(mClass);
222 }
223 
sendEvent(int event)224 void JNIAudioPortCallback::sendEvent(int event)
225 {
226     JNIEnv *env = AndroidRuntime::getJNIEnv();
227     if (env == NULL) {
228         return;
229     }
230     env->CallStaticVoidMethod(mClass, gAudioPortEventHandlerMethods.postEventFromNative, mObject,
231                               event, 0, 0, NULL);
232     if (env->ExceptionCheck()) {
233         ALOGW("An exception occurred while notifying an event.");
234         env->ExceptionClear();
235     }
236 }
237 
onAudioPortListUpdate()238 void JNIAudioPortCallback::onAudioPortListUpdate()
239 {
240     sendEvent(AUDIOPORT_EVENT_PORT_LIST_UPDATED);
241 }
242 
onAudioPatchListUpdate()243 void JNIAudioPortCallback::onAudioPatchListUpdate()
244 {
245     sendEvent(AUDIOPORT_EVENT_PATCH_LIST_UPDATED);
246 }
247 
onServiceDied()248 void JNIAudioPortCallback::onServiceDied()
249 {
250     sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
251 }
252 
setJniCallback(JNIEnv * env,jobject thiz,const sp<JNIAudioPortCallback> & callback)253 static sp<JNIAudioPortCallback> setJniCallback(JNIEnv* env,
254                                        jobject thiz,
255                                        const sp<JNIAudioPortCallback>& callback)
256 {
257     Mutex::Autolock l(gLock);
258     sp<JNIAudioPortCallback> old =
259             (JNIAudioPortCallback*)env->GetLongField(thiz, gEventHandlerFields.mJniCallback);
260     if (callback.get()) {
261         callback->incStrong((void*)setJniCallback);
262     }
263     if (old != 0) {
264         old->decStrong((void*)setJniCallback);
265     }
266     env->SetLongField(thiz, gEventHandlerFields.mJniCallback, (jlong)callback.get());
267     return old;
268 }
269 
check_AudioSystem_Command(status_t status)270 static int check_AudioSystem_Command(status_t status)
271 {
272     switch (status) {
273     case DEAD_OBJECT:
274         return kAudioStatusMediaServerDied;
275     case NO_ERROR:
276         return kAudioStatusOk;
277     default:
278         break;
279     }
280     return kAudioStatusError;
281 }
282 
283 static jint
android_media_AudioSystem_muteMicrophone(JNIEnv * env,jobject thiz,jboolean on)284 android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
285 {
286     return (jint) check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
287 }
288 
289 static jboolean
android_media_AudioSystem_isMicrophoneMuted(JNIEnv * env,jobject thiz)290 android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
291 {
292     bool state = false;
293     AudioSystem::isMicrophoneMuted(&state);
294     return state;
295 }
296 
297 static jboolean
android_media_AudioSystem_isStreamActive(JNIEnv * env,jobject thiz,jint stream,jint inPastMs)298 android_media_AudioSystem_isStreamActive(JNIEnv *env, jobject thiz, jint stream, jint inPastMs)
299 {
300     bool state = false;
301     AudioSystem::isStreamActive((audio_stream_type_t) stream, &state, inPastMs);
302     return state;
303 }
304 
305 static jboolean
android_media_AudioSystem_isStreamActiveRemotely(JNIEnv * env,jobject thiz,jint stream,jint inPastMs)306 android_media_AudioSystem_isStreamActiveRemotely(JNIEnv *env, jobject thiz, jint stream,
307         jint inPastMs)
308 {
309     bool state = false;
310     AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
311     return state;
312 }
313 
314 static jboolean
android_media_AudioSystem_isSourceActive(JNIEnv * env,jobject thiz,jint source)315 android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
316 {
317     bool state = false;
318     AudioSystem::isSourceActive((audio_source_t) source, &state);
319     return state;
320 }
321 
322 static jint
android_media_AudioSystem_newAudioSessionId(JNIEnv * env,jobject thiz)323 android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
324 {
325     return AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
326 }
327 
328 static jint
android_media_AudioSystem_setParameters(JNIEnv * env,jobject thiz,jstring keyValuePairs)329 android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
330 {
331     const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
332     String8 c_keyValuePairs8;
333     if (keyValuePairs) {
334         c_keyValuePairs8 = String8(
335             reinterpret_cast<const char16_t*>(c_keyValuePairs),
336             env->GetStringLength(keyValuePairs));
337         env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
338     }
339     int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
340     return (jint) status;
341 }
342 
343 static jstring
android_media_AudioSystem_getParameters(JNIEnv * env,jobject thiz,jstring keys)344 android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
345 {
346     const jchar* c_keys = env->GetStringCritical(keys, 0);
347     String8 c_keys8;
348     if (keys) {
349         c_keys8 = String8(reinterpret_cast<const char16_t*>(c_keys),
350                           env->GetStringLength(keys));
351         env->ReleaseStringCritical(keys, c_keys);
352     }
353     return env->NewStringUTF(AudioSystem::getParameters(c_keys8).string());
354 }
355 
356 static void
android_media_AudioSystem_error_callback(status_t err)357 android_media_AudioSystem_error_callback(status_t err)
358 {
359     JNIEnv *env = AndroidRuntime::getJNIEnv();
360     if (env == NULL) {
361         return;
362     }
363 
364     jclass clazz = env->FindClass(kClassPathName);
365 
366     env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
367                               "errorCallbackFromNative","(I)V"),
368                               check_AudioSystem_Command(err));
369 
370     env->DeleteLocalRef(clazz);
371 }
372 
373 static void
android_media_AudioSystem_dyn_policy_callback(int event,String8 regId,int val)374 android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val)
375 {
376     JNIEnv *env = AndroidRuntime::getJNIEnv();
377     if (env == NULL) {
378         return;
379     }
380 
381     jclass clazz = env->FindClass(kClassPathName);
382     const char* zechars = regId.string();
383     jstring zestring = env->NewStringUTF(zechars);
384 
385     env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative,
386             event, zestring, val);
387 
388     env->ReleaseStringUTFChars(zestring, zechars);
389     env->DeleteLocalRef(clazz);
390 }
391 
392 static void
android_media_AudioSystem_recording_callback(int event,audio_session_t session,int source,const audio_config_base_t * clientConfig,const audio_config_base_t * deviceConfig,audio_patch_handle_t patchHandle)393 android_media_AudioSystem_recording_callback(int event, audio_session_t session, int source,
394         const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
395         audio_patch_handle_t patchHandle)
396 {
397     JNIEnv *env = AndroidRuntime::getJNIEnv();
398     if (env == NULL) {
399         return;
400     }
401     if (clientConfig == NULL || deviceConfig == NULL) {
402         ALOGE("Unexpected null client/device configurations in recording callback");
403         return;
404     }
405 
406     // create an array for 2*3 integers to store the record configurations (client + device)
407     //                 plus 1 integer for the patch handle
408     const int REC_PARAM_SIZE = 7;
409     jintArray recParamArray = env->NewIntArray(REC_PARAM_SIZE);
410     if (recParamArray == NULL) {
411         ALOGE("recording callback: Couldn't allocate int array for configuration data");
412         return;
413     }
414     jint recParamData[REC_PARAM_SIZE];
415     recParamData[0] = (jint) audioFormatFromNative(clientConfig->format);
416     // FIXME this doesn't support index-based masks
417     recParamData[1] = (jint) inChannelMaskFromNative(clientConfig->channel_mask);
418     recParamData[2] = (jint) clientConfig->sample_rate;
419     recParamData[3] = (jint) audioFormatFromNative(deviceConfig->format);
420     // FIXME this doesn't support index-based masks
421     recParamData[4] = (jint) inChannelMaskFromNative(deviceConfig->channel_mask);
422     recParamData[5] = (jint) deviceConfig->sample_rate;
423     recParamData[6] = (jint) patchHandle;
424     env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData);
425 
426     // callback into java
427     jclass clazz = env->FindClass(kClassPathName);
428     env->CallStaticVoidMethod(clazz,
429             gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
430             event, session, source, recParamArray);
431     env->DeleteLocalRef(clazz);
432 
433     env->DeleteLocalRef(recParamArray);
434 }
435 
436 static jint
android_media_AudioSystem_setDeviceConnectionState(JNIEnv * env,jobject thiz,jint device,jint state,jstring device_address,jstring device_name)437 android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
438 {
439     const char *c_address = env->GetStringUTFChars(device_address, NULL);
440     const char *c_name = env->GetStringUTFChars(device_name, NULL);
441     int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
442                                           static_cast <audio_policy_dev_state_t>(state),
443                                           c_address, c_name));
444     env->ReleaseStringUTFChars(device_address, c_address);
445     env->ReleaseStringUTFChars(device_name, c_name);
446     return (jint) status;
447 }
448 
449 static jint
android_media_AudioSystem_getDeviceConnectionState(JNIEnv * env,jobject thiz,jint device,jstring device_address)450 android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
451 {
452     const char *c_address = env->GetStringUTFChars(device_address, NULL);
453     int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
454                                           c_address));
455     env->ReleaseStringUTFChars(device_address, c_address);
456     return (jint) state;
457 }
458 
459 static jint
android_media_AudioSystem_setPhoneState(JNIEnv * env,jobject thiz,jint state)460 android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
461 {
462     return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
463 }
464 
465 static jint
android_media_AudioSystem_setForceUse(JNIEnv * env,jobject thiz,jint usage,jint config)466 android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
467 {
468     return (jint) check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
469                                                            static_cast <audio_policy_forced_cfg_t>(config)));
470 }
471 
472 static jint
android_media_AudioSystem_getForceUse(JNIEnv * env,jobject thiz,jint usage)473 android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
474 {
475     return static_cast <jint>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
476 }
477 
478 static jint
android_media_AudioSystem_initStreamVolume(JNIEnv * env,jobject thiz,jint stream,jint indexMin,jint indexMax)479 android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
480 {
481     return (jint) check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
482                                                                    indexMin,
483                                                                    indexMax));
484 }
485 
486 static jint
android_media_AudioSystem_setStreamVolumeIndex(JNIEnv * env,jobject thiz,jint stream,jint index,jint device)487 android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
488                                                jobject thiz,
489                                                jint stream,
490                                                jint index,
491                                                jint device)
492 {
493     return (jint) check_AudioSystem_Command(
494             AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
495                                               index,
496                                               (audio_devices_t)device));
497 }
498 
499 static jint
android_media_AudioSystem_getStreamVolumeIndex(JNIEnv * env,jobject thiz,jint stream,jint device)500 android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env,
501                                                jobject thiz,
502                                                jint stream,
503                                                jint device)
504 {
505     int index;
506     if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
507                                           &index,
508                                           (audio_devices_t)device)
509             != NO_ERROR) {
510         index = -1;
511     }
512     return (jint) index;
513 }
514 
515 static jint
android_media_AudioSystem_setMasterVolume(JNIEnv * env,jobject thiz,jfloat value)516 android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
517 {
518     return (jint) check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
519 }
520 
521 static jfloat
android_media_AudioSystem_getMasterVolume(JNIEnv * env,jobject thiz)522 android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
523 {
524     float value;
525     if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
526         value = -1.0;
527     }
528     return value;
529 }
530 
531 static jint
android_media_AudioSystem_setMasterMute(JNIEnv * env,jobject thiz,jboolean mute)532 android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
533 {
534     return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
535 }
536 
537 static jboolean
android_media_AudioSystem_getMasterMute(JNIEnv * env,jobject thiz)538 android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
539 {
540     bool mute;
541     if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
542         mute = false;
543     }
544     return mute;
545 }
546 
547 static jint
android_media_AudioSystem_setMasterMono(JNIEnv * env,jobject thiz,jboolean mono)548 android_media_AudioSystem_setMasterMono(JNIEnv *env, jobject thiz, jboolean mono)
549 {
550     return (jint) check_AudioSystem_Command(AudioSystem::setMasterMono(mono));
551 }
552 
553 static jboolean
android_media_AudioSystem_getMasterMono(JNIEnv * env,jobject thiz)554 android_media_AudioSystem_getMasterMono(JNIEnv *env, jobject thiz)
555 {
556     bool mono;
557     if (AudioSystem::getMasterMono(&mono) != NO_ERROR) {
558         mono = false;
559     }
560     return mono;
561 }
562 
563 static jint
android_media_AudioSystem_getDevicesForStream(JNIEnv * env,jobject thiz,jint stream)564 android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
565 {
566     return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
567 }
568 
569 static jint
android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv * env,jobject clazz)570 android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
571 {
572     return (jint) AudioSystem::getPrimaryOutputSamplingRate();
573 }
574 
575 static jint
android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv * env,jobject clazz)576 android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
577 {
578     return (jint) AudioSystem::getPrimaryOutputFrameCount();
579 }
580 
581 static jint
android_media_AudioSystem_getOutputLatency(JNIEnv * env,jobject clazz,jint stream)582 android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
583 {
584     uint32_t afLatency;
585     if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
586             != NO_ERROR) {
587         afLatency = -1;
588     }
589     return (jint) afLatency;
590 }
591 
592 static jint
android_media_AudioSystem_setLowRamDevice(JNIEnv * env,jobject clazz,jboolean isLowRamDevice)593 android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
594 {
595     return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
596 }
597 
598 static jint
android_media_AudioSystem_checkAudioFlinger(JNIEnv * env,jobject clazz)599 android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
600 {
601     return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
602 }
603 
604 
useInChannelMask(audio_port_type_t type,audio_port_role_t role)605 static bool useInChannelMask(audio_port_type_t type, audio_port_role_t role)
606 {
607     return ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
608                 ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
609 }
610 
convertAudioGainConfigToNative(JNIEnv * env,struct audio_gain_config * nAudioGainConfig,const jobject jAudioGainConfig,bool useInMask)611 static void convertAudioGainConfigToNative(JNIEnv *env,
612                                                struct audio_gain_config *nAudioGainConfig,
613                                                const jobject jAudioGainConfig,
614                                                bool useInMask)
615 {
616     nAudioGainConfig->index = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mIndex);
617     nAudioGainConfig->mode = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
618     ALOGV("convertAudioGainConfigToNative got gain index %d", nAudioGainConfig->index);
619     jint jMask = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mChannelMask);
620     audio_channel_mask_t nMask;
621     if (useInMask) {
622         nMask = inChannelMaskToNative(jMask);
623         ALOGV("convertAudioGainConfigToNative IN mask java %x native %x", jMask, nMask);
624     } else {
625         nMask = outChannelMaskToNative(jMask);
626         ALOGV("convertAudioGainConfigToNative OUT mask java %x native %x", jMask, nMask);
627     }
628     nAudioGainConfig->channel_mask = nMask;
629     nAudioGainConfig->ramp_duration_ms = env->GetIntField(jAudioGainConfig,
630                                                        gAudioGainConfigFields.mRampDurationMs);
631     jintArray jValues = (jintArray)env->GetObjectField(jAudioGainConfig,
632                                                        gAudioGainConfigFields.mValues);
633     int *nValues = env->GetIntArrayElements(jValues, NULL);
634     size_t size = env->GetArrayLength(jValues);
635     memcpy(nAudioGainConfig->values, nValues, size * sizeof(int));
636     env->DeleteLocalRef(jValues);
637 }
638 
639 
convertAudioPortConfigToNative(JNIEnv * env,struct audio_port_config * nAudioPortConfig,const jobject jAudioPortConfig,bool useConfigMask)640 static jint convertAudioPortConfigToNative(JNIEnv *env,
641                                                struct audio_port_config *nAudioPortConfig,
642                                                const jobject jAudioPortConfig,
643                                                bool useConfigMask)
644 {
645     jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
646     jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
647     nAudioPortConfig->id = env->GetIntField(jHandle, gAudioHandleFields.mId);
648     nAudioPortConfig->role = (audio_port_role_t)env->GetIntField(jAudioPort,
649                                                                  gAudioPortFields.mRole);
650     if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
651         nAudioPortConfig->type = AUDIO_PORT_TYPE_DEVICE;
652     } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
653         nAudioPortConfig->type = AUDIO_PORT_TYPE_MIX;
654     } else {
655         env->DeleteLocalRef(jAudioPort);
656         env->DeleteLocalRef(jHandle);
657         return (jint)AUDIO_JAVA_ERROR;
658     }
659     ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
660           nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
661 
662     unsigned int configMask = 0;
663 
664     nAudioPortConfig->sample_rate = env->GetIntField(jAudioPortConfig,
665                                                      gAudioPortConfigFields.mSamplingRate);
666     if (nAudioPortConfig->sample_rate != 0) {
667         configMask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
668     }
669 
670     bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
671     audio_channel_mask_t nMask;
672     jint jMask = env->GetIntField(jAudioPortConfig,
673                                    gAudioPortConfigFields.mChannelMask);
674     if (useInMask) {
675         nMask = inChannelMaskToNative(jMask);
676         ALOGV("convertAudioPortConfigToNative IN mask java %x native %x", jMask, nMask);
677     } else {
678         nMask = outChannelMaskToNative(jMask);
679         ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
680     }
681     nAudioPortConfig->channel_mask = nMask;
682     if (nAudioPortConfig->channel_mask != AUDIO_CHANNEL_NONE) {
683         configMask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
684     }
685 
686     jint jFormat = env->GetIntField(jAudioPortConfig, gAudioPortConfigFields.mFormat);
687     audio_format_t nFormat = audioFormatToNative(jFormat);
688     ALOGV("convertAudioPortConfigToNative format %d native %d", jFormat, nFormat);
689     nAudioPortConfig->format = nFormat;
690     if (nAudioPortConfig->format != AUDIO_FORMAT_DEFAULT &&
691             nAudioPortConfig->format != AUDIO_FORMAT_INVALID) {
692         configMask |= AUDIO_PORT_CONFIG_FORMAT;
693     }
694 
695     jobject jGain = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mGain);
696     if (jGain != NULL) {
697         convertAudioGainConfigToNative(env, &nAudioPortConfig->gain, jGain, useInMask);
698         env->DeleteLocalRef(jGain);
699         configMask |= AUDIO_PORT_CONFIG_GAIN;
700     } else {
701         ALOGV("convertAudioPortConfigToNative no gain");
702         nAudioPortConfig->gain.index = -1;
703     }
704     if (useConfigMask) {
705         nAudioPortConfig->config_mask = env->GetIntField(jAudioPortConfig,
706                                                          gAudioPortConfigFields.mConfigMask);
707     } else {
708         nAudioPortConfig->config_mask = configMask;
709     }
710     env->DeleteLocalRef(jAudioPort);
711     env->DeleteLocalRef(jHandle);
712     return (jint)AUDIO_JAVA_SUCCESS;
713 }
714 
convertAudioPortConfigFromNative(JNIEnv * env,jobject jAudioPort,jobject * jAudioPortConfig,const struct audio_port_config * nAudioPortConfig)715 static jint convertAudioPortConfigFromNative(JNIEnv *env,
716                                                  jobject jAudioPort,
717                                                  jobject *jAudioPortConfig,
718                                                  const struct audio_port_config *nAudioPortConfig)
719 {
720     jint jStatus = AUDIO_JAVA_SUCCESS;
721     jobject jAudioGainConfig = NULL;
722     jobject jAudioGain = NULL;
723     jintArray jGainValues;
724     bool audioportCreated = false;
725 
726     ALOGV("convertAudioPortConfigFromNative jAudioPort %p", jAudioPort);
727 
728     if (jAudioPort == NULL) {
729         jobject jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
730                                                  nAudioPortConfig->id);
731 
732         ALOGV("convertAudioPortConfigFromNative handle %d is a %s", nAudioPortConfig->id,
733               nAudioPortConfig->type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix");
734 
735         if (jHandle == NULL) {
736             return (jint)AUDIO_JAVA_ERROR;
737         }
738         // create dummy port and port config objects with just the correct handle
739         // and configuration data. The actual AudioPortConfig objects will be
740         // constructed by java code with correct class type (device, mix etc...)
741         // and reference to AudioPort instance in this client
742         jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
743                                            jHandle, // handle
744                                            0,       // role
745                                            NULL,    // name
746                                            NULL,    // samplingRates
747                                            NULL,    // channelMasks
748                                            NULL,    // channelIndexMasks
749                                            NULL,    // formats
750                                            NULL);   // gains
751         env->DeleteLocalRef(jHandle);
752         if (jAudioPort == NULL) {
753             return (jint)AUDIO_JAVA_ERROR;
754         }
755         ALOGV("convertAudioPortConfigFromNative jAudioPort created for handle %d",
756               nAudioPortConfig->id);
757 
758         audioportCreated = true;
759     }
760 
761     bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
762 
763     audio_channel_mask_t nMask;
764     jint jMask;
765 
766     int gainIndex = nAudioPortConfig->gain.index;
767     if (gainIndex >= 0) {
768         ALOGV("convertAudioPortConfigFromNative gain found with index %d mode %x",
769               gainIndex, nAudioPortConfig->gain.mode);
770         if (audioportCreated) {
771             ALOGV("convertAudioPortConfigFromNative creating gain");
772             jAudioGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
773                                                gainIndex,
774                                                0,
775                                                0,
776                                                0,
777                                                0,
778                                                0,
779                                                0,
780                                                0,
781                                                0);
782             if (jAudioGain == NULL) {
783                 ALOGV("convertAudioPortConfigFromNative creating gain FAILED");
784                 jStatus = (jint)AUDIO_JAVA_ERROR;
785                 goto exit;
786             }
787         } else {
788             ALOGV("convertAudioPortConfigFromNative reading gain from port");
789             jobjectArray jGains = (jobjectArray)env->GetObjectField(jAudioPort,
790                                                                       gAudioPortFields.mGains);
791             if (jGains == NULL) {
792                 ALOGV("convertAudioPortConfigFromNative could not get gains from port");
793                 jStatus = (jint)AUDIO_JAVA_ERROR;
794                 goto exit;
795             }
796             jAudioGain = env->GetObjectArrayElement(jGains, gainIndex);
797             env->DeleteLocalRef(jGains);
798             if (jAudioGain == NULL) {
799                 ALOGV("convertAudioPortConfigFromNative could not get gain at index %d", gainIndex);
800                 jStatus = (jint)AUDIO_JAVA_ERROR;
801                 goto exit;
802             }
803         }
804         int numValues;
805         if (useInMask) {
806             numValues = audio_channel_count_from_in_mask(nAudioPortConfig->gain.channel_mask);
807         } else {
808             numValues = audio_channel_count_from_out_mask(nAudioPortConfig->gain.channel_mask);
809         }
810         jGainValues = env->NewIntArray(numValues);
811         if (jGainValues == NULL) {
812             ALOGV("convertAudioPortConfigFromNative could not create gain values %d", numValues);
813             jStatus = (jint)AUDIO_JAVA_ERROR;
814             goto exit;
815         }
816         env->SetIntArrayRegion(jGainValues, 0, numValues,
817                                nAudioPortConfig->gain.values);
818 
819         nMask = nAudioPortConfig->gain.channel_mask;
820         if (useInMask) {
821             jMask = inChannelMaskFromNative(nMask);
822             ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
823         } else {
824             jMask = outChannelMaskFromNative(nMask);
825             ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
826         }
827 
828         jAudioGainConfig = env->NewObject(gAudioGainConfigClass,
829                                         gAudioGainConfigCstor,
830                                         gainIndex,
831                                         jAudioGain,
832                                         nAudioPortConfig->gain.mode,
833                                         jMask,
834                                         jGainValues,
835                                         nAudioPortConfig->gain.ramp_duration_ms);
836         env->DeleteLocalRef(jGainValues);
837         if (jAudioGainConfig == NULL) {
838             ALOGV("convertAudioPortConfigFromNative could not create gain config");
839             jStatus = (jint)AUDIO_JAVA_ERROR;
840             goto exit;
841         }
842     }
843     jclass clazz;
844     jmethodID methodID;
845     if (audioportCreated) {
846         clazz = gAudioPortConfigClass;
847         methodID = gAudioPortConfigCstor;
848         ALOGV("convertAudioPortConfigFromNative building a generic port config");
849     } else {
850         if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
851             clazz = gAudioDevicePortConfigClass;
852             methodID = gAudioDevicePortConfigCstor;
853             ALOGV("convertAudioPortConfigFromNative building a device config");
854         } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
855             clazz = gAudioMixPortConfigClass;
856             methodID = gAudioMixPortConfigCstor;
857             ALOGV("convertAudioPortConfigFromNative building a mix config");
858         } else {
859             jStatus = (jint)AUDIO_JAVA_ERROR;
860             goto exit;
861         }
862     }
863     nMask = nAudioPortConfig->channel_mask;
864     if (useInMask) {
865         jMask = inChannelMaskFromNative(nMask);
866         ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
867     } else {
868         jMask = outChannelMaskFromNative(nMask);
869         ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
870     }
871 
872     *jAudioPortConfig = env->NewObject(clazz, methodID,
873                                        jAudioPort,
874                                        nAudioPortConfig->sample_rate,
875                                        jMask,
876                                        audioFormatFromNative(nAudioPortConfig->format),
877                                        jAudioGainConfig);
878     if (*jAudioPortConfig == NULL) {
879         ALOGV("convertAudioPortConfigFromNative could not create new port config");
880         jStatus = (jint)AUDIO_JAVA_ERROR;
881     } else {
882         ALOGV("convertAudioPortConfigFromNative OK");
883     }
884 
885 exit:
886     if (audioportCreated) {
887         env->DeleteLocalRef(jAudioPort);
888         if (jAudioGain != NULL) {
889             env->DeleteLocalRef(jAudioGain);
890         }
891     }
892     if (jAudioGainConfig != NULL) {
893         env->DeleteLocalRef(jAudioGainConfig);
894     }
895     return jStatus;
896 }
897 
hasFormat(int * formats,size_t size,int format)898 static bool hasFormat(int* formats, size_t size, int format) {
899     for (size_t index = 0; index < size; index++) {
900         if (formats[index] == format) {
901             return true; // found
902         }
903     }
904     return false; // not found
905 }
906 
907 // TODO: pull out to separate file
908 template <typename T, size_t N>
array_size(const T (&)[N])909 static constexpr size_t array_size(const T (&)[N]) {
910     return N;
911 }
912 
convertAudioPortFromNative(JNIEnv * env,jobject * jAudioPort,const struct audio_port * nAudioPort)913 static jint convertAudioPortFromNative(JNIEnv *env,
914                                            jobject *jAudioPort, const struct audio_port *nAudioPort)
915 {
916     jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
917     jintArray jSamplingRates = NULL;
918     jintArray jChannelMasks = NULL;
919     jintArray jChannelIndexMasks = NULL;
920     int* cFormats = NULL;
921     jintArray jFormats = NULL;
922     jobjectArray jGains = NULL;
923     jobject jHandle = NULL;
924     jstring jDeviceName = NULL;
925     bool useInMask;
926     size_t numPositionMasks = 0;
927     size_t numIndexMasks = 0;
928     size_t numUniqueFormats = 0;
929 
930     ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
931         nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
932 
933     // Verify audio port array count info.
934     if (nAudioPort->num_sample_rates > array_size(nAudioPort->sample_rates)
935             || nAudioPort->num_channel_masks > array_size(nAudioPort->channel_masks)
936             || nAudioPort->num_formats > array_size(nAudioPort->formats)
937             || nAudioPort->num_gains > array_size(nAudioPort->gains)) {
938 
939         std::stringstream ss;
940         ss << "convertAudioPortFromNative array count out of bounds:"
941                 << " num_sample_rates " << nAudioPort->num_sample_rates
942                 << " num_channel_masks " << nAudioPort->num_channel_masks
943                 << " num_formats " << nAudioPort->num_formats
944                 << " num_gains " << nAudioPort->num_gains
945                 ;
946         std::string s = ss.str();
947 
948         // Prefer to log through Java wtf instead of native ALOGE.
949         ScopedLocalRef<jclass> jLogClass(env, env->FindClass("android/util/Log"));
950         jmethodID jWtfId = (jLogClass.get() == nullptr)
951                 ? nullptr
952                 : env->GetStaticMethodID(jLogClass.get(), "wtf",
953                         "(Ljava/lang/String;Ljava/lang/String;)I");
954         if (jWtfId != nullptr) {
955             ScopedLocalRef<jstring> jMessage(env, env->NewStringUTF(s.c_str()));
956             ScopedLocalRef<jstring> jTag(env, env->NewStringUTF(LOG_TAG));
957             (void)env->CallStaticIntMethod(jLogClass.get(), jWtfId, jTag.get(), jMessage.get());
958         } else {
959             ALOGE("%s", s.c_str());
960         }
961         jStatus = (jint)AUDIO_JAVA_ERROR;
962         goto exit;
963     }
964 
965     jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
966     if (jSamplingRates == NULL) {
967         jStatus = (jint)AUDIO_JAVA_ERROR;
968         goto exit;
969     }
970     if (nAudioPort->num_sample_rates) {
971         env->SetIntArrayRegion(jSamplingRates, 0, nAudioPort->num_sample_rates,
972                                (jint *)nAudioPort->sample_rates);
973     }
974 
975     // count up how many masks are positional and indexed
976     for(size_t index = 0; index < nAudioPort->num_channel_masks; index++) {
977         const audio_channel_mask_t mask = nAudioPort->channel_masks[index];
978         if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
979             numIndexMasks++;
980         } else {
981             numPositionMasks++;
982         }
983     }
984 
985     jChannelMasks = env->NewIntArray(numPositionMasks);
986     if (jChannelMasks == NULL) {
987         jStatus = (jint)AUDIO_JAVA_ERROR;
988         goto exit;
989     }
990     jChannelIndexMasks = env->NewIntArray(numIndexMasks);
991     if (jChannelIndexMasks == NULL) {
992         jStatus = (jint)AUDIO_JAVA_ERROR;
993         goto exit;
994     }
995     useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
996 
997     // put the masks in the output arrays
998     for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0;
999          maskIndex < nAudioPort->num_channel_masks; maskIndex++) {
1000         const audio_channel_mask_t mask = nAudioPort->channel_masks[maskIndex];
1001         if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
1002             jint jMask = audio_channel_mask_get_bits(mask);
1003             env->SetIntArrayRegion(jChannelIndexMasks, indexedMaskIndex++, 1, &jMask);
1004         } else {
1005             jint jMask = useInMask ? inChannelMaskFromNative(mask)
1006                                    : outChannelMaskFromNative(mask);
1007             env->SetIntArrayRegion(jChannelMasks, posMaskIndex++, 1, &jMask);
1008         }
1009     }
1010 
1011     // formats
1012     if (nAudioPort->num_formats != 0) {
1013         cFormats = new int[nAudioPort->num_formats];
1014         for (size_t index = 0; index < nAudioPort->num_formats; index++) {
1015             int format = audioFormatFromNative(nAudioPort->formats[index]);
1016             if (!hasFormat(cFormats, numUniqueFormats, format)) {
1017                 cFormats[numUniqueFormats++] = format;
1018             }
1019         }
1020     }
1021     jFormats = env->NewIntArray(numUniqueFormats);
1022     if (jFormats == NULL) {
1023         jStatus = (jint)AUDIO_JAVA_ERROR;
1024         goto exit;
1025     }
1026     if (numUniqueFormats != 0) {
1027         env->SetIntArrayRegion(jFormats, 0, numUniqueFormats, cFormats);
1028     }
1029 
1030     // gains
1031     jGains = env->NewObjectArray(nAudioPort->num_gains,
1032                                           gAudioGainClass, NULL);
1033     if (jGains == NULL) {
1034         jStatus = (jint)AUDIO_JAVA_ERROR;
1035         goto exit;
1036     }
1037 
1038     for (size_t j = 0; j < nAudioPort->num_gains; j++) {
1039         audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
1040         jint jMask;
1041         if (useInMask) {
1042             jMask = inChannelMaskFromNative(nMask);
1043             ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
1044         } else {
1045             jMask = outChannelMaskFromNative(nMask);
1046             ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
1047         }
1048 
1049         jobject jGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
1050                                                  j,
1051                                                  nAudioPort->gains[j].mode,
1052                                                  jMask,
1053                                                  nAudioPort->gains[j].min_value,
1054                                                  nAudioPort->gains[j].max_value,
1055                                                  nAudioPort->gains[j].default_value,
1056                                                  nAudioPort->gains[j].step_value,
1057                                                  nAudioPort->gains[j].min_ramp_ms,
1058                                                  nAudioPort->gains[j].max_ramp_ms);
1059         if (jGain == NULL) {
1060             jStatus = (jint)AUDIO_JAVA_ERROR;
1061             goto exit;
1062         }
1063         env->SetObjectArrayElement(jGains, j, jGain);
1064         env->DeleteLocalRef(jGain);
1065     }
1066 
1067     jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1068                                              nAudioPort->id);
1069     if (jHandle == NULL) {
1070         jStatus = (jint)AUDIO_JAVA_ERROR;
1071         goto exit;
1072     }
1073 
1074     jDeviceName = env->NewStringUTF(nAudioPort->name);
1075 
1076     if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
1077         ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
1078         jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
1079         *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
1080                                      jHandle, jDeviceName,
1081                                      jSamplingRates, jChannelMasks, jChannelIndexMasks,
1082                                      jFormats, jGains,
1083                                      nAudioPort->ext.device.type, jAddress);
1084         env->DeleteLocalRef(jAddress);
1085     } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
1086         ALOGV("convertAudioPortFromNative is a mix");
1087         *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
1088                                      jHandle, nAudioPort->ext.mix.handle,
1089                                      nAudioPort->role, jDeviceName,
1090                                      jSamplingRates, jChannelMasks, jChannelIndexMasks,
1091                                      jFormats, jGains);
1092     } else {
1093         ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
1094         jStatus = (jint)AUDIO_JAVA_ERROR;
1095         goto exit;
1096     }
1097     if (*jAudioPort == NULL) {
1098         jStatus = (jint)AUDIO_JAVA_ERROR;
1099         goto exit;
1100     }
1101 
1102     jobject jAudioPortConfig;
1103     jStatus = convertAudioPortConfigFromNative(env,
1104                                                        *jAudioPort,
1105                                                        &jAudioPortConfig,
1106                                                        &nAudioPort->active_config);
1107     if (jStatus != AUDIO_JAVA_SUCCESS) {
1108         goto exit;
1109     }
1110 
1111     env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
1112 
1113 exit:
1114     if (jDeviceName != NULL) {
1115         env->DeleteLocalRef(jDeviceName);
1116     }
1117     if (jSamplingRates != NULL) {
1118         env->DeleteLocalRef(jSamplingRates);
1119     }
1120     if (jChannelMasks != NULL) {
1121         env->DeleteLocalRef(jChannelMasks);
1122     }
1123     if (jChannelIndexMasks != NULL) {
1124         env->DeleteLocalRef(jChannelIndexMasks);
1125     }
1126     if (cFormats != NULL) {
1127         delete[] cFormats;
1128     }
1129     if (jFormats != NULL) {
1130         env->DeleteLocalRef(jFormats);
1131     }
1132     if (jGains != NULL) {
1133         env->DeleteLocalRef(jGains);
1134     }
1135     if (jHandle != NULL) {
1136         env->DeleteLocalRef(jHandle);
1137     }
1138 
1139     return jStatus;
1140 }
1141 
1142 
1143 static jint
android_media_AudioSystem_listAudioPorts(JNIEnv * env,jobject clazz,jobject jPorts,jintArray jGeneration)1144 android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
1145                                          jobject jPorts, jintArray jGeneration)
1146 {
1147     ALOGV("listAudioPorts");
1148 
1149     if (jPorts == NULL) {
1150         ALOGE("listAudioPorts NULL AudioPort ArrayList");
1151         return (jint)AUDIO_JAVA_BAD_VALUE;
1152     }
1153     if (!env->IsInstanceOf(jPorts, gArrayListClass)) {
1154         ALOGE("listAudioPorts not an arraylist");
1155         return (jint)AUDIO_JAVA_BAD_VALUE;
1156     }
1157 
1158     if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
1159         return (jint)AUDIO_JAVA_BAD_VALUE;
1160     }
1161 
1162     status_t status;
1163     unsigned int generation1;
1164     unsigned int generation;
1165     unsigned int numPorts;
1166     jint *nGeneration;
1167     struct audio_port *nPorts = NULL;
1168     int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
1169     jint jStatus;
1170 
1171     // get the port count and all the ports until they both return the same generation
1172     do {
1173         if (attempts-- < 0) {
1174             status = TIMED_OUT;
1175             break;
1176         }
1177 
1178         numPorts = 0;
1179         status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
1180                                              AUDIO_PORT_TYPE_NONE,
1181                                                       &numPorts,
1182                                                       NULL,
1183                                                       &generation1);
1184         if (status != NO_ERROR) {
1185             ALOGE_IF(status != NO_ERROR, "AudioSystem::listAudioPorts error %d", status);
1186             break;
1187         }
1188         if (numPorts == 0) {
1189             jStatus = (jint)AUDIO_JAVA_SUCCESS;
1190             goto exit;
1191         }
1192         nPorts = (struct audio_port *)realloc(nPorts, numPorts * sizeof(struct audio_port));
1193 
1194         status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
1195                                              AUDIO_PORT_TYPE_NONE,
1196                                                       &numPorts,
1197                                                       nPorts,
1198                                                       &generation);
1199         ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
1200               numPorts, generation, generation1);
1201     } while (generation1 != generation && status == NO_ERROR);
1202 
1203     jStatus = nativeToJavaStatus(status);
1204     if (jStatus != AUDIO_JAVA_SUCCESS) {
1205         goto exit;
1206     }
1207 
1208     for (size_t i = 0; i < numPorts; i++) {
1209         jobject jAudioPort;
1210         jStatus = convertAudioPortFromNative(env, &jAudioPort, &nPorts[i]);
1211         if (jStatus != AUDIO_JAVA_SUCCESS) {
1212             goto exit;
1213         }
1214         env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort);
1215     }
1216 
1217 exit:
1218     nGeneration = env->GetIntArrayElements(jGeneration, NULL);
1219     if (nGeneration == NULL) {
1220         jStatus = (jint)AUDIO_JAVA_ERROR;
1221     } else {
1222         nGeneration[0] = generation1;
1223         env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
1224     }
1225     free(nPorts);
1226     return jStatus;
1227 }
1228 
1229 static int
android_media_AudioSystem_createAudioPatch(JNIEnv * env,jobject clazz,jobjectArray jPatches,jobjectArray jSources,jobjectArray jSinks)1230 android_media_AudioSystem_createAudioPatch(JNIEnv *env, jobject clazz,
1231                                  jobjectArray jPatches, jobjectArray jSources, jobjectArray jSinks)
1232 {
1233     status_t status;
1234     jint jStatus;
1235 
1236     ALOGV("createAudioPatch");
1237     if (jPatches == NULL || jSources == NULL || jSinks == NULL) {
1238         return (jint)AUDIO_JAVA_BAD_VALUE;
1239     }
1240 
1241     if (env->GetArrayLength(jPatches) != 1) {
1242         return (jint)AUDIO_JAVA_BAD_VALUE;
1243     }
1244     jint numSources = env->GetArrayLength(jSources);
1245     if (numSources == 0 || numSources > AUDIO_PATCH_PORTS_MAX) {
1246         return (jint)AUDIO_JAVA_BAD_VALUE;
1247     }
1248 
1249     jint numSinks = env->GetArrayLength(jSinks);
1250     if (numSinks == 0 || numSinks > AUDIO_PATCH_PORTS_MAX) {
1251         return (jint)AUDIO_JAVA_BAD_VALUE;
1252     }
1253 
1254     audio_patch_handle_t handle = (audio_patch_handle_t)0;
1255     jobject jPatch = env->GetObjectArrayElement(jPatches, 0);
1256     jobject jPatchHandle = NULL;
1257     if (jPatch != NULL) {
1258         if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
1259             return (jint)AUDIO_JAVA_BAD_VALUE;
1260         }
1261         jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
1262         handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
1263     }
1264 
1265     struct audio_patch nPatch;
1266 
1267     nPatch.id = handle;
1268     nPatch.num_sources = 0;
1269     nPatch.num_sinks = 0;
1270     jobject jSource = NULL;
1271     jobject jSink = NULL;
1272 
1273     for (jint i = 0; i < numSources; i++) {
1274         jSource = env->GetObjectArrayElement(jSources, i);
1275         if (!env->IsInstanceOf(jSource, gAudioPortConfigClass)) {
1276             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
1277             goto exit;
1278         }
1279         jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource, false);
1280         env->DeleteLocalRef(jSource);
1281         jSource = NULL;
1282         if (jStatus != AUDIO_JAVA_SUCCESS) {
1283             goto exit;
1284         }
1285         nPatch.num_sources++;
1286     }
1287 
1288     for (jint i = 0; i < numSinks; i++) {
1289         jSink = env->GetObjectArrayElement(jSinks, i);
1290         if (!env->IsInstanceOf(jSink, gAudioPortConfigClass)) {
1291             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
1292             goto exit;
1293         }
1294         jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink, false);
1295         env->DeleteLocalRef(jSink);
1296         jSink = NULL;
1297         if (jStatus != AUDIO_JAVA_SUCCESS) {
1298             goto exit;
1299         }
1300         nPatch.num_sinks++;
1301     }
1302 
1303     ALOGV("AudioSystem::createAudioPatch");
1304     status = AudioSystem::createAudioPatch(&nPatch, &handle);
1305     ALOGV("AudioSystem::createAudioPatch() returned %d hande %d", status, handle);
1306 
1307     jStatus = nativeToJavaStatus(status);
1308     if (jStatus != AUDIO_JAVA_SUCCESS) {
1309         goto exit;
1310     }
1311 
1312     if (jPatchHandle == NULL) {
1313         jPatchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1314                                            handle);
1315         if (jPatchHandle == NULL) {
1316             jStatus = (jint)AUDIO_JAVA_ERROR;
1317             goto exit;
1318         }
1319         jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle, jSources, jSinks);
1320         if (jPatch == NULL) {
1321             jStatus = (jint)AUDIO_JAVA_ERROR;
1322             goto exit;
1323         }
1324         env->SetObjectArrayElement(jPatches, 0, jPatch);
1325     } else {
1326         env->SetIntField(jPatchHandle, gAudioHandleFields.mId, handle);
1327     }
1328 
1329 exit:
1330     if (jPatchHandle != NULL) {
1331         env->DeleteLocalRef(jPatchHandle);
1332     }
1333     if (jPatch != NULL) {
1334         env->DeleteLocalRef(jPatch);
1335     }
1336     if (jSource != NULL) {
1337         env->DeleteLocalRef(jSource);
1338     }
1339     if (jSink != NULL) {
1340         env->DeleteLocalRef(jSink);
1341     }
1342     return jStatus;
1343 }
1344 
1345 static jint
android_media_AudioSystem_releaseAudioPatch(JNIEnv * env,jobject clazz,jobject jPatch)1346 android_media_AudioSystem_releaseAudioPatch(JNIEnv *env, jobject clazz,
1347                                                jobject jPatch)
1348 {
1349     ALOGV("releaseAudioPatch");
1350     if (jPatch == NULL) {
1351         return (jint)AUDIO_JAVA_BAD_VALUE;
1352     }
1353 
1354     audio_patch_handle_t handle = (audio_patch_handle_t)0;
1355     jobject jPatchHandle = NULL;
1356     if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
1357         return (jint)AUDIO_JAVA_BAD_VALUE;
1358     }
1359     jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
1360     handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
1361     env->DeleteLocalRef(jPatchHandle);
1362 
1363     ALOGV("AudioSystem::releaseAudioPatch");
1364     status_t status = AudioSystem::releaseAudioPatch(handle);
1365     ALOGV("AudioSystem::releaseAudioPatch() returned %d", status);
1366     jint jStatus = nativeToJavaStatus(status);
1367     return jStatus;
1368 }
1369 
1370 static jint
android_media_AudioSystem_listAudioPatches(JNIEnv * env,jobject clazz,jobject jPatches,jintArray jGeneration)1371 android_media_AudioSystem_listAudioPatches(JNIEnv *env, jobject clazz,
1372                                            jobject jPatches, jintArray jGeneration)
1373 {
1374     ALOGV("listAudioPatches");
1375     if (jPatches == NULL) {
1376         ALOGE("listAudioPatches NULL AudioPatch ArrayList");
1377         return (jint)AUDIO_JAVA_BAD_VALUE;
1378     }
1379     if (!env->IsInstanceOf(jPatches, gArrayListClass)) {
1380         ALOGE("listAudioPatches not an arraylist");
1381         return (jint)AUDIO_JAVA_BAD_VALUE;
1382     }
1383 
1384     if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
1385         return (jint)AUDIO_JAVA_BAD_VALUE;
1386     }
1387 
1388     status_t status;
1389     unsigned int generation1;
1390     unsigned int generation;
1391     unsigned int numPatches;
1392     jint *nGeneration;
1393     struct audio_patch *nPatches = NULL;
1394     jobjectArray jSources = NULL;
1395     jobject jSource = NULL;
1396     jobjectArray jSinks = NULL;
1397     jobject jSink = NULL;
1398     jobject jPatch = NULL;
1399     int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
1400     jint jStatus;
1401 
1402     // get the patch count and all the patches until they both return the same generation
1403     do {
1404         if (attempts-- < 0) {
1405             status = TIMED_OUT;
1406             break;
1407         }
1408 
1409         numPatches = 0;
1410         status = AudioSystem::listAudioPatches(&numPatches,
1411                                                NULL,
1412                                                &generation1);
1413         if (status != NO_ERROR) {
1414             ALOGE_IF(status != NO_ERROR, "listAudioPatches AudioSystem::listAudioPatches error %d",
1415                                       status);
1416             break;
1417         }
1418         if (numPatches == 0) {
1419             jStatus = (jint)AUDIO_JAVA_SUCCESS;
1420             goto exit;
1421         }
1422 
1423         nPatches = (struct audio_patch *)realloc(nPatches, numPatches * sizeof(struct audio_patch));
1424 
1425         status = AudioSystem::listAudioPatches(&numPatches,
1426                                                nPatches,
1427                                                &generation);
1428         ALOGV("listAudioPatches AudioSystem::listAudioPatches numPatches %d generation %d generation1 %d",
1429               numPatches, generation, generation1);
1430 
1431     } while (generation1 != generation && status == NO_ERROR);
1432 
1433     jStatus = nativeToJavaStatus(status);
1434     if (jStatus != AUDIO_JAVA_SUCCESS) {
1435         goto exit;
1436     }
1437 
1438     for (size_t i = 0; i < numPatches; i++) {
1439         jobject patchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1440                                                  nPatches[i].id);
1441         if (patchHandle == NULL) {
1442             jStatus = AUDIO_JAVA_ERROR;
1443             goto exit;
1444         }
1445         ALOGV("listAudioPatches patch %zu num_sources %d num_sinks %d",
1446               i, nPatches[i].num_sources, nPatches[i].num_sinks);
1447 
1448         env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
1449 
1450         // load sources
1451         jSources = env->NewObjectArray(nPatches[i].num_sources,
1452                                        gAudioPortConfigClass, NULL);
1453         if (jSources == NULL) {
1454             jStatus = AUDIO_JAVA_ERROR;
1455             goto exit;
1456         }
1457 
1458         for (size_t j = 0; j < nPatches[i].num_sources; j++) {
1459             jStatus = convertAudioPortConfigFromNative(env,
1460                                                       NULL,
1461                                                       &jSource,
1462                                                       &nPatches[i].sources[j]);
1463             if (jStatus != AUDIO_JAVA_SUCCESS) {
1464                 goto exit;
1465             }
1466             env->SetObjectArrayElement(jSources, j, jSource);
1467             env->DeleteLocalRef(jSource);
1468             jSource = NULL;
1469             ALOGV("listAudioPatches patch %zu source %zu is a %s handle %d",
1470                   i, j,
1471                   nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
1472                   nPatches[i].sources[j].id);
1473         }
1474         // load sinks
1475         jSinks = env->NewObjectArray(nPatches[i].num_sinks,
1476                                      gAudioPortConfigClass, NULL);
1477         if (jSinks == NULL) {
1478             jStatus = AUDIO_JAVA_ERROR;
1479             goto exit;
1480         }
1481 
1482         for (size_t j = 0; j < nPatches[i].num_sinks; j++) {
1483             jStatus = convertAudioPortConfigFromNative(env,
1484                                                       NULL,
1485                                                       &jSink,
1486                                                       &nPatches[i].sinks[j]);
1487 
1488             if (jStatus != AUDIO_JAVA_SUCCESS) {
1489                 goto exit;
1490             }
1491             env->SetObjectArrayElement(jSinks, j, jSink);
1492             env->DeleteLocalRef(jSink);
1493             jSink = NULL;
1494             ALOGV("listAudioPatches patch %zu sink %zu is a %s handle %d",
1495                   i, j,
1496                   nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
1497                   nPatches[i].sinks[j].id);
1498         }
1499 
1500         jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor,
1501                                        patchHandle, jSources, jSinks);
1502         env->DeleteLocalRef(jSources);
1503         jSources = NULL;
1504         env->DeleteLocalRef(jSinks);
1505         jSinks = NULL;
1506         if (jPatch == NULL) {
1507             jStatus = AUDIO_JAVA_ERROR;
1508             goto exit;
1509         }
1510         env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch);
1511         env->DeleteLocalRef(jPatch);
1512         jPatch = NULL;
1513     }
1514 
1515 exit:
1516 
1517     nGeneration = env->GetIntArrayElements(jGeneration, NULL);
1518     if (nGeneration == NULL) {
1519         jStatus = AUDIO_JAVA_ERROR;
1520     } else {
1521         nGeneration[0] = generation1;
1522         env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
1523     }
1524 
1525     if (jSources != NULL) {
1526         env->DeleteLocalRef(jSources);
1527     }
1528     if (jSource != NULL) {
1529         env->DeleteLocalRef(jSource);
1530     }
1531     if (jSinks != NULL) {
1532         env->DeleteLocalRef(jSinks);
1533     }
1534     if (jSink != NULL) {
1535         env->DeleteLocalRef(jSink);
1536     }
1537     if (jPatch != NULL) {
1538         env->DeleteLocalRef(jPatch);
1539     }
1540     free(nPatches);
1541     return jStatus;
1542 }
1543 
1544 static jint
android_media_AudioSystem_setAudioPortConfig(JNIEnv * env,jobject clazz,jobject jAudioPortConfig)1545 android_media_AudioSystem_setAudioPortConfig(JNIEnv *env, jobject clazz,
1546                                  jobject jAudioPortConfig)
1547 {
1548     ALOGV("setAudioPortConfig");
1549     if (jAudioPortConfig == NULL) {
1550         return AUDIO_JAVA_BAD_VALUE;
1551     }
1552     if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
1553         return AUDIO_JAVA_BAD_VALUE;
1554     }
1555     struct audio_port_config nAudioPortConfig;
1556     jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig, true);
1557     if (jStatus != AUDIO_JAVA_SUCCESS) {
1558         return jStatus;
1559     }
1560     status_t status = AudioSystem::setAudioPortConfig(&nAudioPortConfig);
1561     ALOGV("AudioSystem::setAudioPortConfig() returned %d", status);
1562     jStatus = nativeToJavaStatus(status);
1563     return jStatus;
1564 }
1565 
1566 static void
android_media_AudioSystem_eventHandlerSetup(JNIEnv * env,jobject thiz,jobject weak_this)1567 android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this)
1568 {
1569     ALOGV("eventHandlerSetup");
1570 
1571     sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
1572 
1573     if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) {
1574         setJniCallback(env, thiz, callback);
1575     }
1576 }
1577 
1578 static void
android_media_AudioSystem_eventHandlerFinalize(JNIEnv * env,jobject thiz)1579 android_media_AudioSystem_eventHandlerFinalize(JNIEnv *env, jobject thiz)
1580 {
1581     ALOGV("eventHandlerFinalize");
1582 
1583     sp<JNIAudioPortCallback> callback = setJniCallback(env, thiz, 0);
1584 
1585     if (callback != 0) {
1586         AudioSystem::removeAudioPortCallback(callback);
1587     }
1588 }
1589 
1590 static jint
android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv * env,jobject thiz,jint sessionId)1591 android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
1592 {
1593     return (jint) AudioSystem::getAudioHwSyncForSession((audio_session_t) sessionId);
1594 }
1595 
1596 static void
android_media_AudioSystem_registerDynPolicyCallback(JNIEnv * env,jobject thiz)1597 android_media_AudioSystem_registerDynPolicyCallback(JNIEnv *env, jobject thiz)
1598 {
1599     AudioSystem::setDynPolicyCallback(android_media_AudioSystem_dyn_policy_callback);
1600 }
1601 
1602 static void
android_media_AudioSystem_registerRecordingCallback(JNIEnv * env,jobject thiz)1603 android_media_AudioSystem_registerRecordingCallback(JNIEnv *env, jobject thiz)
1604 {
1605     AudioSystem::setRecordConfigCallback(android_media_AudioSystem_recording_callback);
1606 }
1607 
1608 
convertAudioMixToNative(JNIEnv * env,AudioMix * nAudioMix,const jobject jAudioMix)1609 static jint convertAudioMixToNative(JNIEnv *env,
1610                                     AudioMix *nAudioMix,
1611                                     const jobject jAudioMix)
1612 {
1613     nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
1614     nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
1615     nAudioMix->mDeviceType = (audio_devices_t)
1616             env->GetIntField(jAudioMix, gAudioMixFields.mDeviceType);
1617 
1618     jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioMix,
1619                                                            gAudioMixFields.mDeviceAddress);
1620     const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
1621     nAudioMix->mDeviceAddress = String8(nDeviceAddress);
1622     env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
1623     env->DeleteLocalRef(jDeviceAddress);
1624 
1625     nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
1626 
1627     jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
1628     nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
1629                                                      gAudioFormatFields.mSampleRate);
1630     nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat,
1631                                                      gAudioFormatFields.mChannelMask));
1632     nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat,
1633                                                      gAudioFormatFields.mEncoding));
1634     env->DeleteLocalRef(jFormat);
1635 
1636     jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
1637     jobject jRuleCriteria = env->GetObjectField(jRule, gAudioMixingRuleFields.mCriteria);
1638     env->DeleteLocalRef(jRule);
1639     jobjectArray jCriteria = (jobjectArray)env->CallObjectMethod(jRuleCriteria,
1640                                                                  gArrayListMethods.toArray);
1641     env->DeleteLocalRef(jRuleCriteria);
1642 
1643     jint numCriteria = env->GetArrayLength(jCriteria);
1644     if (numCriteria > MAX_CRITERIA_PER_MIX) {
1645         numCriteria = MAX_CRITERIA_PER_MIX;
1646     }
1647 
1648     for (jint i = 0; i < numCriteria; i++) {
1649         AudioMixMatchCriterion nCriterion;
1650 
1651         jobject jCriterion = env->GetObjectArrayElement(jCriteria, i);
1652 
1653         nCriterion.mRule = env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mRule);
1654 
1655         const uint32_t match_rule = nCriterion.mRule & ~RULE_EXCLUSION_MASK;
1656         switch (match_rule) {
1657         case RULE_MATCH_UID:
1658             nCriterion.mValue.mUid = env->GetIntField(jCriterion,
1659                     gAudioMixMatchCriterionFields.mIntProp);
1660             break;
1661         case RULE_MATCH_ATTRIBUTE_USAGE:
1662         case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
1663             jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
1664             if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
1665                 nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
1666                         gAudioAttributesFields.mUsage);
1667             } else {
1668                 nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
1669                         gAudioAttributesFields.mSource);
1670             }
1671             env->DeleteLocalRef(jAttributes);
1672             }
1673             break;
1674         }
1675 
1676         nAudioMix->mCriteria.add(nCriterion);
1677         env->DeleteLocalRef(jCriterion);
1678     }
1679 
1680     env->DeleteLocalRef(jCriteria);
1681 
1682     return (jint)AUDIO_JAVA_SUCCESS;
1683 }
1684 
1685 static jint
android_media_AudioSystem_registerPolicyMixes(JNIEnv * env,jobject clazz,jobject jMixesList,jboolean registration)1686 android_media_AudioSystem_registerPolicyMixes(JNIEnv *env, jobject clazz,
1687                                               jobject jMixesList, jboolean registration)
1688 {
1689     ALOGV("registerPolicyMixes");
1690 
1691     if (jMixesList == NULL) {
1692         return (jint)AUDIO_JAVA_BAD_VALUE;
1693     }
1694     if (!env->IsInstanceOf(jMixesList, gArrayListClass)) {
1695         return (jint)AUDIO_JAVA_BAD_VALUE;
1696     }
1697     jobjectArray jMixes = (jobjectArray)env->CallObjectMethod(jMixesList,
1698                                                               gArrayListMethods.toArray);
1699     jint numMixes = env->GetArrayLength(jMixes);
1700     if (numMixes > MAX_MIXES_PER_POLICY) {
1701         numMixes = MAX_MIXES_PER_POLICY;
1702     }
1703 
1704     status_t status;
1705     jint jStatus;
1706     jobject jAudioMix = NULL;
1707     Vector <AudioMix> mixes;
1708     for (jint i = 0; i < numMixes; i++) {
1709         jAudioMix = env->GetObjectArrayElement(jMixes, i);
1710         if (!env->IsInstanceOf(jAudioMix, gAudioMixClass)) {
1711             jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
1712             goto exit;
1713         }
1714         AudioMix mix;
1715         jStatus = convertAudioMixToNative(env, &mix, jAudioMix);
1716         env->DeleteLocalRef(jAudioMix);
1717         jAudioMix = NULL;
1718         if (jStatus != AUDIO_JAVA_SUCCESS) {
1719             goto exit;
1720         }
1721         mixes.add(mix);
1722     }
1723 
1724     ALOGV("AudioSystem::registerPolicyMixes numMixes %d registration %d", numMixes, registration);
1725     status = AudioSystem::registerPolicyMixes(mixes, registration);
1726     ALOGV("AudioSystem::registerPolicyMixes() returned %d", status);
1727 
1728     jStatus = nativeToJavaStatus(status);
1729     if (jStatus != AUDIO_JAVA_SUCCESS) {
1730         goto exit;
1731     }
1732 
1733 exit:
1734     if (jAudioMix != NULL) {
1735         env->DeleteLocalRef(jAudioMix);
1736     }
1737     return jStatus;
1738 }
1739 
1740 static jint
android_media_AudioSystem_systemReady(JNIEnv * env,jobject thiz)1741 android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz)
1742 {
1743     return nativeToJavaStatus(AudioSystem::systemReady());
1744 }
1745 
1746 
1747 // ----------------------------------------------------------------------------
1748 
1749 static const JNINativeMethod gMethods[] = {
1750     {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
1751     {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
1752     {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
1753     {"isMicrophoneMuted",   "()Z",      (void *)android_media_AudioSystem_isMicrophoneMuted},
1754     {"isStreamActive",      "(II)Z",    (void *)android_media_AudioSystem_isStreamActive},
1755     {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
1756     {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
1757     {"newAudioSessionId",   "()I",      (void *)android_media_AudioSystem_newAudioSessionId},
1758     {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
1759     {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
1760     {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
1761     {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
1762     {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
1763     {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
1764     {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
1765     {"getStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_getStreamVolumeIndex},
1766     {"setMasterVolume",     "(F)I",     (void *)android_media_AudioSystem_setMasterVolume},
1767     {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
1768     {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
1769     {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
1770     {"setMasterMono",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMono},
1771     {"getMasterMono",       "()Z",      (void *)android_media_AudioSystem_getMasterMono},
1772     {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
1773     {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
1774     {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
1775     {"getOutputLatency",    "(I)I",     (void *)android_media_AudioSystem_getOutputLatency},
1776     {"setLowRamDevice",     "(Z)I",     (void *)android_media_AudioSystem_setLowRamDevice},
1777     {"checkAudioFlinger",    "()I",     (void *)android_media_AudioSystem_checkAudioFlinger},
1778     {"listAudioPorts",      "(Ljava/util/ArrayList;[I)I",
1779                                                 (void *)android_media_AudioSystem_listAudioPorts},
1780     {"createAudioPatch",    "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
1781                                             (void *)android_media_AudioSystem_createAudioPatch},
1782     {"releaseAudioPatch",   "(Landroid/media/AudioPatch;)I",
1783                                             (void *)android_media_AudioSystem_releaseAudioPatch},
1784     {"listAudioPatches",    "(Ljava/util/ArrayList;[I)I",
1785                                                 (void *)android_media_AudioSystem_listAudioPatches},
1786     {"setAudioPortConfig",   "(Landroid/media/AudioPortConfig;)I",
1787                                             (void *)android_media_AudioSystem_setAudioPortConfig},
1788     {"getAudioHwSyncForSession", "(I)I",
1789                                     (void *)android_media_AudioSystem_getAudioHwSyncForSession},
1790     {"registerPolicyMixes",    "(Ljava/util/ArrayList;Z)I",
1791                                             (void *)android_media_AudioSystem_registerPolicyMixes},
1792     {"native_register_dynamic_policy_callback", "()V",
1793                                     (void *)android_media_AudioSystem_registerDynPolicyCallback},
1794     {"native_register_recording_callback", "()V",
1795                                     (void *)android_media_AudioSystem_registerRecordingCallback},
1796     {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
1797 };
1798 
1799 
1800 static const JNINativeMethod gEventHandlerMethods[] = {
1801     {"native_setup",
1802         "(Ljava/lang/Object;)V",
1803         (void *)android_media_AudioSystem_eventHandlerSetup},
1804     {"native_finalize",
1805         "()V",
1806         (void *)android_media_AudioSystem_eventHandlerFinalize},
1807 };
1808 
register_android_media_AudioSystem(JNIEnv * env)1809 int register_android_media_AudioSystem(JNIEnv *env)
1810 {
1811     jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
1812     gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
1813     gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
1814     gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass, "toArray", "()[Ljava/lang/Object;");
1815 
1816     jclass audioHandleClass = FindClassOrDie(env, "android/media/AudioHandle");
1817     gAudioHandleClass = MakeGlobalRefOrDie(env, audioHandleClass);
1818     gAudioHandleCstor = GetMethodIDOrDie(env, audioHandleClass, "<init>", "(I)V");
1819     gAudioHandleFields.mId = GetFieldIDOrDie(env, audioHandleClass, "mId", "I");
1820 
1821     jclass audioPortClass = FindClassOrDie(env, "android/media/AudioPort");
1822     gAudioPortClass = MakeGlobalRefOrDie(env, audioPortClass);
1823     gAudioPortCstor = GetMethodIDOrDie(env, audioPortClass, "<init>",
1824             "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
1825     gAudioPortFields.mHandle = GetFieldIDOrDie(env, audioPortClass, "mHandle",
1826                                                "Landroid/media/AudioHandle;");
1827     gAudioPortFields.mRole = GetFieldIDOrDie(env, audioPortClass, "mRole", "I");
1828     gAudioPortFields.mGains = GetFieldIDOrDie(env, audioPortClass, "mGains",
1829                                               "[Landroid/media/AudioGain;");
1830     gAudioPortFields.mActiveConfig = GetFieldIDOrDie(env, audioPortClass, "mActiveConfig",
1831                                                      "Landroid/media/AudioPortConfig;");
1832 
1833     jclass audioPortConfigClass = FindClassOrDie(env, "android/media/AudioPortConfig");
1834     gAudioPortConfigClass = MakeGlobalRefOrDie(env, audioPortConfigClass);
1835     gAudioPortConfigCstor = GetMethodIDOrDie(env, audioPortConfigClass, "<init>",
1836             "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
1837     gAudioPortConfigFields.mPort = GetFieldIDOrDie(env, audioPortConfigClass, "mPort",
1838                                                    "Landroid/media/AudioPort;");
1839     gAudioPortConfigFields.mSamplingRate = GetFieldIDOrDie(env, audioPortConfigClass,
1840                                                            "mSamplingRate", "I");
1841     gAudioPortConfigFields.mChannelMask = GetFieldIDOrDie(env, audioPortConfigClass,
1842                                                           "mChannelMask", "I");
1843     gAudioPortConfigFields.mFormat = GetFieldIDOrDie(env, audioPortConfigClass, "mFormat", "I");
1844     gAudioPortConfigFields.mGain = GetFieldIDOrDie(env, audioPortConfigClass, "mGain",
1845                                                    "Landroid/media/AudioGainConfig;");
1846     gAudioPortConfigFields.mConfigMask = GetFieldIDOrDie(env, audioPortConfigClass, "mConfigMask",
1847                                                          "I");
1848 
1849     jclass audioDevicePortConfigClass = FindClassOrDie(env, "android/media/AudioDevicePortConfig");
1850     gAudioDevicePortConfigClass = MakeGlobalRefOrDie(env, audioDevicePortConfigClass);
1851     gAudioDevicePortConfigCstor = GetMethodIDOrDie(env, audioDevicePortConfigClass, "<init>",
1852             "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
1853 
1854     jclass audioMixPortConfigClass = FindClassOrDie(env, "android/media/AudioMixPortConfig");
1855     gAudioMixPortConfigClass = MakeGlobalRefOrDie(env, audioMixPortConfigClass);
1856     gAudioMixPortConfigCstor = GetMethodIDOrDie(env, audioMixPortConfigClass, "<init>",
1857             "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
1858 
1859     jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort");
1860     gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
1861     gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
1862             "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
1863 
1864     jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
1865     gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
1866     gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
1867             "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
1868 
1869     jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
1870     gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
1871     gAudioGainCstor = GetMethodIDOrDie(env, audioGainClass, "<init>", "(IIIIIIIII)V");
1872 
1873     jclass audioGainConfigClass = FindClassOrDie(env, "android/media/AudioGainConfig");
1874     gAudioGainConfigClass = MakeGlobalRefOrDie(env, audioGainConfigClass);
1875     gAudioGainConfigCstor = GetMethodIDOrDie(env, audioGainConfigClass, "<init>",
1876                                              "(ILandroid/media/AudioGain;II[II)V");
1877     gAudioGainConfigFields.mIndex = GetFieldIDOrDie(env, gAudioGainConfigClass, "mIndex", "I");
1878     gAudioGainConfigFields.mMode = GetFieldIDOrDie(env, audioGainConfigClass, "mMode", "I");
1879     gAudioGainConfigFields.mChannelMask = GetFieldIDOrDie(env, audioGainConfigClass, "mChannelMask",
1880                                                           "I");
1881     gAudioGainConfigFields.mValues = GetFieldIDOrDie(env, audioGainConfigClass, "mValues", "[I");
1882     gAudioGainConfigFields.mRampDurationMs = GetFieldIDOrDie(env, audioGainConfigClass,
1883                                                              "mRampDurationMs", "I");
1884 
1885     jclass audioPatchClass = FindClassOrDie(env, "android/media/AudioPatch");
1886     gAudioPatchClass = MakeGlobalRefOrDie(env, audioPatchClass);
1887     gAudioPatchCstor = GetMethodIDOrDie(env, audioPatchClass, "<init>",
1888 "(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V");
1889     gAudioPatchFields.mHandle = GetFieldIDOrDie(env, audioPatchClass, "mHandle",
1890                                                 "Landroid/media/AudioHandle;");
1891 
1892     jclass eventHandlerClass = FindClassOrDie(env, kEventHandlerClassPathName);
1893     gAudioPortEventHandlerMethods.postEventFromNative = GetStaticMethodIDOrDie(
1894                                                     env, eventHandlerClass, "postEventFromNative",
1895                                                     "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1896     gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
1897                                                     eventHandlerClass, "mJniCallback", "J");
1898 
1899     gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative =
1900             GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
1901                     "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
1902     gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
1903             GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
1904                     "recordingCallbackFromNative", "(III[I)V");
1905 
1906     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
1907     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
1908     gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
1909                                                 "Landroid/media/audiopolicy/AudioMixingRule;");
1910     gAudioMixFields.mFormat = GetFieldIDOrDie(env, audioMixClass, "mFormat",
1911                                                 "Landroid/media/AudioFormat;");
1912     gAudioMixFields.mRouteFlags = GetFieldIDOrDie(env, audioMixClass, "mRouteFlags", "I");
1913     gAudioMixFields.mDeviceType = GetFieldIDOrDie(env, audioMixClass, "mDeviceSystemType", "I");
1914     gAudioMixFields.mDeviceAddress = GetFieldIDOrDie(env, audioMixClass, "mDeviceAddress",
1915                                                       "Ljava/lang/String;");
1916     gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
1917     gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
1918 
1919     jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
1920     gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
1921     gAudioFormatFields.mEncoding = GetFieldIDOrDie(env, audioFormatClass, "mEncoding", "I");
1922     gAudioFormatFields.mSampleRate = GetFieldIDOrDie(env, audioFormatClass, "mSampleRate", "I");
1923     gAudioFormatFields.mChannelMask = GetFieldIDOrDie(env, audioFormatClass, "mChannelMask", "I");
1924 
1925     jclass audioMixingRuleClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule");
1926     gAudioMixingRuleClass = MakeGlobalRefOrDie(env, audioMixingRuleClass);
1927     gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
1928                                                        "Ljava/util/ArrayList;");
1929 
1930     jclass audioMixMatchCriterionClass =
1931                 FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion");
1932     gAudioMixMatchCriterionClass = MakeGlobalRefOrDie(env,audioMixMatchCriterionClass);
1933     gAudioMixMatchCriterionFields.mAttr = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mAttr",
1934                                                        "Landroid/media/AudioAttributes;");
1935     gAudioMixMatchCriterionFields.mIntProp = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mIntProp",
1936                                                        "I");
1937     gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
1938                                                        "I");
1939 
1940     jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
1941     gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
1942     gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
1943     gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
1944 
1945     AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
1946 
1947     RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1948     return RegisterMethodsOrDie(env, kEventHandlerClassPathName, gEventHandlerMethods,
1949                                 NELEM(gEventHandlerMethods));
1950 }
1951