blob: d30e6eba48e73b16354e9a36e79a2588f02afa25 [file] [log] [blame]
Glenn Kastenb3db2132012-01-19 08:59:58 -08001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002**
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
Eric Laurent3a241992014-05-19 19:33:26 -070018//#define LOG_NDEBUG 0
19
Eric Laurentb69681c2014-05-19 19:02:51 -070020#define LOG_TAG "AudioSystem-JNI"
Glenn Kastenc81d31c2012-03-13 14:46:23 -070021#include <utils/Log.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022
Andy Hung737d9fb2016-08-16 18:38:49 -070023#include <sstream>
Glenn Kastenc81d31c2012-03-13 14:46:23 -070024#include <jni.h>
25#include <JNIHelp.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080026#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027
28#include <media/AudioSystem.h>
Eric Laurent7f5eb9f2014-12-01 19:36:30 -080029#include <media/AudioPolicy.h>
Andy Hung737d9fb2016-08-16 18:38:49 -070030#include <nativehelper/ScopedLocalRef.h>
Dima Zavin34bb4192011-05-11 14:15:23 -070031#include <system/audio.h>
Dima Zavin290029d2011-06-13 18:16:26 -070032#include <system/audio_policy.h>
Eric Laurentb69681c2014-05-19 19:02:51 -070033#include "android_media_AudioFormat.h"
34#include "android_media_AudioErrors.h"
Dima Zavin24fc2fb2011-04-19 22:30:36 -070035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036// ----------------------------------------------------------------------------
37
38using namespace android;
39
Glenn Kastened0079d2011-04-04 10:50:50 -070040static const char* const kClassPathName = "android/media/AudioSystem";
41
Eric Laurentb69681c2014-05-19 19:02:51 -070042static jclass gArrayListClass;
43static struct {
44 jmethodID add;
Eric Laurent7f5eb9f2014-12-01 19:36:30 -080045 jmethodID toArray;
Eric Laurentb69681c2014-05-19 19:02:51 -070046} gArrayListMethods;
47
48static jclass gAudioHandleClass;
49static jmethodID gAudioHandleCstor;
50static struct {
51 jfieldID mId;
52} gAudioHandleFields;
53
54static jclass gAudioPortClass;
55static jmethodID gAudioPortCstor;
56static struct {
57 jfieldID mHandle;
58 jfieldID mRole;
59 jfieldID mGains;
60 jfieldID mActiveConfig;
61 // other fields unused by JNI
62} gAudioPortFields;
63
64static jclass gAudioPortConfigClass;
65static jmethodID gAudioPortConfigCstor;
66static struct {
67 jfieldID mPort;
68 jfieldID mSamplingRate;
69 jfieldID mChannelMask;
70 jfieldID mFormat;
71 jfieldID mGain;
Eric Laurent3a241992014-05-19 19:33:26 -070072 jfieldID mConfigMask;
Eric Laurentb69681c2014-05-19 19:02:51 -070073} gAudioPortConfigFields;
74
75static jclass gAudioDevicePortClass;
76static jmethodID gAudioDevicePortCstor;
77
78static jclass gAudioDevicePortConfigClass;
79static jmethodID gAudioDevicePortConfigCstor;
80
81static jclass gAudioMixPortClass;
82static jmethodID gAudioMixPortCstor;
83
84static jclass gAudioMixPortConfigClass;
85static jmethodID gAudioMixPortConfigCstor;
86
87static jclass gAudioGainClass;
88static jmethodID gAudioGainCstor;
89
90static jclass gAudioGainConfigClass;
91static jmethodID gAudioGainConfigCstor;
92static 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
101static jclass gAudioPatchClass;
102static jmethodID gAudioPatchCstor;
103static struct {
104 jfieldID mHandle;
105 // other fields unused by JNI
106} gAudioPatchFields;
107
Eric Laurent7f5eb9f2014-12-01 19:36:30 -0800108static jclass gAudioMixClass;
109static struct {
110 jfieldID mRule;
111 jfieldID mFormat;
112 jfieldID mRouteFlags;
Jean-Michel Trivi4ad39882016-03-14 18:46:41 -0700113 jfieldID mDeviceType;
114 jfieldID mDeviceAddress;
Eric Laurent7f5eb9f2014-12-01 19:36:30 -0800115 jfieldID mMixType;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700116 jfieldID mCallbackFlags;
Eric Laurent7f5eb9f2014-12-01 19:36:30 -0800117} gAudioMixFields;
118
119static jclass gAudioFormatClass;
120static struct {
121 jfieldID mEncoding;
122 jfieldID mSampleRate;
123 jfieldID mChannelMask;
124 // other fields unused by JNI
125} gAudioFormatFields;
126
127static jclass gAudioMixingRuleClass;
128static struct {
129 jfieldID mCriteria;
130 // other fields unused by JNI
131} gAudioMixingRuleFields;
132
Jean-Michel Triviba6b4b42016-02-10 14:26:35 -0800133static jclass gAudioMixMatchCriterionClass;
Eric Laurent7f5eb9f2014-12-01 19:36:30 -0800134static struct {
135 jfieldID mAttr;
Jean-Michel Triviba6b4b42016-02-10 14:26:35 -0800136 jfieldID mIntProp;
Eric Laurent7f5eb9f2014-12-01 19:36:30 -0800137 jfieldID mRule;
Jean-Michel Triviba6b4b42016-02-10 14:26:35 -0800138} gAudioMixMatchCriterionFields;
Eric Laurent7f5eb9f2014-12-01 19:36:30 -0800139
140static jclass gAudioAttributesClass;
141static struct {
142 jfieldID mUsage;
143 jfieldID mSource;
144} gAudioAttributesFields;
145
146
Eric Laurent700e7342014-05-02 18:33:15 -0700147static const char* const kEventHandlerClassPathName =
148 "android/media/AudioPortEventHandler";
Eric Laurent2615afb2015-03-25 14:51:08 -0700149static struct {
150 jfieldID mJniCallback;
151} gEventHandlerFields;
152static struct {
153 jmethodID postEventFromNative;
154} gAudioPortEventHandlerMethods;
155
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700156static struct {
157 jmethodID postDynPolicyEventFromNative;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800158 jmethodID postRecordConfigEventFromNative;
159} gAudioPolicyEventHandlerMethods;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700160
Eric Laurent2615afb2015-03-25 14:51:08 -0700161static Mutex gLock;
Eric Laurentb69681c2014-05-19 19:02:51 -0700162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163enum AudioError {
164 kAudioStatusOk = 0,
165 kAudioStatusError = 1,
166 kAudioStatusMediaServerDied = 100
167};
168
Eric Laurent700e7342014-05-02 18:33:15 -0700169enum {
170 AUDIOPORT_EVENT_PORT_LIST_UPDATED = 1,
171 AUDIOPORT_EVENT_PATCH_LIST_UPDATED = 2,
172 AUDIOPORT_EVENT_SERVICE_DIED = 3,
173};
174
Eric Laurentb69681c2014-05-19 19:02:51 -0700175#define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
176
Eric Laurent700e7342014-05-02 18:33:15 -0700177// ----------------------------------------------------------------------------
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700178// ref-counted object for audio port callbacks
Eric Laurent700e7342014-05-02 18:33:15 -0700179class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
180{
181public:
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
189private:
190 void sendEvent(int event);
191
Eric Laurent2615afb2015-03-25 14:51:08 -0700192 jclass mClass; // Reference to AudioPortEventHandler class
193 jobject mObject; // Weak ref to AudioPortEventHandler Java object to call on
Eric Laurent700e7342014-05-02 18:33:15 -0700194};
195
196JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
197{
198
Eric Laurent2615afb2015-03-25 14:51:08 -0700199 // Hold onto the AudioPortEventHandler class for use in calling the static method
Eric Laurent700e7342014-05-02 18:33:15 -0700200 // 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
Eric Laurent2615afb2015-03-25 14:51:08 -0700208 // We use a weak reference so the AudioPortEventHandler object can be garbage collected.
Eric Laurent700e7342014-05-02 18:33:15 -0700209 // The reference is only used as a proxy for callbacks.
210 mObject = env->NewGlobalRef(weak_thiz);
211}
212
213JNIAudioPortCallback::~JNIAudioPortCallback()
214{
215 // remove global references
216 JNIEnv *env = AndroidRuntime::getJNIEnv();
Eric Laurent449c5882014-11-12 11:07:48 -0800217 if (env == NULL) {
218 return;
219 }
Eric Laurent700e7342014-05-02 18:33:15 -0700220 env->DeleteGlobalRef(mObject);
221 env->DeleteGlobalRef(mClass);
222}
223
224void JNIAudioPortCallback::sendEvent(int event)
225{
226 JNIEnv *env = AndroidRuntime::getJNIEnv();
Eric Laurent449c5882014-11-12 11:07:48 -0800227 if (env == NULL) {
228 return;
229 }
Eric Laurent2615afb2015-03-25 14:51:08 -0700230 env->CallStaticVoidMethod(mClass, gAudioPortEventHandlerMethods.postEventFromNative, mObject,
Eric Laurent700e7342014-05-02 18:33:15 -0700231 event, 0, 0, NULL);
232 if (env->ExceptionCheck()) {
233 ALOGW("An exception occurred while notifying an event.");
234 env->ExceptionClear();
235 }
236}
237
238void JNIAudioPortCallback::onAudioPortListUpdate()
239{
240 sendEvent(AUDIOPORT_EVENT_PORT_LIST_UPDATED);
241}
242
243void JNIAudioPortCallback::onAudioPatchListUpdate()
244{
245 sendEvent(AUDIOPORT_EVENT_PATCH_LIST_UPDATED);
246}
247
248void JNIAudioPortCallback::onServiceDied()
249{
250 sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
251}
252
Eric Laurent2615afb2015-03-25 14:51:08 -0700253static 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270static int check_AudioSystem_Command(status_t status)
271{
Eric Laurentdfb881f2013-07-18 14:41:39 -0700272 switch (status) {
273 case DEAD_OBJECT:
274 return kAudioStatusMediaServerDied;
275 case NO_ERROR:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 return kAudioStatusOk;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700277 default:
278 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700280 return kAudioStatusError;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281}
282
Ashok Bhat075e9a12014-01-06 13:45:09 +0000283static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
285{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000286 return (jint) check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287}
288
289static jboolean
290android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
291{
292 bool state = false;
293 AudioSystem::isMicrophoneMuted(&state);
294 return state;
295}
296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297static jboolean
Eric Laurent25101b02011-02-02 09:33:30 -0800298android_media_AudioSystem_isStreamActive(JNIEnv *env, jobject thiz, jint stream, jint inPastMs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299{
300 bool state = false;
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800301 AudioSystem::isStreamActive((audio_stream_type_t) stream, &state, inPastMs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 return state;
303}
304
Jean-Michel Trivid6770542012-10-10 12:03:41 -0700305static jboolean
Jean-Michel Trivi679d5042013-02-04 16:24:09 -0800306android_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
314static jboolean
Jean-Michel Trivid6770542012-10-10 12:03:41 -0700315android_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
Ashok Bhat075e9a12014-01-06 13:45:09 +0000322static jint
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -0700323android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
324{
Glenn Kasten211d9052016-02-26 16:22:40 -0800325 return AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -0700326}
327
328static jint
Eric Laurenta553c252009-07-17 12:17:14 -0700329android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330{
Eric Laurenta553c252009-07-17 12:17:14 -0700331 const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
332 String8 c_keyValuePairs8;
333 if (keyValuePairs) {
Dan Albert66987492014-11-20 11:41:21 -0800334 c_keyValuePairs8 = String8(
335 reinterpret_cast<const char16_t*>(c_keyValuePairs),
336 env->GetStringLength(keyValuePairs));
Eric Laurenta553c252009-07-17 12:17:14 -0700337 env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
338 }
Glenn Kastenc94752a2013-12-19 12:40:33 -0800339 int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
Ashok Bhat075e9a12014-01-06 13:45:09 +0000340 return (jint) status;
Eric Laurenta553c252009-07-17 12:17:14 -0700341}
342
343static jstring
344android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
345{
346 const jchar* c_keys = env->GetStringCritical(keys, 0);
347 String8 c_keys8;
348 if (keys) {
Dan Albert66987492014-11-20 11:41:21 -0800349 c_keys8 = String8(reinterpret_cast<const char16_t*>(c_keys),
350 env->GetStringLength(keys));
Eric Laurenta553c252009-07-17 12:17:14 -0700351 env->ReleaseStringCritical(keys, c_keys);
352 }
Glenn Kastenc94752a2013-12-19 12:40:33 -0800353 return env->NewStringUTF(AudioSystem::getParameters(c_keys8).string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354}
355
Glenn Kastened0079d2011-04-04 10:50:50 -0700356static void
357android_media_AudioSystem_error_callback(status_t err)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358{
Eric Laurent539719a2013-07-18 14:08:00 -0700359 JNIEnv *env = AndroidRuntime::getJNIEnv();
Eric Laurent0e7a4d92010-10-15 12:33:16 -0700360 if (env == NULL) {
361 return;
362 }
363
Glenn Kastened0079d2011-04-04 10:50:50 -0700364 jclass clazz = env->FindClass(kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365
Eric Laurentdfb881f2013-07-18 14:41:39 -0700366 env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
367 "errorCallbackFromNative","(I)V"),
368 check_AudioSystem_Command(err));
Viorel Sumanb637ccf2014-05-30 16:51:07 +0300369
370 env->DeleteLocalRef(clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371}
372
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700373static void
374android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val)
375{
376 JNIEnv *env = AndroidRuntime::getJNIEnv();
377 if (env == NULL) {
378 return;
379 }
380
381 jclass clazz = env->FindClass(kClassPathName);
382 const char* zechars = regId.string();
383 jstring zestring = env->NewStringUTF(zechars);
384
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800385 env->CallStaticVoidMethod(clazz, gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative,
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700386 event, zestring, val);
387
388 env->ReleaseStringUTFChars(zestring, zechars);
389 env->DeleteLocalRef(clazz);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800390}
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700391
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800392static void
Glenn Kasten33b84042016-03-08 12:02:55 -0800393android_media_AudioSystem_recording_callback(int event, audio_session_t session, int source,
Jean-Michel Trivi8ab72802016-02-25 16:31:45 -0800394 const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
395 audio_patch_handle_t patchHandle)
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800396{
397 JNIEnv *env = AndroidRuntime::getJNIEnv();
398 if (env == NULL) {
399 return;
400 }
Jean-Michel Trivi33fd8162016-02-22 10:52:41 -0800401 if (clientConfig == NULL || deviceConfig == NULL) {
402 ALOGE("Unexpected null client/device configurations in recording callback");
403 return;
404 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800405
Jean-Michel Trivi33fd8162016-02-22 10:52:41 -0800406 // create an array for 2*3 integers to store the record configurations (client + device)
Jean-Michel Trivi8ab72802016-02-25 16:31:45 -0800407 // plus 1 integer for the patch handle
408 const int REC_PARAM_SIZE = 7;
409 jintArray recParamArray = env->NewIntArray(REC_PARAM_SIZE);
Jean-Michel Trivi33fd8162016-02-22 10:52:41 -0800410 if (recParamArray == NULL) {
411 ALOGE("recording callback: Couldn't allocate int array for configuration data");
412 return;
413 }
Jean-Michel Trivi8ab72802016-02-25 16:31:45 -0800414 jint recParamData[REC_PARAM_SIZE];
Jean-Michel Trivi33fd8162016-02-22 10:52:41 -0800415 recParamData[0] = (jint) audioFormatFromNative(clientConfig->format);
416 // FIXME this doesn't support index-based masks
417 recParamData[1] = (jint) inChannelMaskFromNative(clientConfig->channel_mask);
418 recParamData[2] = (jint) clientConfig->sample_rate;
419 recParamData[3] = (jint) audioFormatFromNative(deviceConfig->format);
420 // FIXME this doesn't support index-based masks
421 recParamData[4] = (jint) inChannelMaskFromNative(deviceConfig->channel_mask);
422 recParamData[5] = (jint) deviceConfig->sample_rate;
Jean-Michel Trivi8ab72802016-02-25 16:31:45 -0800423 recParamData[6] = (jint) patchHandle;
424 env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData);
Jean-Michel Trivi33fd8162016-02-22 10:52:41 -0800425
426 // callback into java
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800427 jclass clazz = env->FindClass(kClassPathName);
428 env->CallStaticVoidMethod(clazz,
429 gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
Jean-Michel Trivi33fd8162016-02-22 10:52:41 -0800430 event, session, source, recParamArray);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800431 env->DeleteLocalRef(clazz);
Jean-Michel Trivi33fd8162016-02-22 10:52:41 -0800432
433 env->DeleteLocalRef(recParamArray);
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700434}
435
Ashok Bhat075e9a12014-01-06 13:45:09 +0000436static jint
Paul McLean10804eb2015-01-28 11:16:35 -0800437android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
Eric Laurenta553c252009-07-17 12:17:14 -0700438{
439 const char *c_address = env->GetStringUTFChars(device_address, NULL);
Paul McLean10804eb2015-01-28 11:16:35 -0800440 const char *c_name = env->GetStringUTFChars(device_name, NULL);
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700441 int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
442 static_cast <audio_policy_dev_state_t>(state),
Paul McLean10804eb2015-01-28 11:16:35 -0800443 c_address, c_name));
Eric Laurenta553c252009-07-17 12:17:14 -0700444 env->ReleaseStringUTFChars(device_address, c_address);
Paul McLean10804eb2015-01-28 11:16:35 -0800445 env->ReleaseStringUTFChars(device_name, c_name);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000446 return (jint) status;
Eric Laurenta553c252009-07-17 12:17:14 -0700447}
448
Ashok Bhat075e9a12014-01-06 13:45:09 +0000449static jint
Eric Laurenta553c252009-07-17 12:17:14 -0700450android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
451{
452 const char *c_address = env->GetStringUTFChars(device_address, NULL);
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700453 int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
Eric Laurenta553c252009-07-17 12:17:14 -0700454 c_address));
455 env->ReleaseStringUTFChars(device_address, c_address);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000456 return (jint) state;
Eric Laurenta553c252009-07-17 12:17:14 -0700457}
458
Ashok Bhat075e9a12014-01-06 13:45:09 +0000459static jint
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800460android_media_AudioSystem_handleDeviceConfigChange(JNIEnv *env, jobject thiz, jint device, jstring device_address, jstring device_name)
461{
462 const char *c_address = env->GetStringUTFChars(device_address, NULL);
463 const char *c_name = env->GetStringUTFChars(device_name, NULL);
464 int status = check_AudioSystem_Command(AudioSystem::handleDeviceConfigChange(static_cast <audio_devices_t>(device),
465 c_address, c_name));
466 env->ReleaseStringUTFChars(device_address, c_address);
467 env->ReleaseStringUTFChars(device_name, c_name);
468 return (jint) status;
469}
470
471static jint
Eric Laurenta553c252009-07-17 12:17:14 -0700472android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
473{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000474 return (jint) check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
Eric Laurenta553c252009-07-17 12:17:14 -0700475}
476
Ashok Bhat075e9a12014-01-06 13:45:09 +0000477static jint
Eric Laurenta553c252009-07-17 12:17:14 -0700478android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
479{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000480 return (jint) check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700481 static_cast <audio_policy_forced_cfg_t>(config)));
Eric Laurenta553c252009-07-17 12:17:14 -0700482}
483
Ashok Bhat075e9a12014-01-06 13:45:09 +0000484static jint
Eric Laurenta553c252009-07-17 12:17:14 -0700485android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
486{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000487 return static_cast <jint>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
Eric Laurenta553c252009-07-17 12:17:14 -0700488}
489
Ashok Bhat075e9a12014-01-06 13:45:09 +0000490static jint
Eric Laurenta553c252009-07-17 12:17:14 -0700491android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
492{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000493 return (jint) check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
Eric Laurenta553c252009-07-17 12:17:14 -0700494 indexMin,
495 indexMax));
496}
497
Ashok Bhat075e9a12014-01-06 13:45:09 +0000498static jint
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800499android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
500 jobject thiz,
501 jint stream,
502 jint index,
503 jint device)
Eric Laurenta553c252009-07-17 12:17:14 -0700504{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000505 return (jint) check_AudioSystem_Command(
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800506 AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
507 index,
508 (audio_devices_t)device));
Eric Laurenta553c252009-07-17 12:17:14 -0700509}
510
Ashok Bhat075e9a12014-01-06 13:45:09 +0000511static jint
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800512android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env,
513 jobject thiz,
514 jint stream,
515 jint device)
Eric Laurenta553c252009-07-17 12:17:14 -0700516{
517 int index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800518 if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
519 &index,
520 (audio_devices_t)device)
521 != NO_ERROR) {
Eric Laurenta553c252009-07-17 12:17:14 -0700522 index = -1;
523 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000524 return (jint) index;
Eric Laurenta553c252009-07-17 12:17:14 -0700525}
526
Ashok Bhat075e9a12014-01-06 13:45:09 +0000527static jint
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400528android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
529{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000530 return (jint) check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400531}
532
533static jfloat
534android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
535{
536 float value;
537 if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
538 value = -1.0;
539 }
540 return value;
541}
542
Ashok Bhat075e9a12014-01-06 13:45:09 +0000543static jint
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400544android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
545{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000546 return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400547}
548
Vladimir Markoc1bcdbb2014-10-29 20:34:15 +0000549static jboolean
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400550android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
551{
552 bool mute;
553 if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
554 mute = false;
555 }
556 return mute;
557}
558
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800559static jint
Andy Hungf04b84d2015-12-18 17:33:27 -0800560android_media_AudioSystem_setMasterMono(JNIEnv *env, jobject thiz, jboolean mono)
561{
562 return (jint) check_AudioSystem_Command(AudioSystem::setMasterMono(mono));
563}
564
565static jboolean
566android_media_AudioSystem_getMasterMono(JNIEnv *env, jobject thiz)
567{
568 bool mono;
569 if (AudioSystem::getMasterMono(&mono) != NO_ERROR) {
570 mono = false;
571 }
572 return mono;
573}
574
575static jint
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800576android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
577{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700578 return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800579}
580
Glenn Kastenc6c43652012-09-24 17:32:30 -0700581static jint
582android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
583{
584 return (jint) AudioSystem::getPrimaryOutputSamplingRate();
585}
586
587static jint
588android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
589{
590 return (jint) AudioSystem::getPrimaryOutputFrameCount();
591}
592
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100593static jint
594android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
595{
596 uint32_t afLatency;
597 if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
598 != NO_ERROR) {
599 afLatency = -1;
600 }
601 return (jint) afLatency;
602}
603
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700604static jint
605android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
606{
607 return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
608}
609
Ashok Bhat075e9a12014-01-06 13:45:09 +0000610static jint
Eric Laurentdfb881f2013-07-18 14:41:39 -0700611android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
612{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000613 return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
Eric Laurentdfb881f2013-07-18 14:41:39 -0700614}
615
Eric Laurentb69681c2014-05-19 19:02:51 -0700616
617static bool useInChannelMask(audio_port_type_t type, audio_port_role_t role)
618{
619 return ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
620 ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
621}
622
Eric Laurent3a241992014-05-19 19:33:26 -0700623static void convertAudioGainConfigToNative(JNIEnv *env,
624 struct audio_gain_config *nAudioGainConfig,
625 const jobject jAudioGainConfig,
626 bool useInMask)
627{
628 nAudioGainConfig->index = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mIndex);
629 nAudioGainConfig->mode = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
630 ALOGV("convertAudioGainConfigToNative got gain index %d", nAudioGainConfig->index);
631 jint jMask = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mChannelMask);
632 audio_channel_mask_t nMask;
633 if (useInMask) {
634 nMask = inChannelMaskToNative(jMask);
635 ALOGV("convertAudioGainConfigToNative IN mask java %x native %x", jMask, nMask);
636 } else {
637 nMask = outChannelMaskToNative(jMask);
638 ALOGV("convertAudioGainConfigToNative OUT mask java %x native %x", jMask, nMask);
639 }
640 nAudioGainConfig->channel_mask = nMask;
641 nAudioGainConfig->ramp_duration_ms = env->GetIntField(jAudioGainConfig,
642 gAudioGainConfigFields.mRampDurationMs);
643 jintArray jValues = (jintArray)env->GetObjectField(jAudioGainConfig,
644 gAudioGainConfigFields.mValues);
645 int *nValues = env->GetIntArrayElements(jValues, NULL);
646 size_t size = env->GetArrayLength(jValues);
647 memcpy(nAudioGainConfig->values, nValues, size * sizeof(int));
648 env->DeleteLocalRef(jValues);
649}
650
651
Eric Laurentb69681c2014-05-19 19:02:51 -0700652static jint convertAudioPortConfigToNative(JNIEnv *env,
653 struct audio_port_config *nAudioPortConfig,
Eric Laurent6368a7d2014-11-19 12:18:32 -0800654 const jobject jAudioPortConfig,
655 bool useConfigMask)
Eric Laurentb69681c2014-05-19 19:02:51 -0700656{
657 jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
658 jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
659 nAudioPortConfig->id = env->GetIntField(jHandle, gAudioHandleFields.mId);
660 nAudioPortConfig->role = (audio_port_role_t)env->GetIntField(jAudioPort,
661 gAudioPortFields.mRole);
662 if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
663 nAudioPortConfig->type = AUDIO_PORT_TYPE_DEVICE;
664 } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
665 nAudioPortConfig->type = AUDIO_PORT_TYPE_MIX;
666 } else {
667 env->DeleteLocalRef(jAudioPort);
668 env->DeleteLocalRef(jHandle);
669 return (jint)AUDIO_JAVA_ERROR;
670 }
671 ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
672 nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
673
Eric Laurent6368a7d2014-11-19 12:18:32 -0800674 unsigned int configMask = 0;
675
Eric Laurentb69681c2014-05-19 19:02:51 -0700676 nAudioPortConfig->sample_rate = env->GetIntField(jAudioPortConfig,
677 gAudioPortConfigFields.mSamplingRate);
Eric Laurent6368a7d2014-11-19 12:18:32 -0800678 if (nAudioPortConfig->sample_rate != 0) {
679 configMask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
680 }
Eric Laurentb69681c2014-05-19 19:02:51 -0700681
682 bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
683 audio_channel_mask_t nMask;
684 jint jMask = env->GetIntField(jAudioPortConfig,
685 gAudioPortConfigFields.mChannelMask);
686 if (useInMask) {
687 nMask = inChannelMaskToNative(jMask);
688 ALOGV("convertAudioPortConfigToNative IN mask java %x native %x", jMask, nMask);
689 } else {
690 nMask = outChannelMaskToNative(jMask);
691 ALOGV("convertAudioPortConfigToNative OUT mask java %x native %x", jMask, nMask);
692 }
693 nAudioPortConfig->channel_mask = nMask;
Eric Laurent6368a7d2014-11-19 12:18:32 -0800694 if (nAudioPortConfig->channel_mask != AUDIO_CHANNEL_NONE) {
695 configMask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
696 }
Eric Laurentb69681c2014-05-19 19:02:51 -0700697
698 jint jFormat = env->GetIntField(jAudioPortConfig, gAudioPortConfigFields.mFormat);
699 audio_format_t nFormat = audioFormatToNative(jFormat);
700 ALOGV("convertAudioPortConfigToNative format %d native %d", jFormat, nFormat);
701 nAudioPortConfig->format = nFormat;
Eric Laurent6368a7d2014-11-19 12:18:32 -0800702 if (nAudioPortConfig->format != AUDIO_FORMAT_DEFAULT &&
703 nAudioPortConfig->format != AUDIO_FORMAT_INVALID) {
704 configMask |= AUDIO_PORT_CONFIG_FORMAT;
705 }
706
Eric Laurentb69681c2014-05-19 19:02:51 -0700707 jobject jGain = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mGain);
708 if (jGain != NULL) {
Eric Laurent3a241992014-05-19 19:33:26 -0700709 convertAudioGainConfigToNative(env, &nAudioPortConfig->gain, jGain, useInMask);
Eric Laurentb69681c2014-05-19 19:02:51 -0700710 env->DeleteLocalRef(jGain);
Eric Laurent6368a7d2014-11-19 12:18:32 -0800711 configMask |= AUDIO_PORT_CONFIG_GAIN;
Eric Laurentb69681c2014-05-19 19:02:51 -0700712 } else {
713 ALOGV("convertAudioPortConfigToNative no gain");
714 nAudioPortConfig->gain.index = -1;
715 }
Eric Laurent6368a7d2014-11-19 12:18:32 -0800716 if (useConfigMask) {
717 nAudioPortConfig->config_mask = env->GetIntField(jAudioPortConfig,
718 gAudioPortConfigFields.mConfigMask);
719 } else {
720 nAudioPortConfig->config_mask = configMask;
721 }
Eric Laurentb69681c2014-05-19 19:02:51 -0700722 env->DeleteLocalRef(jAudioPort);
723 env->DeleteLocalRef(jHandle);
724 return (jint)AUDIO_JAVA_SUCCESS;
725}
726
727static jint convertAudioPortConfigFromNative(JNIEnv *env,
728 jobject jAudioPort,
729 jobject *jAudioPortConfig,
730 const struct audio_port_config *nAudioPortConfig)
731{
732 jint jStatus = AUDIO_JAVA_SUCCESS;
733 jobject jAudioGainConfig = NULL;
734 jobject jAudioGain = NULL;
735 jintArray jGainValues;
736 bool audioportCreated = false;
737
738 ALOGV("convertAudioPortConfigFromNative jAudioPort %p", jAudioPort);
739
740 if (jAudioPort == NULL) {
741 jobject jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
742 nAudioPortConfig->id);
743
744 ALOGV("convertAudioPortConfigFromNative handle %d is a %s", nAudioPortConfig->id,
745 nAudioPortConfig->type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix");
746
747 if (jHandle == NULL) {
748 return (jint)AUDIO_JAVA_ERROR;
749 }
750 // create dummy port and port config objects with just the correct handle
751 // and configuration data. The actual AudioPortConfig objects will be
752 // constructed by java code with correct class type (device, mix etc...)
753 // and reference to AudioPort instance in this client
754 jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
Paul McLeanf29e5f32015-06-15 10:19:22 -0700755 jHandle, // handle
756 0, // role
757 NULL, // name
758 NULL, // samplingRates
759 NULL, // channelMasks
760 NULL, // channelIndexMasks
761 NULL, // formats
762 NULL); // gains
Eric Laurentb69681c2014-05-19 19:02:51 -0700763 env->DeleteLocalRef(jHandle);
764 if (jAudioPort == NULL) {
765 return (jint)AUDIO_JAVA_ERROR;
766 }
767 ALOGV("convertAudioPortConfigFromNative jAudioPort created for handle %d",
768 nAudioPortConfig->id);
769
770 audioportCreated = true;
771 }
772
773 bool useInMask = useInChannelMask(nAudioPortConfig->type, nAudioPortConfig->role);
774
775 audio_channel_mask_t nMask;
776 jint jMask;
777
778 int gainIndex = nAudioPortConfig->gain.index;
779 if (gainIndex >= 0) {
780 ALOGV("convertAudioPortConfigFromNative gain found with index %d mode %x",
781 gainIndex, nAudioPortConfig->gain.mode);
782 if (audioportCreated) {
783 ALOGV("convertAudioPortConfigFromNative creating gain");
784 jAudioGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
785 gainIndex,
786 0,
787 0,
788 0,
789 0,
790 0,
791 0,
792 0,
793 0);
794 if (jAudioGain == NULL) {
795 ALOGV("convertAudioPortConfigFromNative creating gain FAILED");
796 jStatus = (jint)AUDIO_JAVA_ERROR;
797 goto exit;
798 }
799 } else {
800 ALOGV("convertAudioPortConfigFromNative reading gain from port");
801 jobjectArray jGains = (jobjectArray)env->GetObjectField(jAudioPort,
802 gAudioPortFields.mGains);
803 if (jGains == NULL) {
804 ALOGV("convertAudioPortConfigFromNative could not get gains from port");
805 jStatus = (jint)AUDIO_JAVA_ERROR;
806 goto exit;
807 }
808 jAudioGain = env->GetObjectArrayElement(jGains, gainIndex);
809 env->DeleteLocalRef(jGains);
810 if (jAudioGain == NULL) {
811 ALOGV("convertAudioPortConfigFromNative could not get gain at index %d", gainIndex);
812 jStatus = (jint)AUDIO_JAVA_ERROR;
813 goto exit;
814 }
815 }
Eric Laurent0078c7c2014-06-04 09:49:52 -0700816 int numValues;
817 if (useInMask) {
818 numValues = audio_channel_count_from_in_mask(nAudioPortConfig->gain.channel_mask);
819 } else {
820 numValues = audio_channel_count_from_out_mask(nAudioPortConfig->gain.channel_mask);
821 }
Eric Laurentb69681c2014-05-19 19:02:51 -0700822 jGainValues = env->NewIntArray(numValues);
823 if (jGainValues == NULL) {
824 ALOGV("convertAudioPortConfigFromNative could not create gain values %d", numValues);
825 jStatus = (jint)AUDIO_JAVA_ERROR;
826 goto exit;
827 }
828 env->SetIntArrayRegion(jGainValues, 0, numValues,
829 nAudioPortConfig->gain.values);
830
831 nMask = nAudioPortConfig->gain.channel_mask;
832 if (useInMask) {
833 jMask = inChannelMaskFromNative(nMask);
834 ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
835 } else {
836 jMask = outChannelMaskFromNative(nMask);
837 ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
838 }
839
840 jAudioGainConfig = env->NewObject(gAudioGainConfigClass,
841 gAudioGainConfigCstor,
842 gainIndex,
843 jAudioGain,
844 nAudioPortConfig->gain.mode,
845 jMask,
846 jGainValues,
847 nAudioPortConfig->gain.ramp_duration_ms);
848 env->DeleteLocalRef(jGainValues);
849 if (jAudioGainConfig == NULL) {
850 ALOGV("convertAudioPortConfigFromNative could not create gain config");
851 jStatus = (jint)AUDIO_JAVA_ERROR;
852 goto exit;
853 }
854 }
855 jclass clazz;
856 jmethodID methodID;
857 if (audioportCreated) {
858 clazz = gAudioPortConfigClass;
859 methodID = gAudioPortConfigCstor;
860 ALOGV("convertAudioPortConfigFromNative building a generic port config");
861 } else {
862 if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
863 clazz = gAudioDevicePortConfigClass;
864 methodID = gAudioDevicePortConfigCstor;
865 ALOGV("convertAudioPortConfigFromNative building a device config");
866 } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
867 clazz = gAudioMixPortConfigClass;
868 methodID = gAudioMixPortConfigCstor;
869 ALOGV("convertAudioPortConfigFromNative building a mix config");
870 } else {
871 jStatus = (jint)AUDIO_JAVA_ERROR;
872 goto exit;
873 }
874 }
875 nMask = nAudioPortConfig->channel_mask;
876 if (useInMask) {
877 jMask = inChannelMaskFromNative(nMask);
878 ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
879 } else {
880 jMask = outChannelMaskFromNative(nMask);
881 ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
882 }
883
884 *jAudioPortConfig = env->NewObject(clazz, methodID,
885 jAudioPort,
886 nAudioPortConfig->sample_rate,
887 jMask,
888 audioFormatFromNative(nAudioPortConfig->format),
889 jAudioGainConfig);
890 if (*jAudioPortConfig == NULL) {
891 ALOGV("convertAudioPortConfigFromNative could not create new port config");
892 jStatus = (jint)AUDIO_JAVA_ERROR;
893 } else {
894 ALOGV("convertAudioPortConfigFromNative OK");
895 }
896
897exit:
898 if (audioportCreated) {
899 env->DeleteLocalRef(jAudioPort);
900 if (jAudioGain != NULL) {
901 env->DeleteLocalRef(jAudioGain);
902 }
903 }
904 if (jAudioGainConfig != NULL) {
905 env->DeleteLocalRef(jAudioGainConfig);
906 }
907 return jStatus;
908}
909
Paul McLean4e5e9e92015-06-17 10:10:11 -0700910static bool hasFormat(int* formats, size_t size, int format) {
911 for (size_t index = 0; index < size; index++) {
912 if (formats[index] == format) {
913 return true; // found
914 }
915 }
916 return false; // not found
917}
918
Andy Hung737d9fb2016-08-16 18:38:49 -0700919// TODO: pull out to separate file
920template <typename T, size_t N>
921static constexpr size_t array_size(const T (&)[N]) {
922 return N;
923}
924
Eric Laurentb69681c2014-05-19 19:02:51 -0700925static jint convertAudioPortFromNative(JNIEnv *env,
926 jobject *jAudioPort, const struct audio_port *nAudioPort)
927{
928 jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
929 jintArray jSamplingRates = NULL;
930 jintArray jChannelMasks = NULL;
Paul McLeanf29e5f32015-06-15 10:19:22 -0700931 jintArray jChannelIndexMasks = NULL;
Paul McLean4e5e9e92015-06-17 10:10:11 -0700932 int* cFormats = NULL;
Eric Laurentb69681c2014-05-19 19:02:51 -0700933 jintArray jFormats = NULL;
934 jobjectArray jGains = NULL;
935 jobject jHandle = NULL;
Paul McLean10804eb2015-01-28 11:16:35 -0800936 jstring jDeviceName = NULL;
Eric Laurentb69681c2014-05-19 19:02:51 -0700937 bool useInMask;
Paul McLeanf29e5f32015-06-15 10:19:22 -0700938 size_t numPositionMasks = 0;
939 size_t numIndexMasks = 0;
Paul McLean2db94372015-06-18 12:47:34 -0700940 size_t numUniqueFormats = 0;
941
Paul McLean10804eb2015-01-28 11:16:35 -0800942 ALOGV("convertAudioPortFromNative id %d role %d type %d name %s",
943 nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name);
Eric Laurentb69681c2014-05-19 19:02:51 -0700944
Andy Hung737d9fb2016-08-16 18:38:49 -0700945 // Verify audio port array count info.
946 if (nAudioPort->num_sample_rates > array_size(nAudioPort->sample_rates)
947 || nAudioPort->num_channel_masks > array_size(nAudioPort->channel_masks)
948 || nAudioPort->num_formats > array_size(nAudioPort->formats)
949 || nAudioPort->num_gains > array_size(nAudioPort->gains)) {
950
951 std::stringstream ss;
952 ss << "convertAudioPortFromNative array count out of bounds:"
953 << " num_sample_rates " << nAudioPort->num_sample_rates
954 << " num_channel_masks " << nAudioPort->num_channel_masks
955 << " num_formats " << nAudioPort->num_formats
956 << " num_gains " << nAudioPort->num_gains
957 ;
958 std::string s = ss.str();
959
960 // Prefer to log through Java wtf instead of native ALOGE.
961 ScopedLocalRef<jclass> jLogClass(env, env->FindClass("android/util/Log"));
962 jmethodID jWtfId = (jLogClass.get() == nullptr)
963 ? nullptr
964 : env->GetStaticMethodID(jLogClass.get(), "wtf",
965 "(Ljava/lang/String;Ljava/lang/String;)I");
966 if (jWtfId != nullptr) {
967 ScopedLocalRef<jstring> jMessage(env, env->NewStringUTF(s.c_str()));
968 ScopedLocalRef<jstring> jTag(env, env->NewStringUTF(LOG_TAG));
969 (void)env->CallStaticIntMethod(jLogClass.get(), jWtfId, jTag.get(), jMessage.get());
970 } else {
971 ALOGE("%s", s.c_str());
972 }
973 jStatus = (jint)AUDIO_JAVA_ERROR;
974 goto exit;
975 }
976
Eric Laurentb69681c2014-05-19 19:02:51 -0700977 jSamplingRates = env->NewIntArray(nAudioPort->num_sample_rates);
978 if (jSamplingRates == NULL) {
979 jStatus = (jint)AUDIO_JAVA_ERROR;
980 goto exit;
981 }
982 if (nAudioPort->num_sample_rates) {
983 env->SetIntArrayRegion(jSamplingRates, 0, nAudioPort->num_sample_rates,
984 (jint *)nAudioPort->sample_rates);
985 }
986
Paul McLeanf29e5f32015-06-15 10:19:22 -0700987 // count up how many masks are positional and indexed
988 for(size_t index = 0; index < nAudioPort->num_channel_masks; index++) {
989 const audio_channel_mask_t mask = nAudioPort->channel_masks[index];
990 if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
991 numIndexMasks++;
992 } else {
993 numPositionMasks++;
994 }
995 }
996
997 jChannelMasks = env->NewIntArray(numPositionMasks);
Eric Laurentb69681c2014-05-19 19:02:51 -0700998 if (jChannelMasks == NULL) {
999 jStatus = (jint)AUDIO_JAVA_ERROR;
1000 goto exit;
1001 }
Paul McLeanf29e5f32015-06-15 10:19:22 -07001002 jChannelIndexMasks = env->NewIntArray(numIndexMasks);
1003 if (jChannelIndexMasks == NULL) {
1004 jStatus = (jint)AUDIO_JAVA_ERROR;
1005 goto exit;
1006 }
Eric Laurentb69681c2014-05-19 19:02:51 -07001007 useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role);
1008
Paul McLeanf29e5f32015-06-15 10:19:22 -07001009 // put the masks in the output arrays
1010 for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0;
1011 maskIndex < nAudioPort->num_channel_masks; maskIndex++) {
1012 const audio_channel_mask_t mask = nAudioPort->channel_masks[maskIndex];
1013 if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
1014 jint jMask = audio_channel_mask_get_bits(mask);
1015 env->SetIntArrayRegion(jChannelIndexMasks, indexedMaskIndex++, 1, &jMask);
Eric Laurentb69681c2014-05-19 19:02:51 -07001016 } else {
Paul McLeanf29e5f32015-06-15 10:19:22 -07001017 jint jMask = useInMask ? inChannelMaskFromNative(mask)
1018 : outChannelMaskFromNative(mask);
1019 env->SetIntArrayRegion(jChannelMasks, posMaskIndex++, 1, &jMask);
Eric Laurentb69681c2014-05-19 19:02:51 -07001020 }
Eric Laurentb69681c2014-05-19 19:02:51 -07001021 }
1022
Paul McLeanf29e5f32015-06-15 10:19:22 -07001023 // formats
Paul McLean2db94372015-06-18 12:47:34 -07001024 if (nAudioPort->num_formats != 0) {
1025 cFormats = new int[nAudioPort->num_formats];
1026 for (size_t index = 0; index < nAudioPort->num_formats; index++) {
1027 int format = audioFormatFromNative(nAudioPort->formats[index]);
1028 if (!hasFormat(cFormats, numUniqueFormats, format)) {
1029 cFormats[numUniqueFormats++] = format;
1030 }
Paul McLean4e5e9e92015-06-17 10:10:11 -07001031 }
1032 }
1033 jFormats = env->NewIntArray(numUniqueFormats);
Eric Laurentb69681c2014-05-19 19:02:51 -07001034 if (jFormats == NULL) {
1035 jStatus = (jint)AUDIO_JAVA_ERROR;
1036 goto exit;
1037 }
Paul McLean2db94372015-06-18 12:47:34 -07001038 if (numUniqueFormats != 0) {
1039 env->SetIntArrayRegion(jFormats, 0, numUniqueFormats, cFormats);
1040 }
Eric Laurentb69681c2014-05-19 19:02:51 -07001041
Paul McLeanf29e5f32015-06-15 10:19:22 -07001042 // gains
Eric Laurentb69681c2014-05-19 19:02:51 -07001043 jGains = env->NewObjectArray(nAudioPort->num_gains,
1044 gAudioGainClass, NULL);
1045 if (jGains == NULL) {
1046 jStatus = (jint)AUDIO_JAVA_ERROR;
1047 goto exit;
1048 }
Paul McLeanf29e5f32015-06-15 10:19:22 -07001049
Eric Laurentb69681c2014-05-19 19:02:51 -07001050 for (size_t j = 0; j < nAudioPort->num_gains; j++) {
1051 audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask;
Paul McLeanf29e5f32015-06-15 10:19:22 -07001052 jint jMask;
Eric Laurentb69681c2014-05-19 19:02:51 -07001053 if (useInMask) {
1054 jMask = inChannelMaskFromNative(nMask);
1055 ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask);
1056 } else {
1057 jMask = outChannelMaskFromNative(nMask);
1058 ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
1059 }
1060
1061 jobject jGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
1062 j,
1063 nAudioPort->gains[j].mode,
1064 jMask,
1065 nAudioPort->gains[j].min_value,
1066 nAudioPort->gains[j].max_value,
1067 nAudioPort->gains[j].default_value,
1068 nAudioPort->gains[j].step_value,
1069 nAudioPort->gains[j].min_ramp_ms,
1070 nAudioPort->gains[j].max_ramp_ms);
1071 if (jGain == NULL) {
1072 jStatus = (jint)AUDIO_JAVA_ERROR;
1073 goto exit;
1074 }
1075 env->SetObjectArrayElement(jGains, j, jGain);
1076 env->DeleteLocalRef(jGain);
1077 }
1078
1079 jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1080 nAudioPort->id);
1081 if (jHandle == NULL) {
1082 jStatus = (jint)AUDIO_JAVA_ERROR;
1083 goto exit;
1084 }
1085
Paul McLean10804eb2015-01-28 11:16:35 -08001086 jDeviceName = env->NewStringUTF(nAudioPort->name);
1087
Eric Laurentb69681c2014-05-19 19:02:51 -07001088 if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
1089 ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
1090 jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
1091 *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor,
Paul McLean10804eb2015-01-28 11:16:35 -08001092 jHandle, jDeviceName,
Paul McLeanf29e5f32015-06-15 10:19:22 -07001093 jSamplingRates, jChannelMasks, jChannelIndexMasks,
1094 jFormats, jGains,
Eric Laurentb69681c2014-05-19 19:02:51 -07001095 nAudioPort->ext.device.type, jAddress);
1096 env->DeleteLocalRef(jAddress);
1097 } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
1098 ALOGV("convertAudioPortFromNative is a mix");
1099 *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
Eric Laurent4bcdba82015-05-01 11:37:49 -07001100 jHandle, nAudioPort->ext.mix.handle,
1101 nAudioPort->role, jDeviceName,
Paul McLeanf29e5f32015-06-15 10:19:22 -07001102 jSamplingRates, jChannelMasks, jChannelIndexMasks,
Eric Laurentb69681c2014-05-19 19:02:51 -07001103 jFormats, jGains);
1104 } else {
1105 ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
1106 jStatus = (jint)AUDIO_JAVA_ERROR;
1107 goto exit;
1108 }
1109 if (*jAudioPort == NULL) {
1110 jStatus = (jint)AUDIO_JAVA_ERROR;
1111 goto exit;
1112 }
1113
1114 jobject jAudioPortConfig;
1115 jStatus = convertAudioPortConfigFromNative(env,
1116 *jAudioPort,
1117 &jAudioPortConfig,
1118 &nAudioPort->active_config);
1119 if (jStatus != AUDIO_JAVA_SUCCESS) {
Andy Hung737d9fb2016-08-16 18:38:49 -07001120 goto exit;
Eric Laurentb69681c2014-05-19 19:02:51 -07001121 }
1122
1123 env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
1124
1125exit:
Paul McLean10804eb2015-01-28 11:16:35 -08001126 if (jDeviceName != NULL) {
1127 env->DeleteLocalRef(jDeviceName);
1128 }
Eric Laurentb69681c2014-05-19 19:02:51 -07001129 if (jSamplingRates != NULL) {
1130 env->DeleteLocalRef(jSamplingRates);
1131 }
1132 if (jChannelMasks != NULL) {
1133 env->DeleteLocalRef(jChannelMasks);
1134 }
Paul McLean4e5e9e92015-06-17 10:10:11 -07001135 if (jChannelIndexMasks != NULL) {
1136 env->DeleteLocalRef(jChannelIndexMasks);
1137 }
1138 if (cFormats != NULL) {
1139 delete[] cFormats;
1140 }
Eric Laurentb69681c2014-05-19 19:02:51 -07001141 if (jFormats != NULL) {
1142 env->DeleteLocalRef(jFormats);
1143 }
1144 if (jGains != NULL) {
1145 env->DeleteLocalRef(jGains);
1146 }
1147 if (jHandle != NULL) {
1148 env->DeleteLocalRef(jHandle);
1149 }
1150
1151 return jStatus;
1152}
1153
1154
1155static jint
1156android_media_AudioSystem_listAudioPorts(JNIEnv *env, jobject clazz,
1157 jobject jPorts, jintArray jGeneration)
1158{
1159 ALOGV("listAudioPorts");
1160
1161 if (jPorts == NULL) {
1162 ALOGE("listAudioPorts NULL AudioPort ArrayList");
1163 return (jint)AUDIO_JAVA_BAD_VALUE;
1164 }
1165 if (!env->IsInstanceOf(jPorts, gArrayListClass)) {
1166 ALOGE("listAudioPorts not an arraylist");
1167 return (jint)AUDIO_JAVA_BAD_VALUE;
1168 }
1169
1170 if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
1171 return (jint)AUDIO_JAVA_BAD_VALUE;
1172 }
1173
1174 status_t status;
1175 unsigned int generation1;
1176 unsigned int generation;
1177 unsigned int numPorts;
1178 jint *nGeneration;
1179 struct audio_port *nPorts = NULL;
1180 int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
Eric Laurentb36d1042016-04-14 18:00:38 -07001181 jint jStatus;
Eric Laurentb69681c2014-05-19 19:02:51 -07001182
1183 // get the port count and all the ports until they both return the same generation
1184 do {
1185 if (attempts-- < 0) {
1186 status = TIMED_OUT;
1187 break;
1188 }
1189
1190 numPorts = 0;
1191 status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
1192 AUDIO_PORT_TYPE_NONE,
1193 &numPorts,
1194 NULL,
1195 &generation1);
Eric Laurentb36d1042016-04-14 18:00:38 -07001196 if (status != NO_ERROR) {
Eric Laurentb69681c2014-05-19 19:02:51 -07001197 ALOGE_IF(status != NO_ERROR, "AudioSystem::listAudioPorts error %d", status);
1198 break;
1199 }
Eric Laurentb36d1042016-04-14 18:00:38 -07001200 if (numPorts == 0) {
1201 jStatus = (jint)AUDIO_JAVA_SUCCESS;
1202 goto exit;
1203 }
Eric Laurentb69681c2014-05-19 19:02:51 -07001204 nPorts = (struct audio_port *)realloc(nPorts, numPorts * sizeof(struct audio_port));
1205
1206 status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE,
1207 AUDIO_PORT_TYPE_NONE,
1208 &numPorts,
1209 nPorts,
1210 &generation);
1211 ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
1212 numPorts, generation, generation1);
1213 } while (generation1 != generation && status == NO_ERROR);
1214
Eric Laurentb36d1042016-04-14 18:00:38 -07001215 jStatus = nativeToJavaStatus(status);
Eric Laurentb69681c2014-05-19 19:02:51 -07001216 if (jStatus != AUDIO_JAVA_SUCCESS) {
1217 goto exit;
1218 }
1219
Eric Laurentb69681c2014-05-19 19:02:51 -07001220 for (size_t i = 0; i < numPorts; i++) {
1221 jobject jAudioPort;
1222 jStatus = convertAudioPortFromNative(env, &jAudioPort, &nPorts[i]);
1223 if (jStatus != AUDIO_JAVA_SUCCESS) {
1224 goto exit;
1225 }
1226 env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort);
1227 }
1228
1229exit:
Eric Laurentb36d1042016-04-14 18:00:38 -07001230 nGeneration = env->GetIntArrayElements(jGeneration, NULL);
1231 if (nGeneration == NULL) {
1232 jStatus = (jint)AUDIO_JAVA_ERROR;
1233 } else {
1234 nGeneration[0] = generation1;
1235 env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
1236 }
Eric Laurentb69681c2014-05-19 19:02:51 -07001237 free(nPorts);
1238 return jStatus;
1239}
1240
1241static int
1242android_media_AudioSystem_createAudioPatch(JNIEnv *env, jobject clazz,
1243 jobjectArray jPatches, jobjectArray jSources, jobjectArray jSinks)
1244{
1245 status_t status;
1246 jint jStatus;
1247
1248 ALOGV("createAudioPatch");
1249 if (jPatches == NULL || jSources == NULL || jSinks == NULL) {
1250 return (jint)AUDIO_JAVA_BAD_VALUE;
1251 }
1252
1253 if (env->GetArrayLength(jPatches) != 1) {
1254 return (jint)AUDIO_JAVA_BAD_VALUE;
1255 }
1256 jint numSources = env->GetArrayLength(jSources);
1257 if (numSources == 0 || numSources > AUDIO_PATCH_PORTS_MAX) {
1258 return (jint)AUDIO_JAVA_BAD_VALUE;
1259 }
1260
1261 jint numSinks = env->GetArrayLength(jSinks);
1262 if (numSinks == 0 || numSinks > AUDIO_PATCH_PORTS_MAX) {
1263 return (jint)AUDIO_JAVA_BAD_VALUE;
1264 }
1265
1266 audio_patch_handle_t handle = (audio_patch_handle_t)0;
1267 jobject jPatch = env->GetObjectArrayElement(jPatches, 0);
1268 jobject jPatchHandle = NULL;
1269 if (jPatch != NULL) {
1270 if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
1271 return (jint)AUDIO_JAVA_BAD_VALUE;
1272 }
1273 jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
1274 handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
1275 }
1276
1277 struct audio_patch nPatch;
1278
1279 nPatch.id = handle;
1280 nPatch.num_sources = 0;
1281 nPatch.num_sinks = 0;
1282 jobject jSource = NULL;
1283 jobject jSink = NULL;
1284
1285 for (jint i = 0; i < numSources; i++) {
1286 jSource = env->GetObjectArrayElement(jSources, i);
1287 if (!env->IsInstanceOf(jSource, gAudioPortConfigClass)) {
1288 jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
1289 goto exit;
1290 }
Eric Laurent6368a7d2014-11-19 12:18:32 -08001291 jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource, false);
Eric Laurentb69681c2014-05-19 19:02:51 -07001292 env->DeleteLocalRef(jSource);
1293 jSource = NULL;
1294 if (jStatus != AUDIO_JAVA_SUCCESS) {
1295 goto exit;
1296 }
1297 nPatch.num_sources++;
1298 }
1299
1300 for (jint i = 0; i < numSinks; i++) {
1301 jSink = env->GetObjectArrayElement(jSinks, i);
1302 if (!env->IsInstanceOf(jSink, gAudioPortConfigClass)) {
1303 jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
1304 goto exit;
1305 }
Eric Laurent6368a7d2014-11-19 12:18:32 -08001306 jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink, false);
Eric Laurentb69681c2014-05-19 19:02:51 -07001307 env->DeleteLocalRef(jSink);
1308 jSink = NULL;
1309 if (jStatus != AUDIO_JAVA_SUCCESS) {
1310 goto exit;
1311 }
1312 nPatch.num_sinks++;
1313 }
1314
1315 ALOGV("AudioSystem::createAudioPatch");
1316 status = AudioSystem::createAudioPatch(&nPatch, &handle);
1317 ALOGV("AudioSystem::createAudioPatch() returned %d hande %d", status, handle);
1318
1319 jStatus = nativeToJavaStatus(status);
1320 if (jStatus != AUDIO_JAVA_SUCCESS) {
1321 goto exit;
1322 }
1323
1324 if (jPatchHandle == NULL) {
1325 jPatchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1326 handle);
1327 if (jPatchHandle == NULL) {
1328 jStatus = (jint)AUDIO_JAVA_ERROR;
1329 goto exit;
1330 }
1331 jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle, jSources, jSinks);
1332 if (jPatch == NULL) {
1333 jStatus = (jint)AUDIO_JAVA_ERROR;
1334 goto exit;
1335 }
1336 env->SetObjectArrayElement(jPatches, 0, jPatch);
1337 } else {
1338 env->SetIntField(jPatchHandle, gAudioHandleFields.mId, handle);
1339 }
1340
1341exit:
1342 if (jPatchHandle != NULL) {
1343 env->DeleteLocalRef(jPatchHandle);
1344 }
1345 if (jPatch != NULL) {
1346 env->DeleteLocalRef(jPatch);
1347 }
1348 if (jSource != NULL) {
1349 env->DeleteLocalRef(jSource);
1350 }
1351 if (jSink != NULL) {
1352 env->DeleteLocalRef(jSink);
1353 }
1354 return jStatus;
1355}
1356
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001357static jint
Eric Laurentb69681c2014-05-19 19:02:51 -07001358android_media_AudioSystem_releaseAudioPatch(JNIEnv *env, jobject clazz,
1359 jobject jPatch)
1360{
1361 ALOGV("releaseAudioPatch");
1362 if (jPatch == NULL) {
1363 return (jint)AUDIO_JAVA_BAD_VALUE;
1364 }
1365
1366 audio_patch_handle_t handle = (audio_patch_handle_t)0;
1367 jobject jPatchHandle = NULL;
1368 if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
1369 return (jint)AUDIO_JAVA_BAD_VALUE;
1370 }
1371 jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
1372 handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
1373 env->DeleteLocalRef(jPatchHandle);
1374
1375 ALOGV("AudioSystem::releaseAudioPatch");
1376 status_t status = AudioSystem::releaseAudioPatch(handle);
1377 ALOGV("AudioSystem::releaseAudioPatch() returned %d", status);
1378 jint jStatus = nativeToJavaStatus(status);
Andreas Gampe0f0b4912014-11-12 08:03:48 -08001379 return jStatus;
Eric Laurentb69681c2014-05-19 19:02:51 -07001380}
1381
1382static jint
1383android_media_AudioSystem_listAudioPatches(JNIEnv *env, jobject clazz,
1384 jobject jPatches, jintArray jGeneration)
1385{
1386 ALOGV("listAudioPatches");
1387 if (jPatches == NULL) {
1388 ALOGE("listAudioPatches NULL AudioPatch ArrayList");
1389 return (jint)AUDIO_JAVA_BAD_VALUE;
1390 }
1391 if (!env->IsInstanceOf(jPatches, gArrayListClass)) {
1392 ALOGE("listAudioPatches not an arraylist");
1393 return (jint)AUDIO_JAVA_BAD_VALUE;
1394 }
1395
1396 if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
1397 return (jint)AUDIO_JAVA_BAD_VALUE;
1398 }
1399
1400 status_t status;
1401 unsigned int generation1;
1402 unsigned int generation;
1403 unsigned int numPatches;
1404 jint *nGeneration;
1405 struct audio_patch *nPatches = NULL;
1406 jobjectArray jSources = NULL;
1407 jobject jSource = NULL;
1408 jobjectArray jSinks = NULL;
1409 jobject jSink = NULL;
1410 jobject jPatch = NULL;
1411 int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
Eric Laurentb36d1042016-04-14 18:00:38 -07001412 jint jStatus;
Eric Laurentb69681c2014-05-19 19:02:51 -07001413
1414 // get the patch count and all the patches until they both return the same generation
1415 do {
1416 if (attempts-- < 0) {
1417 status = TIMED_OUT;
1418 break;
1419 }
1420
1421 numPatches = 0;
1422 status = AudioSystem::listAudioPatches(&numPatches,
1423 NULL,
1424 &generation1);
Eric Laurentb36d1042016-04-14 18:00:38 -07001425 if (status != NO_ERROR) {
Eric Laurentb69681c2014-05-19 19:02:51 -07001426 ALOGE_IF(status != NO_ERROR, "listAudioPatches AudioSystem::listAudioPatches error %d",
1427 status);
1428 break;
1429 }
Eric Laurentb36d1042016-04-14 18:00:38 -07001430 if (numPatches == 0) {
1431 jStatus = (jint)AUDIO_JAVA_SUCCESS;
1432 goto exit;
1433 }
1434
Eric Laurentb69681c2014-05-19 19:02:51 -07001435 nPatches = (struct audio_patch *)realloc(nPatches, numPatches * sizeof(struct audio_patch));
1436
1437 status = AudioSystem::listAudioPatches(&numPatches,
1438 nPatches,
1439 &generation);
1440 ALOGV("listAudioPatches AudioSystem::listAudioPatches numPatches %d generation %d generation1 %d",
1441 numPatches, generation, generation1);
1442
1443 } while (generation1 != generation && status == NO_ERROR);
1444
Eric Laurentb36d1042016-04-14 18:00:38 -07001445 jStatus = nativeToJavaStatus(status);
Eric Laurentb69681c2014-05-19 19:02:51 -07001446 if (jStatus != AUDIO_JAVA_SUCCESS) {
1447 goto exit;
1448 }
1449
Eric Laurentb69681c2014-05-19 19:02:51 -07001450 for (size_t i = 0; i < numPatches; i++) {
1451 jobject patchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
1452 nPatches[i].id);
1453 if (patchHandle == NULL) {
1454 jStatus = AUDIO_JAVA_ERROR;
1455 goto exit;
1456 }
Dan Albert46d84442014-11-18 16:07:51 -08001457 ALOGV("listAudioPatches patch %zu num_sources %d num_sinks %d",
Eric Laurentb69681c2014-05-19 19:02:51 -07001458 i, nPatches[i].num_sources, nPatches[i].num_sinks);
1459
1460 env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
1461
1462 // load sources
1463 jSources = env->NewObjectArray(nPatches[i].num_sources,
1464 gAudioPortConfigClass, NULL);
1465 if (jSources == NULL) {
1466 jStatus = AUDIO_JAVA_ERROR;
1467 goto exit;
1468 }
1469
1470 for (size_t j = 0; j < nPatches[i].num_sources; j++) {
1471 jStatus = convertAudioPortConfigFromNative(env,
1472 NULL,
1473 &jSource,
1474 &nPatches[i].sources[j]);
1475 if (jStatus != AUDIO_JAVA_SUCCESS) {
1476 goto exit;
1477 }
1478 env->SetObjectArrayElement(jSources, j, jSource);
1479 env->DeleteLocalRef(jSource);
1480 jSource = NULL;
Dan Albert46d84442014-11-18 16:07:51 -08001481 ALOGV("listAudioPatches patch %zu source %zu is a %s handle %d",
Eric Laurentb69681c2014-05-19 19:02:51 -07001482 i, j,
1483 nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
1484 nPatches[i].sources[j].id);
1485 }
1486 // load sinks
1487 jSinks = env->NewObjectArray(nPatches[i].num_sinks,
1488 gAudioPortConfigClass, NULL);
1489 if (jSinks == NULL) {
1490 jStatus = AUDIO_JAVA_ERROR;
1491 goto exit;
1492 }
1493
1494 for (size_t j = 0; j < nPatches[i].num_sinks; j++) {
1495 jStatus = convertAudioPortConfigFromNative(env,
1496 NULL,
1497 &jSink,
1498 &nPatches[i].sinks[j]);
1499
1500 if (jStatus != AUDIO_JAVA_SUCCESS) {
1501 goto exit;
1502 }
1503 env->SetObjectArrayElement(jSinks, j, jSink);
1504 env->DeleteLocalRef(jSink);
1505 jSink = NULL;
Dan Albert46d84442014-11-18 16:07:51 -08001506 ALOGV("listAudioPatches patch %zu sink %zu is a %s handle %d",
Eric Laurentb69681c2014-05-19 19:02:51 -07001507 i, j,
1508 nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
1509 nPatches[i].sinks[j].id);
1510 }
1511
1512 jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor,
1513 patchHandle, jSources, jSinks);
1514 env->DeleteLocalRef(jSources);
1515 jSources = NULL;
1516 env->DeleteLocalRef(jSinks);
1517 jSinks = NULL;
1518 if (jPatch == NULL) {
1519 jStatus = AUDIO_JAVA_ERROR;
1520 goto exit;
1521 }
1522 env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch);
1523 env->DeleteLocalRef(jPatch);
1524 jPatch = NULL;
1525 }
1526
1527exit:
Eric Laurentb36d1042016-04-14 18:00:38 -07001528
1529 nGeneration = env->GetIntArrayElements(jGeneration, NULL);
1530 if (nGeneration == NULL) {
1531 jStatus = AUDIO_JAVA_ERROR;
1532 } else {
1533 nGeneration[0] = generation1;
1534 env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
1535 }
1536
Eric Laurentb69681c2014-05-19 19:02:51 -07001537 if (jSources != NULL) {
1538 env->DeleteLocalRef(jSources);
1539 }
1540 if (jSource != NULL) {
1541 env->DeleteLocalRef(jSource);
1542 }
1543 if (jSinks != NULL) {
1544 env->DeleteLocalRef(jSinks);
1545 }
1546 if (jSink != NULL) {
1547 env->DeleteLocalRef(jSink);
1548 }
1549 if (jPatch != NULL) {
1550 env->DeleteLocalRef(jPatch);
1551 }
1552 free(nPatches);
1553 return jStatus;
1554}
1555
Eric Laurent3a241992014-05-19 19:33:26 -07001556static jint
1557android_media_AudioSystem_setAudioPortConfig(JNIEnv *env, jobject clazz,
1558 jobject jAudioPortConfig)
1559{
1560 ALOGV("setAudioPortConfig");
1561 if (jAudioPortConfig == NULL) {
1562 return AUDIO_JAVA_BAD_VALUE;
1563 }
1564 if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
1565 return AUDIO_JAVA_BAD_VALUE;
1566 }
1567 struct audio_port_config nAudioPortConfig;
Eric Laurent6368a7d2014-11-19 12:18:32 -08001568 jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig, true);
Eric Laurent3a241992014-05-19 19:33:26 -07001569 if (jStatus != AUDIO_JAVA_SUCCESS) {
1570 return jStatus;
1571 }
1572 status_t status = AudioSystem::setAudioPortConfig(&nAudioPortConfig);
1573 ALOGV("AudioSystem::setAudioPortConfig() returned %d", status);
1574 jStatus = nativeToJavaStatus(status);
1575 return jStatus;
1576}
1577
Eric Laurent700e7342014-05-02 18:33:15 -07001578static void
1579android_media_AudioSystem_eventHandlerSetup(JNIEnv *env, jobject thiz, jobject weak_this)
1580{
1581 ALOGV("eventHandlerSetup");
1582
1583 sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
1584
Eric Laurent2615afb2015-03-25 14:51:08 -07001585 if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) {
1586 setJniCallback(env, thiz, callback);
1587 }
Eric Laurent700e7342014-05-02 18:33:15 -07001588}
1589
1590static void
1591android_media_AudioSystem_eventHandlerFinalize(JNIEnv *env, jobject thiz)
1592{
1593 ALOGV("eventHandlerFinalize");
1594
Eric Laurent2615afb2015-03-25 14:51:08 -07001595 sp<JNIAudioPortCallback> callback = setJniCallback(env, thiz, 0);
Eric Laurent700e7342014-05-02 18:33:15 -07001596
Eric Laurent2615afb2015-03-25 14:51:08 -07001597 if (callback != 0) {
1598 AudioSystem::removeAudioPortCallback(callback);
1599 }
Eric Laurent700e7342014-05-02 18:33:15 -07001600}
1601
Eric Laurentb634e1b2014-08-01 14:44:46 -07001602static jint
1603android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
1604{
Glenn Kasten33b84042016-03-08 12:02:55 -08001605 return (jint) AudioSystem::getAudioHwSyncForSession((audio_session_t) sessionId);
Eric Laurentb634e1b2014-08-01 14:44:46 -07001606}
1607
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07001608static void
1609android_media_AudioSystem_registerDynPolicyCallback(JNIEnv *env, jobject thiz)
1610{
1611 AudioSystem::setDynPolicyCallback(android_media_AudioSystem_dyn_policy_callback);
1612}
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001613
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08001614static void
1615android_media_AudioSystem_registerRecordingCallback(JNIEnv *env, jobject thiz)
1616{
1617 AudioSystem::setRecordConfigCallback(android_media_AudioSystem_recording_callback);
1618}
1619
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001620
1621static jint convertAudioMixToNative(JNIEnv *env,
1622 AudioMix *nAudioMix,
1623 const jobject jAudioMix)
1624{
1625 nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
1626 nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
Jean-Michel Trivi4ad39882016-03-14 18:46:41 -07001627 nAudioMix->mDeviceType = (audio_devices_t)
1628 env->GetIntField(jAudioMix, gAudioMixFields.mDeviceType);
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001629
Jean-Michel Trivi4ad39882016-03-14 18:46:41 -07001630 jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioMix,
1631 gAudioMixFields.mDeviceAddress);
1632 const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
1633 nAudioMix->mDeviceAddress = String8(nDeviceAddress);
1634 env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
1635 env->DeleteLocalRef(jDeviceAddress);
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001636
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07001637 nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
1638
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001639 jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
1640 nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
1641 gAudioFormatFields.mSampleRate);
1642 nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat,
1643 gAudioFormatFields.mChannelMask));
1644 nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat,
1645 gAudioFormatFields.mEncoding));
1646 env->DeleteLocalRef(jFormat);
1647
1648 jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
1649 jobject jRuleCriteria = env->GetObjectField(jRule, gAudioMixingRuleFields.mCriteria);
1650 env->DeleteLocalRef(jRule);
1651 jobjectArray jCriteria = (jobjectArray)env->CallObjectMethod(jRuleCriteria,
1652 gArrayListMethods.toArray);
1653 env->DeleteLocalRef(jRuleCriteria);
1654
1655 jint numCriteria = env->GetArrayLength(jCriteria);
1656 if (numCriteria > MAX_CRITERIA_PER_MIX) {
1657 numCriteria = MAX_CRITERIA_PER_MIX;
1658 }
1659
1660 for (jint i = 0; i < numCriteria; i++) {
Jean-Michel Triviba6b4b42016-02-10 14:26:35 -08001661 AudioMixMatchCriterion nCriterion;
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001662
1663 jobject jCriterion = env->GetObjectArrayElement(jCriteria, i);
1664
Jean-Michel Triviba6b4b42016-02-10 14:26:35 -08001665 nCriterion.mRule = env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mRule);
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001666
Jean-Michel Triviba6b4b42016-02-10 14:26:35 -08001667 const uint32_t match_rule = nCriterion.mRule & ~RULE_EXCLUSION_MASK;
1668 switch (match_rule) {
1669 case RULE_MATCH_UID:
1670 nCriterion.mValue.mUid = env->GetIntField(jCriterion,
1671 gAudioMixMatchCriterionFields.mIntProp);
1672 break;
1673 case RULE_MATCH_ATTRIBUTE_USAGE:
1674 case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
1675 jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
1676 if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
1677 nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
1678 gAudioAttributesFields.mUsage);
1679 } else {
1680 nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
1681 gAudioAttributesFields.mSource);
1682 }
1683 env->DeleteLocalRef(jAttributes);
1684 }
1685 break;
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001686 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001687
1688 nAudioMix->mCriteria.add(nCriterion);
1689 env->DeleteLocalRef(jCriterion);
1690 }
1691
1692 env->DeleteLocalRef(jCriteria);
1693
1694 return (jint)AUDIO_JAVA_SUCCESS;
1695}
1696
1697static jint
1698android_media_AudioSystem_registerPolicyMixes(JNIEnv *env, jobject clazz,
1699 jobject jMixesList, jboolean registration)
1700{
1701 ALOGV("registerPolicyMixes");
1702
1703 if (jMixesList == NULL) {
1704 return (jint)AUDIO_JAVA_BAD_VALUE;
1705 }
1706 if (!env->IsInstanceOf(jMixesList, gArrayListClass)) {
1707 return (jint)AUDIO_JAVA_BAD_VALUE;
1708 }
1709 jobjectArray jMixes = (jobjectArray)env->CallObjectMethod(jMixesList,
1710 gArrayListMethods.toArray);
1711 jint numMixes = env->GetArrayLength(jMixes);
1712 if (numMixes > MAX_MIXES_PER_POLICY) {
1713 numMixes = MAX_MIXES_PER_POLICY;
1714 }
1715
1716 status_t status;
1717 jint jStatus;
1718 jobject jAudioMix = NULL;
1719 Vector <AudioMix> mixes;
1720 for (jint i = 0; i < numMixes; i++) {
1721 jAudioMix = env->GetObjectArrayElement(jMixes, i);
1722 if (!env->IsInstanceOf(jAudioMix, gAudioMixClass)) {
1723 jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
1724 goto exit;
1725 }
1726 AudioMix mix;
1727 jStatus = convertAudioMixToNative(env, &mix, jAudioMix);
1728 env->DeleteLocalRef(jAudioMix);
1729 jAudioMix = NULL;
1730 if (jStatus != AUDIO_JAVA_SUCCESS) {
1731 goto exit;
1732 }
1733 mixes.add(mix);
1734 }
1735
1736 ALOGV("AudioSystem::registerPolicyMixes numMixes %d registration %d", numMixes, registration);
1737 status = AudioSystem::registerPolicyMixes(mixes, registration);
1738 ALOGV("AudioSystem::registerPolicyMixes() returned %d", status);
1739
1740 jStatus = nativeToJavaStatus(status);
1741 if (jStatus != AUDIO_JAVA_SUCCESS) {
1742 goto exit;
1743 }
1744
1745exit:
1746 if (jAudioMix != NULL) {
1747 env->DeleteLocalRef(jAudioMix);
1748 }
1749 return jStatus;
1750}
1751
Eric Laurent0867bed2015-05-20 14:49:08 -07001752static jint
1753android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz)
1754{
1755 return nativeToJavaStatus(AudioSystem::systemReady());
1756}
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001757
1758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759// ----------------------------------------------------------------------------
1760
Daniel Micay76f6a862015-09-19 17:31:01 -04001761static const JNINativeMethod gMethods[] = {
Eric Laurenta553c252009-07-17 12:17:14 -07001762 {"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
1763 {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 {"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
1765 {"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
Jean-Michel Trivid6770542012-10-10 12:03:41 -07001766 {"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive},
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08001767 {"isStreamActiveRemotely","(II)Z", (void *)android_media_AudioSystem_isStreamActiveRemotely},
Jean-Michel Trivid6770542012-10-10 12:03:41 -07001768 {"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07001769 {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
Paul McLean10804eb2015-01-28 11:16:35 -08001770 {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
Eric Laurenta553c252009-07-17 12:17:14 -07001771 {"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08001772 {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
Eric Laurenta553c252009-07-17 12:17:14 -07001773 {"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
Eric Laurenta553c252009-07-17 12:17:14 -07001774 {"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
1775 {"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
1776 {"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001777 {"setStreamVolumeIndex","(III)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
1778 {"getStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_getStreamVolumeIndex},
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001779 {"setMasterVolume", "(F)I", (void *)android_media_AudioSystem_setMasterVolume},
1780 {"getMasterVolume", "()F", (void *)android_media_AudioSystem_getMasterVolume},
1781 {"setMasterMute", "(Z)I", (void *)android_media_AudioSystem_setMasterMute},
1782 {"getMasterMute", "()Z", (void *)android_media_AudioSystem_getMasterMute},
Andy Hungf04b84d2015-12-18 17:33:27 -08001783 {"setMasterMono", "(Z)I", (void *)android_media_AudioSystem_setMasterMono},
1784 {"getMasterMono", "()Z", (void *)android_media_AudioSystem_getMasterMono},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08001785 {"getDevicesForStream", "(I)I", (void *)android_media_AudioSystem_getDevicesForStream},
Glenn Kastenc6c43652012-09-24 17:32:30 -07001786 {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
1787 {"getPrimaryOutputFrameCount", "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001788 {"getOutputLatency", "(I)I", (void *)android_media_AudioSystem_getOutputLatency},
Glenn Kastenfd116ad2013-07-12 17:10:39 -07001789 {"setLowRamDevice", "(Z)I", (void *)android_media_AudioSystem_setLowRamDevice},
Eric Laurentdfb881f2013-07-18 14:41:39 -07001790 {"checkAudioFlinger", "()I", (void *)android_media_AudioSystem_checkAudioFlinger},
Eric Laurentb69681c2014-05-19 19:02:51 -07001791 {"listAudioPorts", "(Ljava/util/ArrayList;[I)I",
1792 (void *)android_media_AudioSystem_listAudioPorts},
1793 {"createAudioPatch", "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
1794 (void *)android_media_AudioSystem_createAudioPatch},
1795 {"releaseAudioPatch", "(Landroid/media/AudioPatch;)I",
1796 (void *)android_media_AudioSystem_releaseAudioPatch},
1797 {"listAudioPatches", "(Ljava/util/ArrayList;[I)I",
1798 (void *)android_media_AudioSystem_listAudioPatches},
Eric Laurent3a241992014-05-19 19:33:26 -07001799 {"setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
1800 (void *)android_media_AudioSystem_setAudioPortConfig},
Eric Laurentb634e1b2014-08-01 14:44:46 -07001801 {"getAudioHwSyncForSession", "(I)I",
1802 (void *)android_media_AudioSystem_getAudioHwSyncForSession},
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001803 {"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
1804 (void *)android_media_AudioSystem_registerPolicyMixes},
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07001805 {"native_register_dynamic_policy_callback", "()V",
1806 (void *)android_media_AudioSystem_registerDynPolicyCallback},
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08001807 {"native_register_recording_callback", "()V",
1808 (void *)android_media_AudioSystem_registerRecordingCallback},
Eric Laurent0867bed2015-05-20 14:49:08 -07001809 {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001810};
1811
Eric Laurentb69681c2014-05-19 19:02:51 -07001812
Daniel Micay76f6a862015-09-19 17:31:01 -04001813static const JNINativeMethod gEventHandlerMethods[] = {
Eric Laurent700e7342014-05-02 18:33:15 -07001814 {"native_setup",
1815 "(Ljava/lang/Object;)V",
1816 (void *)android_media_AudioSystem_eventHandlerSetup},
1817 {"native_finalize",
1818 "()V",
1819 (void *)android_media_AudioSystem_eventHandlerFinalize},
1820};
1821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822int register_android_media_AudioSystem(JNIEnv *env)
1823{
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001824 jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
1825 gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
1826 gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
Eric Laurent09378972014-12-10 10:42:08 -08001827 gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass, "toArray", "()[Ljava/lang/Object;");
Eric Laurentb69681c2014-05-19 19:02:51 -07001828
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001829 jclass audioHandleClass = FindClassOrDie(env, "android/media/AudioHandle");
1830 gAudioHandleClass = MakeGlobalRefOrDie(env, audioHandleClass);
1831 gAudioHandleCstor = GetMethodIDOrDie(env, audioHandleClass, "<init>", "(I)V");
1832 gAudioHandleFields.mId = GetFieldIDOrDie(env, audioHandleClass, "mId", "I");
Eric Laurentb69681c2014-05-19 19:02:51 -07001833
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001834 jclass audioPortClass = FindClassOrDie(env, "android/media/AudioPort");
1835 gAudioPortClass = MakeGlobalRefOrDie(env, audioPortClass);
1836 gAudioPortCstor = GetMethodIDOrDie(env, audioPortClass, "<init>",
Paul McLeanf29e5f32015-06-15 10:19:22 -07001837 "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001838 gAudioPortFields.mHandle = GetFieldIDOrDie(env, audioPortClass, "mHandle",
Eric Laurentb69681c2014-05-19 19:02:51 -07001839 "Landroid/media/AudioHandle;");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001840 gAudioPortFields.mRole = GetFieldIDOrDie(env, audioPortClass, "mRole", "I");
1841 gAudioPortFields.mGains = GetFieldIDOrDie(env, audioPortClass, "mGains",
Eric Laurentb69681c2014-05-19 19:02:51 -07001842 "[Landroid/media/AudioGain;");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001843 gAudioPortFields.mActiveConfig = GetFieldIDOrDie(env, audioPortClass, "mActiveConfig",
1844 "Landroid/media/AudioPortConfig;");
Eric Laurentb69681c2014-05-19 19:02:51 -07001845
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001846 jclass audioPortConfigClass = FindClassOrDie(env, "android/media/AudioPortConfig");
1847 gAudioPortConfigClass = MakeGlobalRefOrDie(env, audioPortConfigClass);
1848 gAudioPortConfigCstor = GetMethodIDOrDie(env, audioPortConfigClass, "<init>",
1849 "(Landroid/media/AudioPort;IIILandroid/media/AudioGainConfig;)V");
1850 gAudioPortConfigFields.mPort = GetFieldIDOrDie(env, audioPortConfigClass, "mPort",
Eric Laurentb69681c2014-05-19 19:02:51 -07001851 "Landroid/media/AudioPort;");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001852 gAudioPortConfigFields.mSamplingRate = GetFieldIDOrDie(env, audioPortConfigClass,
Eric Laurentb69681c2014-05-19 19:02:51 -07001853 "mSamplingRate", "I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001854 gAudioPortConfigFields.mChannelMask = GetFieldIDOrDie(env, audioPortConfigClass,
Eric Laurentb69681c2014-05-19 19:02:51 -07001855 "mChannelMask", "I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001856 gAudioPortConfigFields.mFormat = GetFieldIDOrDie(env, audioPortConfigClass, "mFormat", "I");
1857 gAudioPortConfigFields.mGain = GetFieldIDOrDie(env, audioPortConfigClass, "mGain",
Eric Laurentb69681c2014-05-19 19:02:51 -07001858 "Landroid/media/AudioGainConfig;");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001859 gAudioPortConfigFields.mConfigMask = GetFieldIDOrDie(env, audioPortConfigClass, "mConfigMask",
1860 "I");
Eric Laurentb69681c2014-05-19 19:02:51 -07001861
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001862 jclass audioDevicePortConfigClass = FindClassOrDie(env, "android/media/AudioDevicePortConfig");
1863 gAudioDevicePortConfigClass = MakeGlobalRefOrDie(env, audioDevicePortConfigClass);
1864 gAudioDevicePortConfigCstor = GetMethodIDOrDie(env, audioDevicePortConfigClass, "<init>",
1865 "(Landroid/media/AudioDevicePort;IIILandroid/media/AudioGainConfig;)V");
Eric Laurentb69681c2014-05-19 19:02:51 -07001866
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001867 jclass audioMixPortConfigClass = FindClassOrDie(env, "android/media/AudioMixPortConfig");
1868 gAudioMixPortConfigClass = MakeGlobalRefOrDie(env, audioMixPortConfigClass);
1869 gAudioMixPortConfigCstor = GetMethodIDOrDie(env, audioMixPortConfigClass, "<init>",
1870 "(Landroid/media/AudioMixPort;IIILandroid/media/AudioGainConfig;)V");
Eric Laurentb69681c2014-05-19 19:02:51 -07001871
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001872 jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort");
1873 gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass);
1874 gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>",
Paul McLeanf29e5f32015-06-15 10:19:22 -07001875 "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V");
Eric Laurentb69681c2014-05-19 19:02:51 -07001876
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001877 jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
1878 gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
1879 gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
Paul McLeanf29e5f32015-06-15 10:19:22 -07001880 "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V");
Eric Laurentb69681c2014-05-19 19:02:51 -07001881
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001882 jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
1883 gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
1884 gAudioGainCstor = GetMethodIDOrDie(env, audioGainClass, "<init>", "(IIIIIIIII)V");
Eric Laurentb69681c2014-05-19 19:02:51 -07001885
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001886 jclass audioGainConfigClass = FindClassOrDie(env, "android/media/AudioGainConfig");
1887 gAudioGainConfigClass = MakeGlobalRefOrDie(env, audioGainConfigClass);
1888 gAudioGainConfigCstor = GetMethodIDOrDie(env, audioGainConfigClass, "<init>",
Eric Laurentb69681c2014-05-19 19:02:51 -07001889 "(ILandroid/media/AudioGain;II[II)V");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001890 gAudioGainConfigFields.mIndex = GetFieldIDOrDie(env, gAudioGainConfigClass, "mIndex", "I");
1891 gAudioGainConfigFields.mMode = GetFieldIDOrDie(env, audioGainConfigClass, "mMode", "I");
1892 gAudioGainConfigFields.mChannelMask = GetFieldIDOrDie(env, audioGainConfigClass, "mChannelMask",
Eric Laurentb69681c2014-05-19 19:02:51 -07001893 "I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001894 gAudioGainConfigFields.mValues = GetFieldIDOrDie(env, audioGainConfigClass, "mValues", "[I");
1895 gAudioGainConfigFields.mRampDurationMs = GetFieldIDOrDie(env, audioGainConfigClass,
Eric Laurentb69681c2014-05-19 19:02:51 -07001896 "mRampDurationMs", "I");
1897
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001898 jclass audioPatchClass = FindClassOrDie(env, "android/media/AudioPatch");
1899 gAudioPatchClass = MakeGlobalRefOrDie(env, audioPatchClass);
1900 gAudioPatchCstor = GetMethodIDOrDie(env, audioPatchClass, "<init>",
Eric Laurentb69681c2014-05-19 19:02:51 -07001901"(Landroid/media/AudioHandle;[Landroid/media/AudioPortConfig;[Landroid/media/AudioPortConfig;)V");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001902 gAudioPatchFields.mHandle = GetFieldIDOrDie(env, audioPatchClass, "mHandle",
Eric Laurentb69681c2014-05-19 19:02:51 -07001903 "Landroid/media/AudioHandle;");
1904
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001905 jclass eventHandlerClass = FindClassOrDie(env, kEventHandlerClassPathName);
Eric Laurent2615afb2015-03-25 14:51:08 -07001906 gAudioPortEventHandlerMethods.postEventFromNative = GetStaticMethodIDOrDie(
1907 env, eventHandlerClass, "postEventFromNative",
1908 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1909 gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
1910 eventHandlerClass, "mJniCallback", "J");
Eric Laurent700e7342014-05-02 18:33:15 -07001911
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08001912 gAudioPolicyEventHandlerMethods.postDynPolicyEventFromNative =
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07001913 GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
1914 "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08001915 gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
1916 GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
Jean-Michel Trivi33fd8162016-02-22 10:52:41 -08001917 "recordingCallbackFromNative", "(III[I)V");
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07001918
Eric Laurent09378972014-12-10 10:42:08 -08001919 jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
1920 gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
1921 gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001922 "Landroid/media/audiopolicy/AudioMixingRule;");
Eric Laurent09378972014-12-10 10:42:08 -08001923 gAudioMixFields.mFormat = GetFieldIDOrDie(env, audioMixClass, "mFormat",
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001924 "Landroid/media/AudioFormat;");
Eric Laurent09378972014-12-10 10:42:08 -08001925 gAudioMixFields.mRouteFlags = GetFieldIDOrDie(env, audioMixClass, "mRouteFlags", "I");
Jean-Michel Trivi4ad39882016-03-14 18:46:41 -07001926 gAudioMixFields.mDeviceType = GetFieldIDOrDie(env, audioMixClass, "mDeviceSystemType", "I");
1927 gAudioMixFields.mDeviceAddress = GetFieldIDOrDie(env, audioMixClass, "mDeviceAddress",
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001928 "Ljava/lang/String;");
Eric Laurent09378972014-12-10 10:42:08 -08001929 gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07001930 gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001931
Eric Laurent09378972014-12-10 10:42:08 -08001932 jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
1933 gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
1934 gAudioFormatFields.mEncoding = GetFieldIDOrDie(env, audioFormatClass, "mEncoding", "I");
1935 gAudioFormatFields.mSampleRate = GetFieldIDOrDie(env, audioFormatClass, "mSampleRate", "I");
1936 gAudioFormatFields.mChannelMask = GetFieldIDOrDie(env, audioFormatClass, "mChannelMask", "I");
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001937
Eric Laurent09378972014-12-10 10:42:08 -08001938 jclass audioMixingRuleClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule");
1939 gAudioMixingRuleClass = MakeGlobalRefOrDie(env, audioMixingRuleClass);
1940 gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001941 "Ljava/util/ArrayList;");
1942
Jean-Michel Triviba6b4b42016-02-10 14:26:35 -08001943 jclass audioMixMatchCriterionClass =
1944 FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion");
1945 gAudioMixMatchCriterionClass = MakeGlobalRefOrDie(env,audioMixMatchCriterionClass);
1946 gAudioMixMatchCriterionFields.mAttr = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mAttr",
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001947 "Landroid/media/AudioAttributes;");
Jean-Michel Triviba6b4b42016-02-10 14:26:35 -08001948 gAudioMixMatchCriterionFields.mIntProp = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mIntProp",
1949 "I");
1950 gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001951 "I");
1952
Eric Laurent09378972014-12-10 10:42:08 -08001953 jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
1954 gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
1955 gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
1956 gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08001957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
Glenn Kasten18db49a2012-03-12 16:29:55 -07001959
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001960 RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1961 return RegisterMethodsOrDie(env, kEventHandlerClassPathName, gEventHandlerMethods,
1962 NELEM(gEventHandlerMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963}