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