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