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