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