1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 //#define LOG_NDEBUG 0
17
18 #define LOG_TAG "AudioTrack-JNI"
19
20 #include "android_media_AudioTrack.h"
21
22 #include <nativehelper/JNIHelp.h>
23 #include "core_jni_helpers.h"
24
25 #include <utils/Log.h>
26 #include <media/AudioParameter.h>
27 #include <media/AudioSystem.h>
28 #include <media/AudioTrack.h>
29
30 #include <android-base/macros.h>
31 #include <binder/MemoryHeapBase.h>
32 #include <binder/MemoryBase.h>
33
34 #include "android_media_AudioAttributes.h"
35 #include "android_media_AudioErrors.h"
36 #include "android_media_AudioFormat.h"
37 #include "android_media_AudioTrackCallback.h"
38 #include "android_media_DeviceCallback.h"
39 #include "android_media_MediaMetricsJNI.h"
40 #include "android_media_PlaybackParams.h"
41 #include "android_media_VolumeShaper.h"
42
43 #include <cinttypes>
44
45 // ----------------------------------------------------------------------------
46
47 using namespace android;
48
49 using ::android::media::VolumeShaper;
50
51 // ----------------------------------------------------------------------------
52 static const char* const kClassPathName = "android/media/AudioTrack";
53
54 struct audio_track_fields_t {
55 // these fields provide access from C++ to the...
56 jmethodID postNativeEventInJava; //... event post callback method
57 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
58 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
59 jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object
60 };
61 static audio_track_fields_t javaAudioTrackFields;
62 static PlaybackParams::fields_t gPlaybackParamsFields;
63 static VolumeShaperHelper::fields_t gVolumeShaperFields;
64
65 struct audiotrack_callback_cookie {
66 jclass audioTrack_class;
67 jobject audioTrack_ref;
68 bool busy;
69 Condition cond;
70 bool isOffload;
71 };
72
73 // keep these values in sync with AudioTrack.java
74 #define MODE_STATIC 0
75 #define MODE_STREAM 1
76
77 // ----------------------------------------------------------------------------
78 class AudioTrackJniStorage {
79 public:
80 sp<MemoryHeapBase> mMemHeap;
81 sp<MemoryBase> mMemBase;
82 audiotrack_callback_cookie mCallbackData{};
83 sp<JNIDeviceCallback> mDeviceCallback;
84 sp<JNIAudioTrackCallback> mAudioTrackCallback;
85
allocSharedMem(int sizeInBytes)86 bool allocSharedMem(int sizeInBytes) {
87 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
88 if (mMemHeap->getHeapID() < 0) {
89 return false;
90 }
91 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
92 return true;
93 }
94 };
95
96 class TunerConfigurationHelper {
97 JNIEnv *const mEnv;
98 jobject const mTunerConfiguration;
99
100 struct Ids {
IdsTunerConfigurationHelper::Ids101 Ids(JNIEnv *env)
102 : mClass(FindClassOrDie(env, "android/media/AudioTrack$TunerConfiguration")),
103 mContentId(GetFieldIDOrDie(env, mClass, "mContentId", "I")),
104 mSyncId(GetFieldIDOrDie(env, mClass, "mSyncId", "I")) {}
105 const jclass mClass;
106 const jfieldID mContentId;
107 const jfieldID mSyncId;
108 };
109
getIds(JNIEnv * env)110 static const Ids &getIds(JNIEnv *env) {
111 // Meyer's singleton, initializes first time control passes through
112 // declaration in a block and is thread-safe per ISO/IEC 14882:2011 6.7.4.
113 static Ids ids(env);
114 return ids;
115 }
116
117 public:
TunerConfigurationHelper(JNIEnv * env,jobject tunerConfiguration)118 TunerConfigurationHelper(JNIEnv *env, jobject tunerConfiguration)
119 : mEnv(env), mTunerConfiguration(tunerConfiguration) {}
120
getContentId() const121 int32_t getContentId() const {
122 if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
123 const Ids &ids = getIds(mEnv);
124 return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mContentId);
125 }
126
getSyncId() const127 int32_t getSyncId() const {
128 if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
129 const Ids &ids = getIds(mEnv);
130 return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mSyncId);
131 }
132
133 // optional check to confirm class and field ids can be found.
initCheckOrDie(JNIEnv * env)134 static void initCheckOrDie(JNIEnv *env) { (void)getIds(env); }
135 };
136
137 static Mutex sLock;
138 static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
139
140 // ----------------------------------------------------------------------------
141 #define DEFAULT_OUTPUT_SAMPLE_RATE 44100
142
143 #define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM (-16)
144 #define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK (-17)
145 #define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT (-18)
146 #define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE (-19)
147 #define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED (-20)
148
149 // ----------------------------------------------------------------------------
audioCallback(int event,void * user,void * info)150 static void audioCallback(int event, void* user, void *info) {
151
152 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
153 {
154 Mutex::Autolock l(sLock);
155 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
156 return;
157 }
158 callbackInfo->busy = true;
159 }
160
161 // used as default argument when event callback doesn't have any, or number of
162 // frames for EVENT_CAN_WRITE_MORE_DATA
163 int arg = 0;
164 bool postEvent = false;
165 switch (event) {
166 // Offload only events
167 case AudioTrack::EVENT_CAN_WRITE_MORE_DATA:
168 // this event will read the info return parameter of the callback:
169 // for JNI offload, use the returned size to indicate:
170 // 1/ no data is returned through callback, as it's all done through write()
171 // 2/ do not wait as AudioTrack does when it receives 0 bytes
172 if (callbackInfo->isOffload) {
173 AudioTrack::Buffer* pBuffer = (AudioTrack::Buffer*) info;
174 const size_t availableForWrite = pBuffer->size;
175 arg = availableForWrite > INT32_MAX ? INT32_MAX : (int) availableForWrite;
176 pBuffer->size = 0;
177 }
178 FALLTHROUGH_INTENDED;
179 case AudioTrack::EVENT_STREAM_END:
180 case AudioTrack::EVENT_NEW_IAUDIOTRACK: // a.k.a. tear down
181 if (callbackInfo->isOffload) {
182 postEvent = true;
183 }
184 break;
185
186 // PCM and offload events
187 case AudioTrack::EVENT_MARKER:
188 case AudioTrack::EVENT_NEW_POS:
189 postEvent = true;
190 break;
191 default:
192 // event will not be posted
193 break;
194 }
195
196 if (postEvent) {
197 JNIEnv *env = AndroidRuntime::getJNIEnv();
198 if (env != NULL) {
199 env->CallStaticVoidMethod(
200 callbackInfo->audioTrack_class,
201 javaAudioTrackFields.postNativeEventInJava,
202 callbackInfo->audioTrack_ref, event, arg, 0, NULL);
203 if (env->ExceptionCheck()) {
204 env->ExceptionDescribe();
205 env->ExceptionClear();
206 }
207 }
208 }
209
210 {
211 Mutex::Autolock l(sLock);
212 callbackInfo->busy = false;
213 callbackInfo->cond.broadcast();
214 }
215 }
216
217
218 // ----------------------------------------------------------------------------
getAudioTrack(JNIEnv * env,jobject thiz)219 static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
220 {
221 Mutex::Autolock l(sLock);
222 AudioTrack* const at =
223 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
224 return sp<AudioTrack>(at);
225 }
226
setAudioTrack(JNIEnv * env,jobject thiz,const sp<AudioTrack> & at)227 static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
228 {
229 Mutex::Autolock l(sLock);
230 sp<AudioTrack> old =
231 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
232 if (at.get()) {
233 at->incStrong((void*)setAudioTrack);
234 }
235 if (old != 0) {
236 old->decStrong((void*)setAudioTrack);
237 }
238 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
239 return old;
240 }
241
242 // ----------------------------------------------------------------------------
android_media_AudioTrack_getAudioTrack(JNIEnv * env,jobject audioTrackObj)243 sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
244 return getAudioTrack(env, audioTrackObj);
245 }
246
247 // ----------------------------------------------------------------------------
android_media_AudioTrack_setup(JNIEnv * env,jobject thiz,jobject weak_this,jobject jaa,jintArray jSampleRate,jint channelPositionMask,jint channelIndexMask,jint audioFormat,jint buffSizeInBytes,jint memoryMode,jintArray jSession,jlong nativeAudioTrack,jboolean offload,jint encapsulationMode,jobject tunerConfiguration)248 static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
249 jobject jaa, jintArray jSampleRate,
250 jint channelPositionMask, jint channelIndexMask,
251 jint audioFormat, jint buffSizeInBytes, jint memoryMode,
252 jintArray jSession, jlong nativeAudioTrack,
253 jboolean offload, jint encapsulationMode,
254 jobject tunerConfiguration) {
255 ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
256 " nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p",
257 jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
258 nativeAudioTrack, offload, encapsulationMode, tunerConfiguration);
259
260 if (jSession == NULL) {
261 ALOGE("Error creating AudioTrack: invalid session ID pointer");
262 return (jint) AUDIO_JAVA_ERROR;
263 }
264
265 // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
266 if (tunerConfiguration != nullptr) {
267 const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
268 ALOGE("Error creating AudioTrack: unsupported tuner contentId:%d syncId:%d",
269 tunerHelper.getContentId(), tunerHelper.getSyncId());
270 return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
271 }
272 // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
273 if (encapsulationMode != 0 /* ENCAPSULATION_MODE_NONE */) {
274 ALOGE("Error creating AudioTrack: unsupported encapsulationMode %d", encapsulationMode);
275 return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
276 }
277
278 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
279 if (nSession == NULL) {
280 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
281 return (jint) AUDIO_JAVA_ERROR;
282 }
283 audio_session_t sessionId = (audio_session_t) nSession[0];
284 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
285 nSession = NULL;
286
287 AudioTrackJniStorage* lpJniStorage = NULL;
288
289 jclass clazz = env->GetObjectClass(thiz);
290 if (clazz == NULL) {
291 ALOGE("Can't find %s when setting up callback.", kClassPathName);
292 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
293 }
294
295 // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
296 sp<AudioTrack> lpTrack;
297 if (nativeAudioTrack == 0) {
298 if (jaa == 0) {
299 ALOGE("Error creating AudioTrack: invalid audio attributes");
300 return (jint) AUDIO_JAVA_ERROR;
301 }
302
303 if (jSampleRate == 0) {
304 ALOGE("Error creating AudioTrack: invalid sample rates");
305 return (jint) AUDIO_JAVA_ERROR;
306 }
307
308 int* sampleRates = env->GetIntArrayElements(jSampleRate, NULL);
309 int sampleRateInHertz = sampleRates[0];
310 env->ReleaseIntArrayElements(jSampleRate, sampleRates, JNI_ABORT);
311
312 // Invalid channel representations are caught by !audio_is_output_channel() below.
313 audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
314 channelPositionMask, channelIndexMask);
315 if (!audio_is_output_channel(nativeChannelMask)) {
316 ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
317 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
318 }
319
320 uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
321
322 // check the format.
323 // This function was called from Java, so we compare the format against the Java constants
324 audio_format_t format = audioFormatToNative(audioFormat);
325 if (format == AUDIO_FORMAT_INVALID) {
326 ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
327 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
328 }
329
330 // compute the frame count
331 size_t frameCount;
332 if (audio_has_proportional_frames(format)) {
333 const size_t bytesPerSample = audio_bytes_per_sample(format);
334 frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
335 } else {
336 frameCount = buffSizeInBytes;
337 }
338
339 // create the native AudioTrack object
340 lpTrack = new AudioTrack();
341
342 // read the AudioAttributes values
343 auto paa = JNIAudioAttributeHelper::makeUnique();
344 jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
345 if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
346 return jStatus;
347 }
348 ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
349 paa->usage, paa->content_type, paa->flags, paa->tags);
350
351 // initialize the callback information:
352 // this data will be passed with every AudioTrack callback
353 lpJniStorage = new AudioTrackJniStorage();
354 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
355 // we use a weak reference so the AudioTrack object can be garbage collected.
356 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
357 lpJniStorage->mCallbackData.isOffload = offload;
358 lpJniStorage->mCallbackData.busy = false;
359
360 audio_offload_info_t offloadInfo;
361 if (offload == JNI_TRUE) {
362 offloadInfo = AUDIO_INFO_INITIALIZER;
363 offloadInfo.format = format;
364 offloadInfo.sample_rate = sampleRateInHertz;
365 offloadInfo.channel_mask = nativeChannelMask;
366 offloadInfo.has_video = false;
367 offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
368 }
369
370 // initialize the native AudioTrack object
371 status_t status = NO_ERROR;
372 switch (memoryMode) {
373 case MODE_STREAM:
374 status = lpTrack->set(
375 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
376 sampleRateInHertz,
377 format,// word length, PCM
378 nativeChannelMask,
379 offload ? 0 : frameCount,
380 offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_NONE,
381 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
382 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
383 0,// shared mem
384 true,// thread can call Java
385 sessionId,// audio session ID
386 offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC,
387 offload ? &offloadInfo : NULL,
388 -1, -1, // default uid, pid values
389 paa.get());
390
391 break;
392
393 case MODE_STATIC:
394 // AudioTrack is using shared memory
395
396 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
397 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
398 goto native_init_failure;
399 }
400
401 status = lpTrack->set(
402 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
403 sampleRateInHertz,
404 format,// word length, PCM
405 nativeChannelMask,
406 frameCount,
407 AUDIO_OUTPUT_FLAG_NONE,
408 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
409 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
410 lpJniStorage->mMemBase,// shared mem
411 true,// thread can call Java
412 sessionId,// audio session ID
413 AudioTrack::TRANSFER_SHARED,
414 NULL, // default offloadInfo
415 -1, -1, // default uid, pid values
416 paa.get());
417 break;
418
419 default:
420 ALOGE("Unknown mode %d", memoryMode);
421 goto native_init_failure;
422 }
423
424 if (status != NO_ERROR) {
425 ALOGE("Error %d initializing AudioTrack", status);
426 goto native_init_failure;
427 }
428 // Set caller name so it can be logged in destructor.
429 // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA
430 lpTrack->setCallerName("java");
431 } else { // end if (nativeAudioTrack == 0)
432 lpTrack = (AudioTrack*)nativeAudioTrack;
433 // TODO: We need to find out which members of the Java AudioTrack might
434 // need to be initialized from the Native AudioTrack
435 // these are directly returned from getters:
436 // mSampleRate
437 // mAudioFormat
438 // mStreamType
439 // mChannelConfiguration
440 // mChannelCount
441 // mState (?)
442 // mPlayState (?)
443 // these may be used internally (Java AudioTrack.audioParamCheck():
444 // mChannelMask
445 // mChannelIndexMask
446 // mDataLoadMode
447
448 // initialize the callback information:
449 // this data will be passed with every AudioTrack callback
450 lpJniStorage = new AudioTrackJniStorage();
451 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
452 // we use a weak reference so the AudioTrack object can be garbage collected.
453 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
454 lpJniStorage->mCallbackData.busy = false;
455 }
456 lpJniStorage->mAudioTrackCallback =
457 new JNIAudioTrackCallback(env, thiz, lpJniStorage->mCallbackData.audioTrack_ref,
458 javaAudioTrackFields.postNativeEventInJava);
459 lpTrack->setAudioTrackCallback(lpJniStorage->mAudioTrackCallback);
460
461 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
462 if (nSession == NULL) {
463 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
464 goto native_init_failure;
465 }
466 // read the audio session ID back from AudioTrack in case we create a new session
467 nSession[0] = lpTrack->getSessionId();
468 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
469 nSession = NULL;
470
471 {
472 const jint elements[1] = { (jint) lpTrack->getSampleRate() };
473 env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
474 }
475
476 { // scope for the lock
477 Mutex::Autolock l(sLock);
478 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
479 }
480 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
481 // of the Java object (in mNativeTrackInJavaObj)
482 setAudioTrack(env, thiz, lpTrack);
483
484 // save the JNI resources so we can free them later
485 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
486 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
487
488 // since we had audio attributes, the stream type was derived from them during the
489 // creation of the native AudioTrack: push the same value to the Java object
490 env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
491
492 return (jint) AUDIO_JAVA_SUCCESS;
493
494 // failures:
495 native_init_failure:
496 if (nSession != NULL) {
497 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
498 }
499 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
500 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
501 delete lpJniStorage;
502 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
503
504 // lpTrack goes out of scope, so reference count drops to zero
505 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
506 }
507
508 // ----------------------------------------------------------------------------
509 static jboolean
android_media_AudioTrack_is_direct_output_supported(JNIEnv * env,jobject thiz,jint encoding,jint sampleRate,jint channelMask,jint channelIndexMask,jint contentType,jint usage,jint flags)510 android_media_AudioTrack_is_direct_output_supported(JNIEnv *env, jobject thiz,
511 jint encoding, jint sampleRate,
512 jint channelMask, jint channelIndexMask,
513 jint contentType, jint usage, jint flags) {
514 audio_config_base_t config = {};
515 audio_attributes_t attributes = {};
516 config.format = static_cast<audio_format_t>(audioFormatToNative(encoding));
517 config.sample_rate = static_cast<uint32_t>(sampleRate);
518 config.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
519 attributes.content_type = static_cast<audio_content_type_t>(contentType);
520 attributes.usage = static_cast<audio_usage_t>(usage);
521 attributes.flags = static_cast<audio_flags_mask_t>(flags);
522 // ignore source and tags attributes as they don't affect querying whether output is supported
523 return AudioTrack::isDirectOutputSupported(config, attributes);
524 }
525
526 // ----------------------------------------------------------------------------
527 static void
android_media_AudioTrack_start(JNIEnv * env,jobject thiz)528 android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
529 {
530 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
531 if (lpTrack == NULL) {
532 jniThrowException(env, "java/lang/IllegalStateException",
533 "Unable to retrieve AudioTrack pointer for start()");
534 return;
535 }
536
537 lpTrack->start();
538 }
539
540
541 // ----------------------------------------------------------------------------
542 static void
android_media_AudioTrack_stop(JNIEnv * env,jobject thiz)543 android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
544 {
545 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
546 if (lpTrack == NULL) {
547 jniThrowException(env, "java/lang/IllegalStateException",
548 "Unable to retrieve AudioTrack pointer for stop()");
549 return;
550 }
551
552 lpTrack->stop();
553 }
554
555
556 // ----------------------------------------------------------------------------
557 static void
android_media_AudioTrack_pause(JNIEnv * env,jobject thiz)558 android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
559 {
560 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
561 if (lpTrack == NULL) {
562 jniThrowException(env, "java/lang/IllegalStateException",
563 "Unable to retrieve AudioTrack pointer for pause()");
564 return;
565 }
566
567 lpTrack->pause();
568 }
569
570
571 // ----------------------------------------------------------------------------
572 static void
android_media_AudioTrack_flush(JNIEnv * env,jobject thiz)573 android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
574 {
575 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
576 if (lpTrack == NULL) {
577 jniThrowException(env, "java/lang/IllegalStateException",
578 "Unable to retrieve AudioTrack pointer for flush()");
579 return;
580 }
581
582 lpTrack->flush();
583 }
584
585 // ----------------------------------------------------------------------------
586 static void
android_media_AudioTrack_set_volume(JNIEnv * env,jobject thiz,jfloat leftVol,jfloat rightVol)587 android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
588 {
589 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
590 if (lpTrack == NULL) {
591 jniThrowException(env, "java/lang/IllegalStateException",
592 "Unable to retrieve AudioTrack pointer for setVolume()");
593 return;
594 }
595
596 lpTrack->setVolume(leftVol, rightVol);
597 }
598
599 // ----------------------------------------------------------------------------
600
601 #define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
android_media_AudioTrack_release(JNIEnv * env,jobject thiz)602 static void android_media_AudioTrack_release(JNIEnv *env, jobject thiz) {
603 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
604 if (lpTrack == NULL) {
605 return;
606 }
607 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
608
609 // delete the JNI data
610 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
611 thiz, javaAudioTrackFields.jniData);
612 // reset the native resources in the Java object so any attempt to access
613 // them after a call to release fails.
614 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
615
616 if (pJniStorage) {
617 Mutex::Autolock l(sLock);
618 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
619 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
620 while (lpCookie->busy) {
621 if (lpCookie->cond.waitRelative(sLock,
622 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
623 NO_ERROR) {
624 break;
625 }
626 }
627 sAudioTrackCallBackCookies.remove(lpCookie);
628 // delete global refs created in native_setup
629 env->DeleteGlobalRef(lpCookie->audioTrack_class);
630 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
631 delete pJniStorage;
632 }
633 }
634
635
636 // ----------------------------------------------------------------------------
android_media_AudioTrack_finalize(JNIEnv * env,jobject thiz)637 static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
638 //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
639 android_media_AudioTrack_release(env, thiz);
640 }
641
642 // overloaded JNI array helper functions (same as in android_media_AudioRecord)
643 static inline
envGetArrayElements(JNIEnv * env,jbyteArray array,jboolean * isCopy)644 jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
645 return env->GetByteArrayElements(array, isCopy);
646 }
647
648 static inline
envReleaseArrayElements(JNIEnv * env,jbyteArray array,jbyte * elems,jint mode)649 void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
650 env->ReleaseByteArrayElements(array, elems, mode);
651 }
652
653 static inline
envGetArrayElements(JNIEnv * env,jshortArray array,jboolean * isCopy)654 jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
655 return env->GetShortArrayElements(array, isCopy);
656 }
657
658 static inline
envReleaseArrayElements(JNIEnv * env,jshortArray array,jshort * elems,jint mode)659 void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
660 env->ReleaseShortArrayElements(array, elems, mode);
661 }
662
663 static inline
envGetArrayElements(JNIEnv * env,jfloatArray array,jboolean * isCopy)664 jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
665 return env->GetFloatArrayElements(array, isCopy);
666 }
667
668 static inline
envReleaseArrayElements(JNIEnv * env,jfloatArray array,jfloat * elems,jint mode)669 void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
670 env->ReleaseFloatArrayElements(array, elems, mode);
671 }
672
673 static inline
interpretWriteSizeError(ssize_t writeSize)674 jint interpretWriteSizeError(ssize_t writeSize) {
675 if (writeSize == WOULD_BLOCK) {
676 return (jint)0;
677 } else if (writeSize == NO_INIT) {
678 return AUDIO_JAVA_DEAD_OBJECT;
679 } else {
680 ALOGE("Error %zd during AudioTrack native read", writeSize);
681 return nativeToJavaStatus(writeSize);
682 }
683 }
684
685 // ----------------------------------------------------------------------------
686 template <typename T>
writeToTrack(const sp<AudioTrack> & track,jint audioFormat,const T * data,jint offsetInSamples,jint sizeInSamples,bool blocking)687 static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
688 jint offsetInSamples, jint sizeInSamples, bool blocking) {
689 // give the data to the native AudioTrack object (the data starts at the offset)
690 ssize_t written = 0;
691 // regular write() or copy the data to the AudioTrack's shared memory?
692 size_t sizeInBytes = sizeInSamples * sizeof(T);
693 if (track->sharedBuffer() == 0) {
694 written = track->write(data + offsetInSamples, sizeInBytes, blocking);
695 // for compatibility with earlier behavior of write(), return 0 in this case
696 if (written == (ssize_t) WOULD_BLOCK) {
697 written = 0;
698 }
699 } else {
700 // writing to shared memory, check for capacity
701 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
702 sizeInBytes = track->sharedBuffer()->size();
703 }
704 memcpy(track->sharedBuffer()->unsecurePointer(), data + offsetInSamples, sizeInBytes);
705 written = sizeInBytes;
706 }
707 if (written >= 0) {
708 return written / sizeof(T);
709 }
710 return interpretWriteSizeError(written);
711 }
712
713 // ----------------------------------------------------------------------------
714 template <typename T>
android_media_AudioTrack_writeArray(JNIEnv * env,jobject thiz,T javaAudioData,jint offsetInSamples,jint sizeInSamples,jint javaAudioFormat,jboolean isWriteBlocking)715 static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
716 T javaAudioData,
717 jint offsetInSamples, jint sizeInSamples,
718 jint javaAudioFormat,
719 jboolean isWriteBlocking) {
720 //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
721 // offsetInSamples, sizeInSamples);
722 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
723 if (lpTrack == NULL) {
724 jniThrowException(env, "java/lang/IllegalStateException",
725 "Unable to retrieve AudioTrack pointer for write()");
726 return (jint)AUDIO_JAVA_INVALID_OPERATION;
727 }
728
729 if (javaAudioData == NULL) {
730 ALOGE("NULL java array of audio data to play");
731 return (jint)AUDIO_JAVA_BAD_VALUE;
732 }
733
734 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
735 // a way that it becomes much more efficient. When doing so, we will have to prevent the
736 // AudioSystem callback to be called while in critical section (in case of media server
737 // process crash for instance)
738
739 // get the pointer for the audio data from the java array
740 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
741 if (cAudioData == NULL) {
742 ALOGE("Error retrieving source of audio data to play");
743 return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
744 }
745
746 jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
747 offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
748
749 envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
750
751 //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
752 // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
753 return samplesWritten;
754 }
755
756 // ----------------------------------------------------------------------------
android_media_AudioTrack_write_native_bytes(JNIEnv * env,jobject thiz,jobject javaByteBuffer,jint byteOffset,jint sizeInBytes,jint javaAudioFormat,jboolean isWriteBlocking)757 static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
758 jobject javaByteBuffer, jint byteOffset, jint sizeInBytes,
759 jint javaAudioFormat, jboolean isWriteBlocking) {
760 //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
761 // offsetInBytes, sizeInBytes);
762 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
763 if (lpTrack == NULL) {
764 jniThrowException(env, "java/lang/IllegalStateException",
765 "Unable to retrieve AudioTrack pointer for write()");
766 return (jint)AUDIO_JAVA_INVALID_OPERATION;
767 }
768
769 const jbyte* bytes =
770 reinterpret_cast<const jbyte*>(env->GetDirectBufferAddress(javaByteBuffer));
771 if (bytes == NULL) {
772 ALOGE("Error retrieving source of audio data to play, can't play");
773 return (jint)AUDIO_JAVA_BAD_VALUE;
774 }
775
776 jint written = writeToTrack(lpTrack, javaAudioFormat, bytes, byteOffset,
777 sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
778
779 return written;
780 }
781
782 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_buffer_size_frames(JNIEnv * env,jobject thiz)783 static jint android_media_AudioTrack_get_buffer_size_frames(JNIEnv *env, jobject thiz) {
784 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
785 if (lpTrack == NULL) {
786 jniThrowException(env, "java/lang/IllegalStateException",
787 "Unable to retrieve AudioTrack pointer for getBufferSizeInFrames()");
788 return (jint)AUDIO_JAVA_ERROR;
789 }
790
791 ssize_t result = lpTrack->getBufferSizeInFrames();
792 if (result < 0) {
793 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
794 "Internal error detected in getBufferSizeInFrames() = %zd", result);
795 return (jint)AUDIO_JAVA_ERROR;
796 }
797 return (jint)result;
798 }
799
800 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_buffer_size_frames(JNIEnv * env,jobject thiz,jint bufferSizeInFrames)801 static jint android_media_AudioTrack_set_buffer_size_frames(JNIEnv *env,
802 jobject thiz, jint bufferSizeInFrames) {
803 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
804 if (lpTrack == NULL) {
805 jniThrowException(env, "java/lang/IllegalStateException",
806 "Unable to retrieve AudioTrack pointer for setBufferSizeInFrames()");
807 return (jint)AUDIO_JAVA_ERROR;
808 }
809 // Value will be coerced into the valid range.
810 // But internal values are unsigned, size_t, so we need to clip
811 // against zero here where it is signed.
812 if (bufferSizeInFrames < 0) {
813 bufferSizeInFrames = 0;
814 }
815 ssize_t result = lpTrack->setBufferSizeInFrames(bufferSizeInFrames);
816 if (result < 0) {
817 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
818 "Internal error detected in setBufferSizeInFrames() = %zd", result);
819 return (jint)AUDIO_JAVA_ERROR;
820 }
821 return (jint)result;
822 }
823
824 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv * env,jobject thiz)825 static jint android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv *env, jobject thiz) {
826 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
827 if (lpTrack == NULL) {
828 jniThrowException(env, "java/lang/IllegalStateException",
829 "Unable to retrieve AudioTrack pointer for getBufferCapacityInFrames()");
830 return (jint)AUDIO_JAVA_ERROR;
831 }
832
833 return lpTrack->frameCount();
834 }
835
836 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_playback_rate(JNIEnv * env,jobject thiz,jint sampleRateInHz)837 static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
838 jint sampleRateInHz) {
839 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
840 if (lpTrack == NULL) {
841 jniThrowException(env, "java/lang/IllegalStateException",
842 "Unable to retrieve AudioTrack pointer for setSampleRate()");
843 return (jint)AUDIO_JAVA_ERROR;
844 }
845 return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
846 }
847
848
849 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_playback_rate(JNIEnv * env,jobject thiz)850 static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
851 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
852 if (lpTrack == NULL) {
853 jniThrowException(env, "java/lang/IllegalStateException",
854 "Unable to retrieve AudioTrack pointer for getSampleRate()");
855 return (jint)AUDIO_JAVA_ERROR;
856 }
857 return (jint) lpTrack->getSampleRate();
858 }
859
860
861 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_playback_params(JNIEnv * env,jobject thiz,jobject params)862 static void android_media_AudioTrack_set_playback_params(JNIEnv *env, jobject thiz,
863 jobject params) {
864 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
865 if (lpTrack == NULL) {
866 jniThrowException(env, "java/lang/IllegalStateException",
867 "AudioTrack not initialized");
868 return;
869 }
870
871 PlaybackParams pbp;
872 pbp.fillFromJobject(env, gPlaybackParamsFields, params);
873
874 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
875 pbp.speedSet, pbp.audioRate.mSpeed,
876 pbp.pitchSet, pbp.audioRate.mPitch,
877 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
878 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
879
880 // to simulate partially set params, we do a read-modify-write.
881 // TODO: pass in the valid set mask into AudioTrack.
882 AudioPlaybackRate rate = lpTrack->getPlaybackRate();
883 bool updatedRate = false;
884 if (pbp.speedSet) {
885 rate.mSpeed = pbp.audioRate.mSpeed;
886 updatedRate = true;
887 }
888 if (pbp.pitchSet) {
889 rate.mPitch = pbp.audioRate.mPitch;
890 updatedRate = true;
891 }
892 if (pbp.audioFallbackModeSet) {
893 rate.mFallbackMode = pbp.audioRate.mFallbackMode;
894 updatedRate = true;
895 }
896 if (pbp.audioStretchModeSet) {
897 rate.mStretchMode = pbp.audioRate.mStretchMode;
898 updatedRate = true;
899 }
900 if (updatedRate) {
901 if (lpTrack->setPlaybackRate(rate) != OK) {
902 jniThrowException(env, "java/lang/IllegalArgumentException",
903 "arguments out of range");
904 }
905 }
906 }
907
908
909 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_playback_params(JNIEnv * env,jobject thiz,jobject params)910 static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env, jobject thiz,
911 jobject params) {
912 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
913 if (lpTrack == NULL) {
914 jniThrowException(env, "java/lang/IllegalStateException",
915 "AudioTrack not initialized");
916 return NULL;
917 }
918
919 PlaybackParams pbs;
920 pbs.audioRate = lpTrack->getPlaybackRate();
921 pbs.speedSet = true;
922 pbs.pitchSet = true;
923 pbs.audioFallbackModeSet = true;
924 pbs.audioStretchModeSet = true;
925 return pbs.asJobject(env, gPlaybackParamsFields);
926 }
927
928
929 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_marker_pos(JNIEnv * env,jobject thiz,jint markerPos)930 static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
931 jint markerPos) {
932 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
933 if (lpTrack == NULL) {
934 jniThrowException(env, "java/lang/IllegalStateException",
935 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
936 return (jint)AUDIO_JAVA_ERROR;
937 }
938 return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
939 }
940
941
942 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_marker_pos(JNIEnv * env,jobject thiz)943 static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
944 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
945 uint32_t markerPos = 0;
946
947 if (lpTrack == NULL) {
948 jniThrowException(env, "java/lang/IllegalStateException",
949 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
950 return (jint)AUDIO_JAVA_ERROR;
951 }
952 lpTrack->getMarkerPosition(&markerPos);
953 return (jint)markerPos;
954 }
955
956
957 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_pos_update_period(JNIEnv * env,jobject thiz,jint period)958 static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
959 jint period) {
960 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
961 if (lpTrack == NULL) {
962 jniThrowException(env, "java/lang/IllegalStateException",
963 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
964 return (jint)AUDIO_JAVA_ERROR;
965 }
966 return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
967 }
968
969
970 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_pos_update_period(JNIEnv * env,jobject thiz)971 static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
972 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
973 uint32_t period = 0;
974
975 if (lpTrack == NULL) {
976 jniThrowException(env, "java/lang/IllegalStateException",
977 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
978 return (jint)AUDIO_JAVA_ERROR;
979 }
980 lpTrack->getPositionUpdatePeriod(&period);
981 return (jint)period;
982 }
983
984
985 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_position(JNIEnv * env,jobject thiz,jint position)986 static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
987 jint position) {
988 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
989 if (lpTrack == NULL) {
990 jniThrowException(env, "java/lang/IllegalStateException",
991 "Unable to retrieve AudioTrack pointer for setPosition()");
992 return (jint)AUDIO_JAVA_ERROR;
993 }
994 return nativeToJavaStatus( lpTrack->setPosition(position) );
995 }
996
997
998 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_position(JNIEnv * env,jobject thiz)999 static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
1000 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1001 uint32_t position = 0;
1002
1003 if (lpTrack == NULL) {
1004 jniThrowException(env, "java/lang/IllegalStateException",
1005 "Unable to retrieve AudioTrack pointer for getPosition()");
1006 return (jint)AUDIO_JAVA_ERROR;
1007 }
1008 lpTrack->getPosition(&position);
1009 return (jint)position;
1010 }
1011
1012
1013 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_latency(JNIEnv * env,jobject thiz)1014 static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
1015 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1016
1017 if (lpTrack == NULL) {
1018 jniThrowException(env, "java/lang/IllegalStateException",
1019 "Unable to retrieve AudioTrack pointer for latency()");
1020 return (jint)AUDIO_JAVA_ERROR;
1021 }
1022 return (jint)lpTrack->latency();
1023 }
1024
1025 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_underrun_count(JNIEnv * env,jobject thiz)1026 static jint android_media_AudioTrack_get_underrun_count(JNIEnv *env, jobject thiz) {
1027 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1028
1029 if (lpTrack == NULL) {
1030 jniThrowException(env, "java/lang/IllegalStateException",
1031 "Unable to retrieve AudioTrack pointer for getUnderrunCount()");
1032 return (jint)AUDIO_JAVA_ERROR;
1033 }
1034 return (jint)lpTrack->getUnderrunCount();
1035 }
1036
1037 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_flags(JNIEnv * env,jobject thiz)1038 static jint android_media_AudioTrack_get_flags(JNIEnv *env, jobject thiz) {
1039 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1040
1041 if (lpTrack == NULL) {
1042 jniThrowException(env, "java/lang/IllegalStateException",
1043 "Unable to retrieve AudioTrack pointer for getFlags()");
1044 return (jint)AUDIO_JAVA_ERROR;
1045 }
1046 return (jint)lpTrack->getFlags();
1047 }
1048
1049 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_timestamp(JNIEnv * env,jobject thiz,jlongArray jTimestamp)1050 static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
1051 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1052
1053 if (lpTrack == NULL) {
1054 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
1055 return (jint)AUDIO_JAVA_ERROR;
1056 }
1057 AudioTimestamp timestamp;
1058 status_t status = lpTrack->getTimestamp(timestamp);
1059 if (status == OK) {
1060 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
1061 if (nTimestamp == NULL) {
1062 ALOGE("Unable to get array for getTimestamp()");
1063 return (jint)AUDIO_JAVA_ERROR;
1064 }
1065 nTimestamp[0] = (jlong) timestamp.mPosition;
1066 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
1067 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
1068 }
1069 return (jint) nativeToJavaStatus(status);
1070 }
1071
1072 // ----------------------------------------------------------------------------
1073 static jobject
android_media_AudioTrack_native_getMetrics(JNIEnv * env,jobject thiz)1074 android_media_AudioTrack_native_getMetrics(JNIEnv *env, jobject thiz)
1075 {
1076 ALOGD("android_media_AudioTrack_native_getMetrics");
1077
1078 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1079
1080 if (lpTrack == NULL) {
1081 ALOGE("Unable to retrieve AudioTrack pointer for getMetrics()");
1082 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1083 return (jobject) NULL;
1084 }
1085
1086 // get what we have for the metrics from the track
1087 mediametrics::Item *item = NULL;
1088
1089 status_t err = lpTrack->getMetrics(item);
1090 if (err != OK) {
1091 ALOGE("getMetrics failed");
1092 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1093 return (jobject) NULL;
1094 }
1095
1096 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
1097
1098 // housekeeping
1099 delete item;
1100 item = NULL;
1101
1102 return mybundle;
1103 }
1104
1105
1106 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_loop(JNIEnv * env,jobject thiz,jint loopStart,jint loopEnd,jint loopCount)1107 static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
1108 jint loopStart, jint loopEnd, jint loopCount) {
1109 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1110 if (lpTrack == NULL) {
1111 jniThrowException(env, "java/lang/IllegalStateException",
1112 "Unable to retrieve AudioTrack pointer for setLoop()");
1113 return (jint)AUDIO_JAVA_ERROR;
1114 }
1115 return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
1116 }
1117
1118
1119 // ----------------------------------------------------------------------------
android_media_AudioTrack_reload(JNIEnv * env,jobject thiz)1120 static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
1121 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1122 if (lpTrack == NULL) {
1123 jniThrowException(env, "java/lang/IllegalStateException",
1124 "Unable to retrieve AudioTrack pointer for reload()");
1125 return (jint)AUDIO_JAVA_ERROR;
1126 }
1127 return nativeToJavaStatus( lpTrack->reload() );
1128 }
1129
1130
1131 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_output_sample_rate(JNIEnv * env,jobject thiz,jint javaStreamType)1132 static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
1133 jint javaStreamType) {
1134 uint32_t afSamplingRate;
1135 // convert the stream type from Java to native value
1136 // FIXME: code duplication with android_media_AudioTrack_setup()
1137 audio_stream_type_t nativeStreamType;
1138 switch (javaStreamType) {
1139 case AUDIO_STREAM_VOICE_CALL:
1140 case AUDIO_STREAM_SYSTEM:
1141 case AUDIO_STREAM_RING:
1142 case AUDIO_STREAM_MUSIC:
1143 case AUDIO_STREAM_ALARM:
1144 case AUDIO_STREAM_NOTIFICATION:
1145 case AUDIO_STREAM_BLUETOOTH_SCO:
1146 case AUDIO_STREAM_DTMF:
1147 nativeStreamType = (audio_stream_type_t) javaStreamType;
1148 break;
1149 default:
1150 nativeStreamType = AUDIO_STREAM_DEFAULT;
1151 break;
1152 }
1153
1154 status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
1155 if (status != NO_ERROR) {
1156 ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
1157 "in AudioTrack JNI", status, nativeStreamType);
1158 return DEFAULT_OUTPUT_SAMPLE_RATE;
1159 } else {
1160 return afSamplingRate;
1161 }
1162 }
1163
1164
1165 // ----------------------------------------------------------------------------
1166 // returns the minimum required size for the successful creation of a streaming AudioTrack
1167 // returns -1 if there was an error querying the hardware.
android_media_AudioTrack_get_min_buff_size(JNIEnv * env,jobject thiz,jint sampleRateInHertz,jint channelCount,jint audioFormat)1168 static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
1169 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
1170
1171 size_t frameCount;
1172 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
1173 sampleRateInHertz);
1174 if (status != NO_ERROR) {
1175 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
1176 sampleRateInHertz, status);
1177 return -1;
1178 }
1179 const audio_format_t format = audioFormatToNative(audioFormat);
1180 if (audio_has_proportional_frames(format)) {
1181 const size_t bytesPerSample = audio_bytes_per_sample(format);
1182 return frameCount * channelCount * bytesPerSample;
1183 } else {
1184 return frameCount;
1185 }
1186 }
1187
1188 // ----------------------------------------------------------------------------
1189 static jint
android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv * env,jobject thiz,jfloat level)1190 android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
1191 {
1192 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1193 if (lpTrack == NULL ) {
1194 jniThrowException(env, "java/lang/IllegalStateException",
1195 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
1196 return -1;
1197 }
1198
1199 status_t status = lpTrack->setAuxEffectSendLevel(level);
1200 if (status != NO_ERROR) {
1201 ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
1202 level, status);
1203 }
1204 return (jint) status;
1205 }
1206
1207 // ----------------------------------------------------------------------------
android_media_AudioTrack_attachAuxEffect(JNIEnv * env,jobject thiz,jint effectId)1208 static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
1209 jint effectId) {
1210 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1211 if (lpTrack == NULL) {
1212 jniThrowException(env, "java/lang/IllegalStateException",
1213 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
1214 return (jint)AUDIO_JAVA_ERROR;
1215 }
1216 return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
1217 }
1218
android_media_AudioTrack_setOutputDevice(JNIEnv * env,jobject thiz,jint device_id)1219 static jboolean android_media_AudioTrack_setOutputDevice(
1220 JNIEnv *env, jobject thiz, jint device_id) {
1221
1222 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1223 if (lpTrack == 0) {
1224 return false;
1225 }
1226 return lpTrack->setOutputDevice(device_id) == NO_ERROR;
1227 }
1228
android_media_AudioTrack_getRoutedDeviceId(JNIEnv * env,jobject thiz)1229 static jint android_media_AudioTrack_getRoutedDeviceId(
1230 JNIEnv *env, jobject thiz) {
1231
1232 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1233 if (lpTrack == NULL) {
1234 return 0;
1235 }
1236 return (jint)lpTrack->getRoutedDeviceId();
1237 }
1238
android_media_AudioTrack_enableDeviceCallback(JNIEnv * env,jobject thiz)1239 static void android_media_AudioTrack_enableDeviceCallback(
1240 JNIEnv *env, jobject thiz) {
1241
1242 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1243 if (lpTrack == NULL) {
1244 return;
1245 }
1246 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1247 thiz, javaAudioTrackFields.jniData);
1248 if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
1249 return;
1250 }
1251 pJniStorage->mDeviceCallback =
1252 new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
1253 javaAudioTrackFields.postNativeEventInJava);
1254 lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
1255 }
1256
android_media_AudioTrack_disableDeviceCallback(JNIEnv * env,jobject thiz)1257 static void android_media_AudioTrack_disableDeviceCallback(
1258 JNIEnv *env, jobject thiz) {
1259
1260 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1261 if (lpTrack == NULL) {
1262 return;
1263 }
1264 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1265 thiz, javaAudioTrackFields.jniData);
1266 if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
1267 return;
1268 }
1269 lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
1270 pJniStorage->mDeviceCallback.clear();
1271 }
1272
1273 // Pass through the arguments to the AudioFlinger track implementation.
android_media_AudioTrack_apply_volume_shaper(JNIEnv * env,jobject thiz,jobject jconfig,jobject joperation)1274 static jint android_media_AudioTrack_apply_volume_shaper(JNIEnv *env, jobject thiz,
1275 jobject jconfig, jobject joperation) {
1276 // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
1277 const int VOLUME_SHAPER_INVALID_OPERATION = -38;
1278
1279 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1280 if (lpTrack == nullptr) {
1281 return (jint)VOLUME_SHAPER_INVALID_OPERATION;
1282 }
1283
1284 sp<VolumeShaper::Configuration> configuration;
1285 sp<VolumeShaper::Operation> operation;
1286 if (jconfig != nullptr) {
1287 configuration = VolumeShaperHelper::convertJobjectToConfiguration(
1288 env, gVolumeShaperFields, jconfig);
1289 ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
1290 }
1291 if (joperation != nullptr) {
1292 operation = VolumeShaperHelper::convertJobjectToOperation(
1293 env, gVolumeShaperFields, joperation);
1294 ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
1295 }
1296 VolumeShaper::Status status = lpTrack->applyVolumeShaper(configuration, operation);
1297 if (status == INVALID_OPERATION) {
1298 status = VOLUME_SHAPER_INVALID_OPERATION;
1299 }
1300 return (jint)status; // if status < 0 an error, else a VolumeShaper id
1301 }
1302
1303 // Pass through the arguments to the AudioFlinger track implementation.
android_media_AudioTrack_get_volume_shaper_state(JNIEnv * env,jobject thiz,jint id)1304 static jobject android_media_AudioTrack_get_volume_shaper_state(JNIEnv *env, jobject thiz,
1305 jint id) {
1306 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1307 if (lpTrack == nullptr) {
1308 return (jobject)nullptr;
1309 }
1310
1311 sp<VolumeShaper::State> state = lpTrack->getVolumeShaperState((int)id);
1312 if (state.get() == nullptr) {
1313 return (jobject)nullptr;
1314 }
1315 return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
1316 }
1317
android_media_AudioTrack_setPresentation(JNIEnv * env,jobject thiz,jint presentationId,jint programId)1318 static int android_media_AudioTrack_setPresentation(
1319 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
1320 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1321 if (lpTrack == NULL) {
1322 jniThrowException(env, "java/lang/IllegalStateException",
1323 "AudioTrack not initialized");
1324 return (jint)AUDIO_JAVA_ERROR;
1325 }
1326
1327 return (jint)lpTrack->selectPresentation((int)presentationId, (int)programId);
1328 }
1329
1330 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_port_id(JNIEnv * env,jobject thiz)1331 static jint android_media_AudioTrack_get_port_id(JNIEnv *env, jobject thiz) {
1332 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1333 if (lpTrack == NULL) {
1334 jniThrowException(env, "java/lang/IllegalStateException",
1335 "AudioTrack not initialized");
1336 return (jint)AUDIO_PORT_HANDLE_NONE;
1337 }
1338 return (jint)lpTrack->getPortId();
1339 }
1340
1341 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_delay_padding(JNIEnv * env,jobject thiz,jint delayInFrames,jint paddingInFrames)1342 static void android_media_AudioTrack_set_delay_padding(JNIEnv *env, jobject thiz,
1343 jint delayInFrames, jint paddingInFrames) {
1344 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1345 if (lpTrack == NULL) {
1346 jniThrowException(env, "java/lang/IllegalStateException",
1347 "AudioTrack not initialized");
1348 return;
1349 }
1350 AudioParameter param = AudioParameter();
1351 param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), (int) delayInFrames);
1352 param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), (int) paddingInFrames);
1353 lpTrack->setParameters(param.toString());
1354 }
1355
android_media_AudioTrack_setAudioDescriptionMixLeveldB(JNIEnv * env,jobject thiz,jfloat level)1356 static jint android_media_AudioTrack_setAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
1357 jfloat level) {
1358 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1359 if (lpTrack == nullptr) {
1360 jniThrowException(env, "java/lang/IllegalStateException", "AudioTrack not initialized");
1361 return (jint)AUDIO_JAVA_ERROR;
1362 }
1363
1364 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1365 return (jint)AUDIO_JAVA_ERROR;
1366 }
1367
android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv * env,jobject thiz,jfloatArray level)1368 static jint android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
1369 jfloatArray level) {
1370 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1371 if (lpTrack == nullptr) {
1372 ALOGE("%s: AudioTrack not initialized", __func__);
1373 return (jint)AUDIO_JAVA_ERROR;
1374 }
1375 jfloat *nativeLevel = (jfloat *)env->GetPrimitiveArrayCritical(level, NULL);
1376 if (nativeLevel == nullptr) {
1377 ALOGE("%s: Cannot retrieve level pointer", __func__);
1378 return (jint)AUDIO_JAVA_ERROR;
1379 }
1380
1381 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1382 // By contract we can return -infinity if unsupported.
1383 *nativeLevel = -std::numeric_limits<float>::infinity();
1384 env->ReleasePrimitiveArrayCritical(level, nativeLevel, 0 /* mode */);
1385 nativeLevel = nullptr;
1386 return (jint)AUDIO_JAVA_SUCCESS;
1387 }
1388
android_media_AudioTrack_setDualMonoMode(JNIEnv * env,jobject thiz,jint dualMonoMode)1389 static jint android_media_AudioTrack_setDualMonoMode(JNIEnv *env, jobject thiz, jint dualMonoMode) {
1390 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1391 if (lpTrack == nullptr) {
1392 jniThrowException(env, "java/lang/IllegalStateException", "AudioTrack not initialized");
1393 return (jint)AUDIO_JAVA_ERROR;
1394 }
1395
1396 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1397 return (jint)AUDIO_JAVA_ERROR;
1398 }
1399
android_media_AudioTrack_getDualMonoMode(JNIEnv * env,jobject thiz,jintArray dualMonoMode)1400 static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
1401 jintArray dualMonoMode) {
1402 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1403 if (lpTrack == nullptr) {
1404 ALOGE("%s: AudioTrack not initialized", __func__);
1405 return (jint)AUDIO_JAVA_ERROR;
1406 }
1407 jfloat *nativeDualMonoMode = (jfloat *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
1408 if (nativeDualMonoMode == nullptr) {
1409 ALOGE("%s: Cannot retrieve dualMonoMode pointer", __func__);
1410 return (jint)AUDIO_JAVA_ERROR;
1411 }
1412
1413 // TODO: replace in r-dev or r-tv-dev with code if HW is able to select dual mono mode.
1414 // By contract we can return DUAL_MONO_MODE_OFF if unsupported.
1415 *nativeDualMonoMode = 0; // DUAL_MONO_MODE_OFF for now.
1416 env->ReleasePrimitiveArrayCritical(dualMonoMode, nativeDualMonoMode, 0 /* mode */);
1417 nativeDualMonoMode = nullptr;
1418 return (jint)AUDIO_JAVA_SUCCESS;
1419 }
1420
1421 // ----------------------------------------------------------------------------
1422 // ----------------------------------------------------------------------------
1423 static const JNINativeMethod gMethods[] = {
1424 // name, signature, funcPtr
1425 {"native_is_direct_output_supported", "(IIIIIII)Z",
1426 (void *)android_media_AudioTrack_is_direct_output_supported},
1427 {"native_start", "()V", (void *)android_media_AudioTrack_start},
1428 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
1429 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
1430 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
1431 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;)I",
1432 (void *)android_media_AudioTrack_setup},
1433 {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
1434 {"native_release", "()V", (void *)android_media_AudioTrack_release},
1435 {"native_write_byte", "([BIIIZ)I", (void *)android_media_AudioTrack_writeArray<jbyteArray>},
1436 {"native_write_native_bytes", "(Ljava/nio/ByteBuffer;IIIZ)I",
1437 (void *)android_media_AudioTrack_write_native_bytes},
1438 {"native_write_short", "([SIIIZ)I",
1439 (void *)android_media_AudioTrack_writeArray<jshortArray>},
1440 {"native_write_float", "([FIIIZ)I",
1441 (void *)android_media_AudioTrack_writeArray<jfloatArray>},
1442 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
1443 {"native_get_buffer_size_frames", "()I",
1444 (void *)android_media_AudioTrack_get_buffer_size_frames},
1445 {"native_set_buffer_size_frames", "(I)I",
1446 (void *)android_media_AudioTrack_set_buffer_size_frames},
1447 {"native_get_buffer_capacity_frames", "()I",
1448 (void *)android_media_AudioTrack_get_buffer_capacity_frames},
1449 {"native_set_playback_rate", "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
1450 {"native_get_playback_rate", "()I", (void *)android_media_AudioTrack_get_playback_rate},
1451 {"native_set_playback_params", "(Landroid/media/PlaybackParams;)V",
1452 (void *)android_media_AudioTrack_set_playback_params},
1453 {"native_get_playback_params", "()Landroid/media/PlaybackParams;",
1454 (void *)android_media_AudioTrack_get_playback_params},
1455 {"native_set_marker_pos", "(I)I", (void *)android_media_AudioTrack_set_marker_pos},
1456 {"native_get_marker_pos", "()I", (void *)android_media_AudioTrack_get_marker_pos},
1457 {"native_set_pos_update_period", "(I)I",
1458 (void *)android_media_AudioTrack_set_pos_update_period},
1459 {"native_get_pos_update_period", "()I",
1460 (void *)android_media_AudioTrack_get_pos_update_period},
1461 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
1462 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
1463 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
1464 {"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
1465 {"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
1466 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
1467 {"native_getMetrics", "()Landroid/os/PersistableBundle;",
1468 (void *)android_media_AudioTrack_native_getMetrics},
1469 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
1470 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
1471 {"native_get_output_sample_rate", "(I)I",
1472 (void *)android_media_AudioTrack_get_output_sample_rate},
1473 {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
1474 {"native_setAuxEffectSendLevel", "(F)I",
1475 (void *)android_media_AudioTrack_setAuxEffectSendLevel},
1476 {"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
1477 {"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
1478 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
1479 {"native_enableDeviceCallback", "()V",
1480 (void *)android_media_AudioTrack_enableDeviceCallback},
1481 {"native_disableDeviceCallback", "()V",
1482 (void *)android_media_AudioTrack_disableDeviceCallback},
1483 {"native_applyVolumeShaper",
1484 "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
1485 (void *)android_media_AudioTrack_apply_volume_shaper},
1486 {"native_getVolumeShaperState", "(I)Landroid/media/VolumeShaper$State;",
1487 (void *)android_media_AudioTrack_get_volume_shaper_state},
1488 {"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
1489 {"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
1490 {"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
1491 {"native_set_audio_description_mix_level_db", "(F)I",
1492 (void *)android_media_AudioTrack_setAudioDescriptionMixLeveldB},
1493 {"native_get_audio_description_mix_level_db", "([F)I",
1494 (void *)android_media_AudioTrack_getAudioDescriptionMixLeveldB},
1495 {"native_set_dual_mono_mode", "(I)I", (void *)android_media_AudioTrack_setDualMonoMode},
1496 {"native_get_dual_mono_mode", "([I)I", (void *)android_media_AudioTrack_getDualMonoMode},
1497 };
1498
1499 // field names found in android/media/AudioTrack.java
1500 #define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
1501 #define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
1502 #define JAVA_JNIDATA_FIELD_NAME "mJniData"
1503 #define JAVA_STREAMTYPE_FIELD_NAME "mStreamType"
1504
1505 // ----------------------------------------------------------------------------
1506 // preconditions:
1507 // theClass is valid
android_media_getIntConstantFromClass(JNIEnv * pEnv,jclass theClass,const char * className,const char * constName,int * constVal)1508 bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1509 const char* constName, int* constVal) {
1510 jfieldID javaConst = NULL;
1511 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1512 if (javaConst != NULL) {
1513 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1514 return true;
1515 } else {
1516 ALOGE("Can't find %s.%s", className, constName);
1517 return false;
1518 }
1519 }
1520
1521 // ----------------------------------------------------------------------------
register_android_media_AudioTrack(JNIEnv * env)1522 int register_android_media_AudioTrack(JNIEnv *env)
1523 {
1524 // must be first
1525 int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1526
1527 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1528 javaAudioTrackFields.postNativeEventInJava = NULL;
1529
1530 // Get the AudioTrack class
1531 jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
1532
1533 // Get the postEvent method
1534 javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1535 audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1536 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1537
1538 // Get the variables fields
1539 // nativeTrackInJavaObj
1540 javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1541 audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
1542 // jniData
1543 javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1544 audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
1545 // fieldStreamType
1546 javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1547 audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
1548
1549 env->DeleteLocalRef(audioTrackClass);
1550
1551 // initialize PlaybackParams field info
1552 gPlaybackParamsFields.init(env);
1553
1554 gVolumeShaperFields.init(env);
1555
1556 // optional check that the TunerConfiguration class and fields exist.
1557 TunerConfigurationHelper::initCheckOrDie(env);
1558
1559 return res;
1560 }
1561
1562
1563 // ----------------------------------------------------------------------------
1564