• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 //#define LOG_NDEBUG 0
19 
20 #define LOG_TAG "AudioSystem-JNI"
21 #include <utils/Log.h>
22 
23 #include <sstream>
24 #include <jni.h>
25 #include <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