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 <JNIHelp.h>
23 #include <JniConstants.h>
24 #include "core_jni_helpers.h"
25
26 #include "ScopedBytes.h"
27
28 #include <utils/Log.h>
29 #include <media/AudioSystem.h>
30 #include <media/AudioTrack.h>
31 #include <audio_utils/primitives.h>
32
33 #include <binder/MemoryHeapBase.h>
34 #include <binder/MemoryBase.h>
35
36 #include "android_media_AudioFormat.h"
37 #include "android_media_AudioErrors.h"
38 #include "android_media_PlaybackParams.h"
39 #include "android_media_DeviceCallback.h"
40
41 // ----------------------------------------------------------------------------
42
43 using namespace android;
44
45 // ----------------------------------------------------------------------------
46 static const char* const kClassPathName = "android/media/AudioTrack";
47 static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
48
49 struct audio_track_fields_t {
50 // these fields provide access from C++ to the...
51 jmethodID postNativeEventInJava; //... event post callback method
52 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
53 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
54 jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object
55 };
56 struct audio_attributes_fields_t {
57 jfieldID fieldUsage; // AudioAttributes.mUsage
58 jfieldID fieldContentType; // AudioAttributes.mContentType
59 jfieldID fieldFlags; // AudioAttributes.mFlags
60 jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags
61 };
62 static audio_track_fields_t javaAudioTrackFields;
63 static audio_attributes_fields_t javaAudioAttrFields;
64 static PlaybackParams::fields_t gPlaybackParamsFields;
65
66 struct audiotrack_callback_cookie {
67 jclass audioTrack_class;
68 jobject audioTrack_ref;
69 bool busy;
70 Condition cond;
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
AudioTrackJniStorage()85 AudioTrackJniStorage() {
86 mCallbackData.audioTrack_class = 0;
87 mCallbackData.audioTrack_ref = 0;
88 }
89
~AudioTrackJniStorage()90 ~AudioTrackJniStorage() {
91 mMemBase.clear();
92 mMemHeap.clear();
93 }
94
allocSharedMem(int sizeInBytes)95 bool allocSharedMem(int sizeInBytes) {
96 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
97 if (mMemHeap->getHeapID() < 0) {
98 return false;
99 }
100 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
101 return true;
102 }
103 };
104
105 static Mutex sLock;
106 static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
107
108 // ----------------------------------------------------------------------------
109 #define DEFAULT_OUTPUT_SAMPLE_RATE 44100
110
111 #define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
112 #define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
113 #define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
114 #define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
115 #define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
116
117 // ----------------------------------------------------------------------------
audioCallback(int event,void * user,void * info)118 static void audioCallback(int event, void* user, void *info) {
119
120 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
121 {
122 Mutex::Autolock l(sLock);
123 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
124 return;
125 }
126 callbackInfo->busy = true;
127 }
128
129 switch (event) {
130 case AudioTrack::EVENT_MARKER: {
131 JNIEnv *env = AndroidRuntime::getJNIEnv();
132 if (user != NULL && env != NULL) {
133 env->CallStaticVoidMethod(
134 callbackInfo->audioTrack_class,
135 javaAudioTrackFields.postNativeEventInJava,
136 callbackInfo->audioTrack_ref, event, 0,0, NULL);
137 if (env->ExceptionCheck()) {
138 env->ExceptionDescribe();
139 env->ExceptionClear();
140 }
141 }
142 } break;
143
144 case AudioTrack::EVENT_NEW_POS: {
145 JNIEnv *env = AndroidRuntime::getJNIEnv();
146 if (user != NULL && env != NULL) {
147 env->CallStaticVoidMethod(
148 callbackInfo->audioTrack_class,
149 javaAudioTrackFields.postNativeEventInJava,
150 callbackInfo->audioTrack_ref, event, 0,0, NULL);
151 if (env->ExceptionCheck()) {
152 env->ExceptionDescribe();
153 env->ExceptionClear();
154 }
155 }
156 } break;
157 }
158
159 {
160 Mutex::Autolock l(sLock);
161 callbackInfo->busy = false;
162 callbackInfo->cond.broadcast();
163 }
164 }
165
166
167 // ----------------------------------------------------------------------------
getAudioTrack(JNIEnv * env,jobject thiz)168 static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
169 {
170 Mutex::Autolock l(sLock);
171 AudioTrack* const at =
172 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
173 return sp<AudioTrack>(at);
174 }
175
setAudioTrack(JNIEnv * env,jobject thiz,const sp<AudioTrack> & at)176 static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
177 {
178 Mutex::Autolock l(sLock);
179 sp<AudioTrack> old =
180 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
181 if (at.get()) {
182 at->incStrong((void*)setAudioTrack);
183 }
184 if (old != 0) {
185 old->decStrong((void*)setAudioTrack);
186 }
187 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
188 return old;
189 }
190
191 // ----------------------------------------------------------------------------
android_media_AudioTrack_getAudioTrack(JNIEnv * env,jobject audioTrackObj)192 sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
193 return getAudioTrack(env, audioTrackObj);
194 }
195
196 // This function converts Java channel masks to a native channel mask.
197 // validity should be checked with audio_is_output_channel().
nativeChannelMaskFromJavaChannelMasks(jint channelPositionMask,jint channelIndexMask)198 static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
199 jint channelPositionMask, jint channelIndexMask)
200 {
201 if (channelIndexMask != 0) { // channel index mask takes priority
202 // To convert to a native channel mask, the Java channel index mask
203 // requires adding the index representation.
204 return audio_channel_mask_from_representation_and_bits(
205 AUDIO_CHANNEL_REPRESENTATION_INDEX,
206 channelIndexMask);
207 }
208 // To convert to a native channel mask, the Java channel position mask
209 // requires a shift by 2 to skip the two deprecated channel
210 // configurations "default" and "mono".
211 return (audio_channel_mask_t)(channelPositionMask >> 2);
212 }
213
214 // ----------------------------------------------------------------------------
215 static jint
android_media_AudioTrack_setup(JNIEnv * env,jobject thiz,jobject weak_this,jobject jaa,jint sampleRateInHertz,jint channelPositionMask,jint channelIndexMask,jint audioFormat,jint buffSizeInBytes,jint memoryMode,jintArray jSession)216 android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
217 jobject jaa,
218 jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask,
219 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {
220
221 ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d",
222 sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes);
223
224 if (jaa == 0) {
225 ALOGE("Error creating AudioTrack: invalid audio attributes");
226 return (jint) AUDIO_JAVA_ERROR;
227 }
228
229 // Invalid channel representations are caught by !audio_is_output_channel() below.
230 audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
231 channelPositionMask, channelIndexMask);
232 if (!audio_is_output_channel(nativeChannelMask)) {
233 ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
234 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
235 }
236
237 uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
238
239 // check the format.
240 // This function was called from Java, so we compare the format against the Java constants
241 audio_format_t format = audioFormatToNative(audioFormat);
242 if (format == AUDIO_FORMAT_INVALID) {
243 ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
244 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
245 }
246
247 // compute the frame count
248 size_t frameCount;
249 if (audio_is_linear_pcm(format)) {
250 const size_t bytesPerSample = audio_bytes_per_sample(format);
251 frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
252 } else {
253 frameCount = buffSizeInBytes;
254 }
255
256 jclass clazz = env->GetObjectClass(thiz);
257 if (clazz == NULL) {
258 ALOGE("Can't find %s when setting up callback.", kClassPathName);
259 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
260 }
261
262 if (jSession == NULL) {
263 ALOGE("Error creating AudioTrack: invalid session ID pointer");
264 return (jint) AUDIO_JAVA_ERROR;
265 }
266
267 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
268 if (nSession == NULL) {
269 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
270 return (jint) AUDIO_JAVA_ERROR;
271 }
272 int sessionId = nSession[0];
273 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
274 nSession = NULL;
275
276 // create the native AudioTrack object
277 sp<AudioTrack> lpTrack = new AudioTrack();
278
279 audio_attributes_t *paa = NULL;
280 // read the AudioAttributes values
281 paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
282 const jstring jtags =
283 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
284 const char* tags = env->GetStringUTFChars(jtags, NULL);
285 // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
286 strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
287 env->ReleaseStringUTFChars(jtags, tags);
288 paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
289 paa->content_type =
290 (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
291 paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
292
293 ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
294 paa->usage, paa->content_type, paa->flags, paa->tags);
295
296 // initialize the callback information:
297 // this data will be passed with every AudioTrack callback
298 AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
299 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
300 // we use a weak reference so the AudioTrack object can be garbage collected.
301 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
302 lpJniStorage->mCallbackData.busy = false;
303
304 // initialize the native AudioTrack object
305 status_t status = NO_ERROR;
306 switch (memoryMode) {
307 case MODE_STREAM:
308
309 status = lpTrack->set(
310 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
311 sampleRateInHertz,
312 format,// word length, PCM
313 nativeChannelMask,
314 frameCount,
315 AUDIO_OUTPUT_FLAG_NONE,
316 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
317 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
318 0,// shared mem
319 true,// thread can call Java
320 sessionId,// audio session ID
321 AudioTrack::TRANSFER_SYNC,
322 NULL, // default offloadInfo
323 -1, -1, // default uid, pid values
324 paa);
325 break;
326
327 case MODE_STATIC:
328 // AudioTrack is using shared memory
329
330 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
331 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
332 goto native_init_failure;
333 }
334
335 status = lpTrack->set(
336 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
337 sampleRateInHertz,
338 format,// word length, PCM
339 nativeChannelMask,
340 frameCount,
341 AUDIO_OUTPUT_FLAG_NONE,
342 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
343 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
344 lpJniStorage->mMemBase,// shared mem
345 true,// thread can call Java
346 sessionId,// audio session ID
347 AudioTrack::TRANSFER_SHARED,
348 NULL, // default offloadInfo
349 -1, -1, // default uid, pid values
350 paa);
351 break;
352
353 default:
354 ALOGE("Unknown mode %d", memoryMode);
355 goto native_init_failure;
356 }
357
358 if (status != NO_ERROR) {
359 ALOGE("Error %d initializing AudioTrack", status);
360 goto native_init_failure;
361 }
362
363 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
364 if (nSession == NULL) {
365 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
366 goto native_init_failure;
367 }
368 // read the audio session ID back from AudioTrack in case we create a new session
369 nSession[0] = lpTrack->getSessionId();
370 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
371 nSession = NULL;
372
373 { // scope for the lock
374 Mutex::Autolock l(sLock);
375 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
376 }
377 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
378 // of the Java object (in mNativeTrackInJavaObj)
379 setAudioTrack(env, thiz, lpTrack);
380
381 // save the JNI resources so we can free them later
382 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
383 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
384
385 // since we had audio attributes, the stream type was derived from them during the
386 // creation of the native AudioTrack: push the same value to the Java object
387 env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
388 // audio attributes were copied in AudioTrack creation
389 free(paa);
390 paa = NULL;
391
392
393 return (jint) AUDIO_JAVA_SUCCESS;
394
395 // failures:
396 native_init_failure:
397 if (paa != NULL) {
398 free(paa);
399 }
400 if (nSession != NULL) {
401 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
402 }
403 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
404 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
405 delete lpJniStorage;
406 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
407
408 // lpTrack goes out of scope, so reference count drops to zero
409 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
410 }
411
412
413 // ----------------------------------------------------------------------------
414 static void
android_media_AudioTrack_start(JNIEnv * env,jobject thiz)415 android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
416 {
417 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
418 if (lpTrack == NULL) {
419 jniThrowException(env, "java/lang/IllegalStateException",
420 "Unable to retrieve AudioTrack pointer for start()");
421 return;
422 }
423
424 lpTrack->start();
425 }
426
427
428 // ----------------------------------------------------------------------------
429 static void
android_media_AudioTrack_stop(JNIEnv * env,jobject thiz)430 android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
431 {
432 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
433 if (lpTrack == NULL) {
434 jniThrowException(env, "java/lang/IllegalStateException",
435 "Unable to retrieve AudioTrack pointer for stop()");
436 return;
437 }
438
439 lpTrack->stop();
440 }
441
442
443 // ----------------------------------------------------------------------------
444 static void
android_media_AudioTrack_pause(JNIEnv * env,jobject thiz)445 android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
446 {
447 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
448 if (lpTrack == NULL) {
449 jniThrowException(env, "java/lang/IllegalStateException",
450 "Unable to retrieve AudioTrack pointer for pause()");
451 return;
452 }
453
454 lpTrack->pause();
455 }
456
457
458 // ----------------------------------------------------------------------------
459 static void
android_media_AudioTrack_flush(JNIEnv * env,jobject thiz)460 android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
461 {
462 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
463 if (lpTrack == NULL) {
464 jniThrowException(env, "java/lang/IllegalStateException",
465 "Unable to retrieve AudioTrack pointer for flush()");
466 return;
467 }
468
469 lpTrack->flush();
470 }
471
472 // ----------------------------------------------------------------------------
473 static void
android_media_AudioTrack_set_volume(JNIEnv * env,jobject thiz,jfloat leftVol,jfloat rightVol)474 android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
475 {
476 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
477 if (lpTrack == NULL) {
478 jniThrowException(env, "java/lang/IllegalStateException",
479 "Unable to retrieve AudioTrack pointer for setVolume()");
480 return;
481 }
482
483 lpTrack->setVolume(leftVol, rightVol);
484 }
485
486 // ----------------------------------------------------------------------------
487
488 #define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
android_media_AudioTrack_release(JNIEnv * env,jobject thiz)489 static void android_media_AudioTrack_release(JNIEnv *env, jobject thiz) {
490 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
491 if (lpTrack == NULL) {
492 return;
493 }
494 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
495 lpTrack->stop();
496
497 // delete the JNI data
498 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
499 thiz, javaAudioTrackFields.jniData);
500 // reset the native resources in the Java object so any attempt to access
501 // them after a call to release fails.
502 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
503
504 if (pJniStorage) {
505 Mutex::Autolock l(sLock);
506 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
507 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
508 while (lpCookie->busy) {
509 if (lpCookie->cond.waitRelative(sLock,
510 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
511 NO_ERROR) {
512 break;
513 }
514 }
515 sAudioTrackCallBackCookies.remove(lpCookie);
516 // delete global refs created in native_setup
517 env->DeleteGlobalRef(lpCookie->audioTrack_class);
518 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
519 delete pJniStorage;
520 }
521 }
522
523
524 // ----------------------------------------------------------------------------
android_media_AudioTrack_finalize(JNIEnv * env,jobject thiz)525 static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
526 //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
527 android_media_AudioTrack_release(env, thiz);
528 }
529
530 // overloaded JNI array helper functions (same as in android_media_AudioRecord)
531 static inline
envGetArrayElements(JNIEnv * env,jbyteArray array,jboolean * isCopy)532 jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
533 return env->GetByteArrayElements(array, isCopy);
534 }
535
536 static inline
envReleaseArrayElements(JNIEnv * env,jbyteArray array,jbyte * elems,jint mode)537 void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
538 env->ReleaseByteArrayElements(array, elems, mode);
539 }
540
541 static inline
envGetArrayElements(JNIEnv * env,jshortArray array,jboolean * isCopy)542 jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
543 return env->GetShortArrayElements(array, isCopy);
544 }
545
546 static inline
envReleaseArrayElements(JNIEnv * env,jshortArray array,jshort * elems,jint mode)547 void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
548 env->ReleaseShortArrayElements(array, elems, mode);
549 }
550
551 static inline
envGetArrayElements(JNIEnv * env,jfloatArray array,jboolean * isCopy)552 jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
553 return env->GetFloatArrayElements(array, isCopy);
554 }
555
556 static inline
envReleaseArrayElements(JNIEnv * env,jfloatArray array,jfloat * elems,jint mode)557 void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
558 env->ReleaseFloatArrayElements(array, elems, mode);
559 }
560
561 // ----------------------------------------------------------------------------
562 template <typename T>
writeToTrack(const sp<AudioTrack> & track,jint audioFormat,const T * data,jint offsetInSamples,jint sizeInSamples,bool blocking)563 static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
564 jint offsetInSamples, jint sizeInSamples, bool blocking) {
565 // give the data to the native AudioTrack object (the data starts at the offset)
566 ssize_t written = 0;
567 // regular write() or copy the data to the AudioTrack's shared memory?
568 size_t sizeInBytes = sizeInSamples * sizeof(T);
569 if (track->sharedBuffer() == 0) {
570 written = track->write(data + offsetInSamples, sizeInBytes, blocking);
571 // for compatibility with earlier behavior of write(), return 0 in this case
572 if (written == (ssize_t) WOULD_BLOCK) {
573 written = 0;
574 }
575 } else {
576 // writing to shared memory, check for capacity
577 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
578 sizeInBytes = track->sharedBuffer()->size();
579 }
580 memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
581 written = sizeInBytes;
582 }
583 if (written > 0) {
584 return written / sizeof(T);
585 }
586 // for compatibility, error codes pass through unchanged
587 return written;
588 }
589
590 // ----------------------------------------------------------------------------
591 template <typename T>
android_media_AudioTrack_writeArray(JNIEnv * env,jobject thiz,T javaAudioData,jint offsetInSamples,jint sizeInSamples,jint javaAudioFormat,jboolean isWriteBlocking)592 static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
593 T javaAudioData,
594 jint offsetInSamples, jint sizeInSamples,
595 jint javaAudioFormat,
596 jboolean isWriteBlocking) {
597 //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
598 // offsetInSamples, sizeInSamples);
599 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
600 if (lpTrack == NULL) {
601 jniThrowException(env, "java/lang/IllegalStateException",
602 "Unable to retrieve AudioTrack pointer for write()");
603 return (jint)AUDIO_JAVA_INVALID_OPERATION;
604 }
605
606 if (javaAudioData == NULL) {
607 ALOGE("NULL java array of audio data to play");
608 return (jint)AUDIO_JAVA_BAD_VALUE;
609 }
610
611 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
612 // a way that it becomes much more efficient. When doing so, we will have to prevent the
613 // AudioSystem callback to be called while in critical section (in case of media server
614 // process crash for instance)
615
616 // get the pointer for the audio data from the java array
617 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
618 if (cAudioData == NULL) {
619 ALOGE("Error retrieving source of audio data to play");
620 return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
621 }
622
623 jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
624 offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
625
626 envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
627
628 //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
629 // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
630 return samplesWritten;
631 }
632
633 // ----------------------------------------------------------------------------
android_media_AudioTrack_write_native_bytes(JNIEnv * env,jobject thiz,jbyteArray javaBytes,jint byteOffset,jint sizeInBytes,jint javaAudioFormat,jboolean isWriteBlocking)634 static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
635 jbyteArray javaBytes, jint byteOffset, jint sizeInBytes,
636 jint javaAudioFormat, jboolean isWriteBlocking) {
637 //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
638 // offsetInBytes, sizeInBytes);
639 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
640 if (lpTrack == NULL) {
641 jniThrowException(env, "java/lang/IllegalStateException",
642 "Unable to retrieve AudioTrack pointer for write()");
643 return (jint)AUDIO_JAVA_INVALID_OPERATION;
644 }
645
646 ScopedBytesRO bytes(env, javaBytes);
647 if (bytes.get() == NULL) {
648 ALOGE("Error retrieving source of audio data to play, can't play");
649 return (jint)AUDIO_JAVA_BAD_VALUE;
650 }
651
652 jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
653 sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
654
655 return written;
656 }
657
658 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_native_frame_count(JNIEnv * env,jobject thiz)659 static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
660 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
661 if (lpTrack == NULL) {
662 jniThrowException(env, "java/lang/IllegalStateException",
663 "Unable to retrieve AudioTrack pointer for frameCount()");
664 return (jint)AUDIO_JAVA_ERROR;
665 }
666
667 return lpTrack->frameCount();
668 }
669
670
671 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_playback_rate(JNIEnv * env,jobject thiz,jint sampleRateInHz)672 static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
673 jint sampleRateInHz) {
674 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
675 if (lpTrack == NULL) {
676 jniThrowException(env, "java/lang/IllegalStateException",
677 "Unable to retrieve AudioTrack pointer for setSampleRate()");
678 return (jint)AUDIO_JAVA_ERROR;
679 }
680 return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
681 }
682
683
684 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_playback_rate(JNIEnv * env,jobject thiz)685 static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
686 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
687 if (lpTrack == NULL) {
688 jniThrowException(env, "java/lang/IllegalStateException",
689 "Unable to retrieve AudioTrack pointer for getSampleRate()");
690 return (jint)AUDIO_JAVA_ERROR;
691 }
692 return (jint) lpTrack->getSampleRate();
693 }
694
695
696 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_playback_params(JNIEnv * env,jobject thiz,jobject params)697 static void android_media_AudioTrack_set_playback_params(JNIEnv *env, jobject thiz,
698 jobject params) {
699 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
700 if (lpTrack == NULL) {
701 jniThrowException(env, "java/lang/IllegalStateException",
702 "AudioTrack not initialized");
703 return;
704 }
705
706 PlaybackParams pbp;
707 pbp.fillFromJobject(env, gPlaybackParamsFields, params);
708
709 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
710 pbp.speedSet, pbp.audioRate.mSpeed,
711 pbp.pitchSet, pbp.audioRate.mPitch,
712 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
713 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
714
715 // to simulate partially set params, we do a read-modify-write.
716 // TODO: pass in the valid set mask into AudioTrack.
717 AudioPlaybackRate rate = lpTrack->getPlaybackRate();
718 bool updatedRate = false;
719 if (pbp.speedSet) {
720 rate.mSpeed = pbp.audioRate.mSpeed;
721 updatedRate = true;
722 }
723 if (pbp.pitchSet) {
724 rate.mPitch = pbp.audioRate.mPitch;
725 updatedRate = true;
726 }
727 if (pbp.audioFallbackModeSet) {
728 rate.mFallbackMode = pbp.audioRate.mFallbackMode;
729 updatedRate = true;
730 }
731 if (pbp.audioStretchModeSet) {
732 rate.mStretchMode = pbp.audioRate.mStretchMode;
733 updatedRate = true;
734 }
735 if (updatedRate) {
736 if (lpTrack->setPlaybackRate(rate) != OK) {
737 jniThrowException(env, "java/lang/IllegalArgumentException",
738 "arguments out of range");
739 }
740 }
741 }
742
743
744 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_playback_params(JNIEnv * env,jobject thiz,jobject params)745 static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env, jobject thiz,
746 jobject params) {
747 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
748 if (lpTrack == NULL) {
749 jniThrowException(env, "java/lang/IllegalStateException",
750 "AudioTrack not initialized");
751 return NULL;
752 }
753
754 PlaybackParams pbs;
755 pbs.audioRate = lpTrack->getPlaybackRate();
756 pbs.speedSet = true;
757 pbs.pitchSet = true;
758 pbs.audioFallbackModeSet = true;
759 pbs.audioStretchModeSet = true;
760 return pbs.asJobject(env, gPlaybackParamsFields);
761 }
762
763
764 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_marker_pos(JNIEnv * env,jobject thiz,jint markerPos)765 static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
766 jint markerPos) {
767 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
768 if (lpTrack == NULL) {
769 jniThrowException(env, "java/lang/IllegalStateException",
770 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
771 return (jint)AUDIO_JAVA_ERROR;
772 }
773 return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
774 }
775
776
777 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_marker_pos(JNIEnv * env,jobject thiz)778 static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
779 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
780 uint32_t markerPos = 0;
781
782 if (lpTrack == NULL) {
783 jniThrowException(env, "java/lang/IllegalStateException",
784 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
785 return (jint)AUDIO_JAVA_ERROR;
786 }
787 lpTrack->getMarkerPosition(&markerPos);
788 return (jint)markerPos;
789 }
790
791
792 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_pos_update_period(JNIEnv * env,jobject thiz,jint period)793 static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
794 jint period) {
795 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
796 if (lpTrack == NULL) {
797 jniThrowException(env, "java/lang/IllegalStateException",
798 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
799 return (jint)AUDIO_JAVA_ERROR;
800 }
801 return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
802 }
803
804
805 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_pos_update_period(JNIEnv * env,jobject thiz)806 static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
807 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
808 uint32_t period = 0;
809
810 if (lpTrack == NULL) {
811 jniThrowException(env, "java/lang/IllegalStateException",
812 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
813 return (jint)AUDIO_JAVA_ERROR;
814 }
815 lpTrack->getPositionUpdatePeriod(&period);
816 return (jint)period;
817 }
818
819
820 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_position(JNIEnv * env,jobject thiz,jint position)821 static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
822 jint position) {
823 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
824 if (lpTrack == NULL) {
825 jniThrowException(env, "java/lang/IllegalStateException",
826 "Unable to retrieve AudioTrack pointer for setPosition()");
827 return (jint)AUDIO_JAVA_ERROR;
828 }
829 return nativeToJavaStatus( lpTrack->setPosition(position) );
830 }
831
832
833 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_position(JNIEnv * env,jobject thiz)834 static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
835 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
836 uint32_t position = 0;
837
838 if (lpTrack == NULL) {
839 jniThrowException(env, "java/lang/IllegalStateException",
840 "Unable to retrieve AudioTrack pointer for getPosition()");
841 return (jint)AUDIO_JAVA_ERROR;
842 }
843 lpTrack->getPosition(&position);
844 return (jint)position;
845 }
846
847
848 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_latency(JNIEnv * env,jobject thiz)849 static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
850 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
851
852 if (lpTrack == NULL) {
853 jniThrowException(env, "java/lang/IllegalStateException",
854 "Unable to retrieve AudioTrack pointer for latency()");
855 return (jint)AUDIO_JAVA_ERROR;
856 }
857 return (jint)lpTrack->latency();
858 }
859
860
861 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_timestamp(JNIEnv * env,jobject thiz,jlongArray jTimestamp)862 static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
863 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
864
865 if (lpTrack == NULL) {
866 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
867 return (jint)AUDIO_JAVA_ERROR;
868 }
869 AudioTimestamp timestamp;
870 status_t status = lpTrack->getTimestamp(timestamp);
871 if (status == OK) {
872 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
873 if (nTimestamp == NULL) {
874 ALOGE("Unable to get array for getTimestamp()");
875 return (jint)AUDIO_JAVA_ERROR;
876 }
877 nTimestamp[0] = (jlong) timestamp.mPosition;
878 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
879 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
880 }
881 return (jint) nativeToJavaStatus(status);
882 }
883
884
885 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_loop(JNIEnv * env,jobject thiz,jint loopStart,jint loopEnd,jint loopCount)886 static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
887 jint loopStart, jint loopEnd, jint loopCount) {
888 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
889 if (lpTrack == NULL) {
890 jniThrowException(env, "java/lang/IllegalStateException",
891 "Unable to retrieve AudioTrack pointer for setLoop()");
892 return (jint)AUDIO_JAVA_ERROR;
893 }
894 return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
895 }
896
897
898 // ----------------------------------------------------------------------------
android_media_AudioTrack_reload(JNIEnv * env,jobject thiz)899 static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
900 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
901 if (lpTrack == NULL) {
902 jniThrowException(env, "java/lang/IllegalStateException",
903 "Unable to retrieve AudioTrack pointer for reload()");
904 return (jint)AUDIO_JAVA_ERROR;
905 }
906 return nativeToJavaStatus( lpTrack->reload() );
907 }
908
909
910 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_output_sample_rate(JNIEnv * env,jobject thiz,jint javaStreamType)911 static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
912 jint javaStreamType) {
913 uint32_t afSamplingRate;
914 // convert the stream type from Java to native value
915 // FIXME: code duplication with android_media_AudioTrack_setup()
916 audio_stream_type_t nativeStreamType;
917 switch (javaStreamType) {
918 case AUDIO_STREAM_VOICE_CALL:
919 case AUDIO_STREAM_SYSTEM:
920 case AUDIO_STREAM_RING:
921 case AUDIO_STREAM_MUSIC:
922 case AUDIO_STREAM_ALARM:
923 case AUDIO_STREAM_NOTIFICATION:
924 case AUDIO_STREAM_BLUETOOTH_SCO:
925 case AUDIO_STREAM_DTMF:
926 nativeStreamType = (audio_stream_type_t) javaStreamType;
927 break;
928 default:
929 nativeStreamType = AUDIO_STREAM_DEFAULT;
930 break;
931 }
932
933 status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
934 if (status != NO_ERROR) {
935 ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
936 "in AudioTrack JNI", status, nativeStreamType);
937 return DEFAULT_OUTPUT_SAMPLE_RATE;
938 } else {
939 return afSamplingRate;
940 }
941 }
942
943
944 // ----------------------------------------------------------------------------
945 // returns the minimum required size for the successful creation of a streaming AudioTrack
946 // 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)947 static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
948 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
949
950 size_t frameCount;
951 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
952 sampleRateInHertz);
953 if (status != NO_ERROR) {
954 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
955 sampleRateInHertz, status);
956 return -1;
957 }
958 const audio_format_t format = audioFormatToNative(audioFormat);
959 if (audio_is_linear_pcm(format)) {
960 const size_t bytesPerSample = audio_bytes_per_sample(format);
961 return frameCount * channelCount * bytesPerSample;
962 } else {
963 return frameCount;
964 }
965 }
966
967 // ----------------------------------------------------------------------------
968 static jint
android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv * env,jobject thiz,jfloat level)969 android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
970 {
971 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
972 if (lpTrack == NULL ) {
973 jniThrowException(env, "java/lang/IllegalStateException",
974 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
975 return -1;
976 }
977
978 status_t status = lpTrack->setAuxEffectSendLevel(level);
979 if (status != NO_ERROR) {
980 ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
981 level, status);
982 }
983 return (jint) status;
984 }
985
986 // ----------------------------------------------------------------------------
android_media_AudioTrack_attachAuxEffect(JNIEnv * env,jobject thiz,jint effectId)987 static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
988 jint effectId) {
989 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
990 if (lpTrack == NULL) {
991 jniThrowException(env, "java/lang/IllegalStateException",
992 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
993 return (jint)AUDIO_JAVA_ERROR;
994 }
995 return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
996 }
997
android_media_AudioTrack_setOutputDevice(JNIEnv * env,jobject thiz,jint device_id)998 static jboolean android_media_AudioTrack_setOutputDevice(
999 JNIEnv *env, jobject thiz, jint device_id) {
1000
1001 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1002 if (lpTrack == 0) {
1003 return false;
1004 }
1005 return lpTrack->setOutputDevice(device_id) == NO_ERROR;
1006 }
1007
android_media_AudioTrack_getRoutedDeviceId(JNIEnv * env,jobject thiz)1008 static jint android_media_AudioTrack_getRoutedDeviceId(
1009 JNIEnv *env, jobject thiz) {
1010
1011 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1012 if (lpTrack == NULL) {
1013 return 0;
1014 }
1015 return (jint)lpTrack->getRoutedDeviceId();
1016 }
1017
android_media_AudioTrack_enableDeviceCallback(JNIEnv * env,jobject thiz)1018 static void android_media_AudioTrack_enableDeviceCallback(
1019 JNIEnv *env, jobject thiz) {
1020
1021 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1022 if (lpTrack == NULL) {
1023 return;
1024 }
1025 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1026 thiz, javaAudioTrackFields.jniData);
1027 if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
1028 return;
1029 }
1030 pJniStorage->mDeviceCallback =
1031 new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
1032 javaAudioTrackFields.postNativeEventInJava);
1033 lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
1034 }
1035
android_media_AudioTrack_disableDeviceCallback(JNIEnv * env,jobject thiz)1036 static void android_media_AudioTrack_disableDeviceCallback(
1037 JNIEnv *env, jobject thiz) {
1038
1039 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1040 if (lpTrack == NULL) {
1041 return;
1042 }
1043 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1044 thiz, javaAudioTrackFields.jniData);
1045 if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
1046 return;
1047 }
1048 lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
1049 pJniStorage->mDeviceCallback.clear();
1050 }
1051
1052
1053 // ----------------------------------------------------------------------------
1054 // ----------------------------------------------------------------------------
1055 static JNINativeMethod gMethods[] = {
1056 // name, signature, funcPtr
1057 {"native_start", "()V", (void *)android_media_AudioTrack_start},
1058 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
1059 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
1060 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
1061 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I",
1062 (void *)android_media_AudioTrack_setup},
1063 {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
1064 {"native_release", "()V", (void *)android_media_AudioTrack_release},
1065 {"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
1066 {"native_write_native_bytes",
1067 "(Ljava/lang/Object;IIIZ)I",
1068 (void *)android_media_AudioTrack_write_native_bytes},
1069 {"native_write_short", "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
1070 {"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
1071 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
1072 {"native_get_native_frame_count",
1073 "()I", (void *)android_media_AudioTrack_get_native_frame_count},
1074 {"native_set_playback_rate",
1075 "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
1076 {"native_get_playback_rate",
1077 "()I", (void *)android_media_AudioTrack_get_playback_rate},
1078 {"native_set_playback_params",
1079 "(Landroid/media/PlaybackParams;)V",
1080 (void *)android_media_AudioTrack_set_playback_params},
1081 {"native_get_playback_params",
1082 "()Landroid/media/PlaybackParams;",
1083 (void *)android_media_AudioTrack_get_playback_params},
1084 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
1085 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
1086 {"native_set_pos_update_period",
1087 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
1088 {"native_get_pos_update_period",
1089 "()I", (void *)android_media_AudioTrack_get_pos_update_period},
1090 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
1091 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
1092 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
1093 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
1094 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
1095 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
1096 {"native_get_output_sample_rate",
1097 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
1098 {"native_get_min_buff_size",
1099 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
1100 {"native_setAuxEffectSendLevel",
1101 "(F)I", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
1102 {"native_attachAuxEffect",
1103 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
1104 {"native_setOutputDevice", "(I)Z",
1105 (void *)android_media_AudioTrack_setOutputDevice},
1106 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
1107 {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
1108 {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
1109 };
1110
1111
1112 // field names found in android/media/AudioTrack.java
1113 #define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
1114 #define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
1115 #define JAVA_JNIDATA_FIELD_NAME "mJniData"
1116 #define JAVA_STREAMTYPE_FIELD_NAME "mStreamType"
1117
1118 // ----------------------------------------------------------------------------
1119 // preconditions:
1120 // theClass is valid
android_media_getIntConstantFromClass(JNIEnv * pEnv,jclass theClass,const char * className,const char * constName,int * constVal)1121 bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1122 const char* constName, int* constVal) {
1123 jfieldID javaConst = NULL;
1124 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1125 if (javaConst != NULL) {
1126 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1127 return true;
1128 } else {
1129 ALOGE("Can't find %s.%s", className, constName);
1130 return false;
1131 }
1132 }
1133
1134
1135 // ----------------------------------------------------------------------------
register_android_media_AudioTrack(JNIEnv * env)1136 int register_android_media_AudioTrack(JNIEnv *env)
1137 {
1138 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1139 javaAudioTrackFields.postNativeEventInJava = NULL;
1140
1141 // Get the AudioTrack class
1142 jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
1143
1144 // Get the postEvent method
1145 javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1146 audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1147 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1148
1149 // Get the variables fields
1150 // nativeTrackInJavaObj
1151 javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1152 audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
1153 // jniData
1154 javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1155 audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
1156 // fieldStreamType
1157 javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1158 audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
1159
1160 env->DeleteLocalRef(audioTrackClass);
1161
1162 // Get the AudioAttributes class and fields
1163 jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
1164 javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
1165 javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
1166 audioAttrClass, "mContentType", "I");
1167 javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
1168 javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
1169 audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
1170
1171 env->DeleteLocalRef(audioAttrClass);
1172
1173 // initialize PlaybackParams field info
1174 gPlaybackParamsFields.init(env);
1175
1176 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1177 }
1178
1179
1180 // ----------------------------------------------------------------------------
1181