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