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