• 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_JNIUtils.h"
41 #include "android_media_MediaMetricsJNI.h"
42 #include "android_media_PlaybackParams.h"
43 #include "android_media_VolumeShaper.h"
44 
45 #include <cinttypes>
46 
47 // ----------------------------------------------------------------------------
48 
49 using namespace android;
50 
51 using ::android::media::VolumeShaper;
52 
53 // ----------------------------------------------------------------------------
54 static const char* const kClassPathName = "android/media/AudioTrack";
55 
56 struct audio_track_fields_t {
57     // these fields provide access from C++ to the...
58     jmethodID postNativeEventInJava; //... event post callback method
59     jfieldID  nativeTrackInJavaObj;  // stores in Java the native AudioTrack object
60     jfieldID  jniData;      // stores in Java additional resources used by the native AudioTrack
61     jfieldID  fieldStreamType; // ... mStreamType field in the AudioTrack Java object
62 };
63 static audio_track_fields_t      javaAudioTrackFields;
64 static PlaybackParams::fields_t gPlaybackParamsFields;
65 static VolumeShaperHelper::fields_t gVolumeShaperFields;
66 
67 class AudioTrackCallbackImpl : public AudioTrack::IAudioTrackCallback {
68   public:
69     enum event_type {
70     // Keep in sync with java
71         EVENT_MORE_DATA = 0,
72         EVENT_UNDERRUN = 1,
73         EVENT_LOOP_END = 2,
74         EVENT_MARKER = 3,
75         EVENT_NEW_POS = 4,
76         EVENT_BUFFER_END = 5,
77         EVENT_NEW_IAUDIOTRACK = 6,
78         EVENT_STREAM_END = 7,
79         // 8 is reserved for future use
80         EVENT_CAN_WRITE_MORE_DATA = 9
81     };
82 
AudioTrackCallbackImpl(jclass audioTrackClass,jobject audioTrackWeakRef,bool isOffload)83     AudioTrackCallbackImpl(jclass audioTrackClass, jobject audioTrackWeakRef, bool isOffload)
84           : mIsOffload(isOffload)
85     {
86       const auto env = getJNIEnvOrDie();
87       mAudioTrackClass = (jclass)env->NewGlobalRef(audioTrackClass);
88       // we use a weak reference so the AudioTrack object can be garbage collected.
89       mAudioTrackWeakRef = env->NewGlobalRef(audioTrackWeakRef);
90 
91     }
92 
93     AudioTrackCallbackImpl(const AudioTrackCallbackImpl&) = delete;
94     AudioTrackCallbackImpl& operator=(const AudioTrackCallbackImpl&) = delete;
~AudioTrackCallbackImpl()95     ~AudioTrackCallbackImpl() {
96         const auto env = getJNIEnvOrDie();
97         env->DeleteGlobalRef(mAudioTrackClass);
98         env->DeleteGlobalRef(mAudioTrackWeakRef);
99     }
100 
onCanWriteMoreData(const AudioTrack::Buffer & buffer)101     size_t onCanWriteMoreData(const AudioTrack::Buffer& buffer) override {
102       if (!mIsOffload) {
103           LOG_FATAL("Received canWrite callback for non-offload track");
104           return 0;
105       }
106       const size_t availableForWrite = buffer.size();
107       const int arg = availableForWrite > INT32_MAX ? INT32_MAX : (int) availableForWrite;
108       postEvent(EVENT_CAN_WRITE_MORE_DATA, arg);
109       return 0;
110     }
111 
onMarker(uint32_t markerPosition)112     void onMarker([[maybe_unused]] uint32_t markerPosition) override {
113         postEvent(EVENT_MARKER);
114     }
onNewPos(uint32_t newPos)115     void onNewPos([[maybe_unused]] uint32_t newPos) override {
116         postEvent(EVENT_NEW_POS);
117     }
118 
119 
onNewIAudioTrack()120     void onNewIAudioTrack() override {
121         if (!mIsOffload) return;
122         postEvent(EVENT_NEW_IAUDIOTRACK);
123     }
124 
onStreamEnd()125     void onStreamEnd() override {
126         if (!mIsOffload) return;
127         postEvent(EVENT_STREAM_END);
128     }
129 
130   protected:
131     jobject     mAudioTrackWeakRef;
132   private:
133 
postEvent(int event,int arg=0)134      void postEvent(int event, int arg = 0) {
135         auto env = getJNIEnvOrDie();
136         env->CallStaticVoidMethod(
137                 mAudioTrackClass,
138                 javaAudioTrackFields.postNativeEventInJava,
139                 mAudioTrackWeakRef, event, arg, 0, NULL);
140         if (env->ExceptionCheck()) {
141             env->ExceptionDescribe();
142             env->ExceptionClear();
143         }
144     }
145 
146     jclass      mAudioTrackClass;
147     const bool  mIsOffload;
148 };
149 
150 // keep these values in sync with AudioTrack.java
151 #define MODE_STATIC 0
152 #define MODE_STREAM 1
153 
154 // ----------------------------------------------------------------------------
155 class AudioTrackJniStorage : public virtual RefBase,
156                              public AudioTrackCallbackImpl
157 {
158 public:
159     // TODO do we always want to initialize the callback implementation?
AudioTrackJniStorage(jclass audioTrackClass,jobject audioTrackRef,bool isOffload=false)160     AudioTrackJniStorage(jclass audioTrackClass, jobject audioTrackRef, bool isOffload = false)
161           : AudioTrackCallbackImpl(audioTrackClass, audioTrackRef, isOffload) {}
162 
163     sp<JNIDeviceCallback> mDeviceCallback;
164     sp<JNIAudioTrackCallback> mAudioTrackCallback;
165 
getAudioTrackWeakRef() const166     jobject getAudioTrackWeakRef() const {
167         return mAudioTrackWeakRef;
168     }
169 
170 };
171 
172 class TunerConfigurationHelper {
173     JNIEnv *const mEnv;
174     jobject const mTunerConfiguration;
175 
176     struct Ids {
IdsTunerConfigurationHelper::Ids177         Ids(JNIEnv *env)
178               : mClass(FindClassOrDie(env, "android/media/AudioTrack$TunerConfiguration")),
179                 mContentId(GetFieldIDOrDie(env, mClass, "mContentId", "I")),
180                 mSyncId(GetFieldIDOrDie(env, mClass, "mSyncId", "I")) {}
181         const jclass mClass;
182         const jfieldID mContentId;
183         const jfieldID mSyncId;
184     };
185 
getIds(JNIEnv * env)186     static const Ids &getIds(JNIEnv *env) {
187         // Meyer's singleton, initializes first time control passes through
188         // declaration in a block and is thread-safe per ISO/IEC 14882:2011 6.7.4.
189         static Ids ids(env);
190         return ids;
191     }
192 
193 public:
TunerConfigurationHelper(JNIEnv * env,jobject tunerConfiguration)194     TunerConfigurationHelper(JNIEnv *env, jobject tunerConfiguration)
195           : mEnv(env), mTunerConfiguration(tunerConfiguration) {}
196 
getContentId() const197     int32_t getContentId() const {
198         if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
199         const Ids &ids = getIds(mEnv);
200         return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mContentId);
201     }
202 
getSyncId() const203     int32_t getSyncId() const {
204         if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
205         const Ids &ids = getIds(mEnv);
206         return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mSyncId);
207     }
208 
209     // optional check to confirm class and field ids can be found.
initCheckOrDie(JNIEnv * env)210     static void initCheckOrDie(JNIEnv *env) { (void)getIds(env); }
211 };
212 
213 
214 // ----------------------------------------------------------------------------
215 #define DEFAULT_OUTPUT_SAMPLE_RATE   44100
216 
217 #define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM         (-16)
218 #define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK  (-17)
219 #define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT       (-18)
220 #define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE   (-19)
221 #define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED    (-20)
222 
223 namespace {
allocSharedMem(int sizeInBytes)224 sp<IMemory> allocSharedMem(int sizeInBytes) {
225     const auto heap = sp<MemoryHeapBase>::make(sizeInBytes, 0, "AudioTrack Heap Base");
226     if (heap->getBase() == MAP_FAILED || heap->getBase() == nullptr) {
227         return nullptr;
228     }
229     return sp<MemoryBase>::make(heap, 0, sizeInBytes);
230 }
231 
getAudioTrack(JNIEnv * env,jobject thiz)232 sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz) {
233     return getFieldSp<AudioTrack>(env, thiz, javaAudioTrackFields.nativeTrackInJavaObj);
234 }
235 
236 } // anonymous
237 // ----------------------------------------------------------------------------
238 // For MediaSync
android_media_AudioTrack_getAudioTrack(JNIEnv * env,jobject audioTrackObj)239 sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
240     return getAudioTrack(env, audioTrackObj);
241 }
242 
243 // ----------------------------------------------------------------------------
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)244 static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
245                                            jobject jaa, jintArray jSampleRate,
246                                            jint channelPositionMask, jint channelIndexMask,
247                                            jint audioFormat, jint buffSizeInBytes, jint memoryMode,
248                                            jintArray jSession, jlong nativeAudioTrack,
249                                            jboolean offload, jint encapsulationMode,
250                                            jobject tunerConfiguration, 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 = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
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->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
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         // TODO b/182469354: make consistent with AudioRecord
327         AttributionSourceState attributionSource;
328         attributionSource.packageName = std::string(opPackageNameStr.c_str());
329         attributionSource.token = sp<BBinder>::make();
330         lpTrack = sp<AudioTrack>::make(attributionSource);
331 
332         // read the AudioAttributes values
333         auto paa = JNIAudioAttributeHelper::makeUnique();
334         jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
335         if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
336             return jStatus;
337         }
338         ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
339                 paa->usage, paa->content_type, paa->flags, paa->tags);
340 
341         // initialize the callback information:
342         // this data will be passed with every AudioTrack callback
343         audio_offload_info_t offloadInfo;
344         if (offload == JNI_TRUE) {
345             offloadInfo = AUDIO_INFO_INITIALIZER;
346             offloadInfo.format = format;
347             offloadInfo.sample_rate = sampleRateInHertz;
348             offloadInfo.channel_mask = nativeChannelMask;
349             offloadInfo.has_video = false;
350             offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
351         }
352 
353         if (encapsulationMode != 0) {
354             offloadInfo = AUDIO_INFO_INITIALIZER;
355             offloadInfo.format = format;
356             offloadInfo.sample_rate = sampleRateInHertz;
357             offloadInfo.channel_mask = nativeChannelMask;
358             offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
359             offloadInfo.encapsulation_mode =
360                     static_cast<audio_encapsulation_mode_t>(encapsulationMode);
361             offloadInfo.content_id = tunerHelper.getContentId();
362             offloadInfo.sync_id = tunerHelper.getSyncId();
363         }
364 
365         // initialize the native AudioTrack object
366         status_t status = NO_ERROR;
367         switch (memoryMode) {
368         case MODE_STREAM:
369             status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed
370                                                         // in paa (last argument)
371                                   sampleRateInHertz,
372                                   format, // word length, PCM
373                                   nativeChannelMask, offload ? 0 : frameCount,
374                                   offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
375                                           : AUDIO_OUTPUT_FLAG_NONE,
376                                   lpJniStorage,
377                                   0,    // notificationFrames == 0 since not using EVENT_MORE_DATA
378                                         // to feed the AudioTrack
379                                   0,    // shared mem
380                                   true, // thread can call Java
381                                   sessionId, // audio session ID
382                                   offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK
383                                           : AudioTrack::TRANSFER_SYNC,
384                                   (offload || encapsulationMode) ? &offloadInfo : NULL,
385                                   AttributionSourceState(), // default uid, pid values
386                                   paa.get());
387             break;
388 
389         case MODE_STATIC:
390         {
391             // AudioTrack is using shared memory
392             const auto iMem = allocSharedMem(buffSizeInBytes);
393             if (iMem == nullptr) {
394                 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
395                 goto native_init_failure;
396             }
397 
398             status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed
399                                                         // in paa (last argument)
400                                   sampleRateInHertz,
401                                   format, // word length, PCM
402                                   nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE,
403                                   lpJniStorage,
404                                   0, // notificationFrames == 0 since not using EVENT_MORE_DATA
405                                      // to feed the AudioTrack
406                                   iMem,                   // shared mem
407                                   true,                   // thread can call Java
408                                   sessionId,              // audio session ID
409                                   AudioTrack::TRANSFER_SHARED,
410                                   nullptr ,               // default offloadInfo
411                                   AttributionSourceState(), // default uid, pid values
412                                   paa.get());
413             break;
414         }
415         default:
416             ALOGE("Unknown mode %d", memoryMode);
417             goto native_init_failure;
418         }
419 
420         if (status != NO_ERROR) {
421             ALOGE("Error %d initializing AudioTrack", status);
422             goto native_init_failure;
423         }
424         // Set caller name so it can be logged in destructor.
425         // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA
426         lpTrack->setCallerName("java");
427     } else {  // end if (nativeAudioTrack == 0)
428         lpTrack = sp<AudioTrack>::fromExisting(reinterpret_cast<AudioTrack*>(nativeAudioTrack));
429         // TODO: We need to find out which members of the Java AudioTrack might
430         // need to be initialized from the Native AudioTrack
431         // these are directly returned from getters:
432         //  mSampleRate
433         //  mAudioFormat
434         //  mStreamType
435         //  mChannelConfiguration
436         //  mChannelCount
437         //  mState (?)
438         //  mPlayState (?)
439         // these may be used internally (Java AudioTrack.audioParamCheck():
440         //  mChannelMask
441         //  mChannelIndexMask
442         //  mDataLoadMode
443 
444         // initialize the callback information:
445         // this data will be passed with every AudioTrack callback
446 
447         // TODO this callback information is useless, it isn't passed to the
448         // native AudioTrack object
449         /*
450         lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
451         // we use a weak reference so the AudioTrack object can be garbage collected.
452         lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
453         lpJniStorage->mCallbackData.busy = false;
454         */
455     }
456     lpJniStorage->mAudioTrackCallback =
457             sp<JNIAudioTrackCallback>::make(env, thiz, lpJniStorage->getAudioTrackWeakRef(),
458                                             javaAudioTrackFields.postNativeEventInJava);
459     lpTrack->setAudioTrackCallback(lpJniStorage->mAudioTrackCallback);
460 
461     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
462     if (nSession == NULL) {
463         ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
464         goto native_init_failure;
465     }
466     // read the audio session ID back from AudioTrack in case we create a new session
467     nSession[0] = lpTrack->getSessionId();
468     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
469     nSession = NULL;
470 
471     {
472         const jint elements[1] = { (jint) lpTrack->getSampleRate() };
473         env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
474     }
475 
476     // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
477     // of the Java object (in mNativeTrackInJavaObj)
478     setFieldSp(env, thiz, lpTrack, javaAudioTrackFields.nativeTrackInJavaObj);
479 
480     // save the JNI resources so we can free them later
481     //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
482     setFieldSp(env, thiz, lpJniStorage, javaAudioTrackFields.jniData);
483 
484     // since we had audio attributes, the stream type was derived from them during the
485     // creation of the native AudioTrack: push the same value to the Java object
486     env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
487 
488     return (jint) AUDIO_JAVA_SUCCESS;
489 
490     // failures:
491 native_init_failure:
492     if (nSession != NULL) {
493         env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
494     }
495 
496     setFieldSp(env, thiz, sp<AudioTrack>{}, javaAudioTrackFields.nativeTrackInJavaObj);
497     setFieldSp(env, thiz, sp<AudioTrackJniStorage>{}, javaAudioTrackFields.jniData);
498     // lpTrack goes out of scope, so reference count drops to zero
499     return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
500 }
501 
502 // ----------------------------------------------------------------------------
503 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)504 android_media_AudioTrack_is_direct_output_supported(JNIEnv *env, jobject thiz,
505                                              jint encoding, jint sampleRate,
506                                              jint channelMask, jint channelIndexMask,
507                                              jint contentType, jint usage, jint flags) {
508     audio_config_base_t config = {};
509     audio_attributes_t attributes = {};
510     config.format = static_cast<audio_format_t>(audioFormatToNative(encoding));
511     config.sample_rate = static_cast<uint32_t>(sampleRate);
512     config.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
513     attributes.content_type = static_cast<audio_content_type_t>(contentType);
514     attributes.usage = static_cast<audio_usage_t>(usage);
515     attributes.flags = static_cast<audio_flags_mask_t>(flags);
516     // ignore source and tags attributes as they don't affect querying whether output is supported
517     return AudioTrack::isDirectOutputSupported(config, attributes);
518 }
519 
520 // ----------------------------------------------------------------------------
521 static void
android_media_AudioTrack_start(JNIEnv * env,jobject thiz)522 android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
523 {
524     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
525     if (lpTrack == NULL) {
526         jniThrowException(env, "java/lang/IllegalStateException",
527             "Unable to retrieve AudioTrack pointer for start()");
528         return;
529     }
530 
531     lpTrack->start();
532 }
533 
534 
535 // ----------------------------------------------------------------------------
536 static void
android_media_AudioTrack_stop(JNIEnv * env,jobject thiz)537 android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
538 {
539     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
540     if (lpTrack == NULL) {
541         jniThrowException(env, "java/lang/IllegalStateException",
542             "Unable to retrieve AudioTrack pointer for stop()");
543         return;
544     }
545 
546     lpTrack->stop();
547 }
548 
549 
550 // ----------------------------------------------------------------------------
551 static void
android_media_AudioTrack_pause(JNIEnv * env,jobject thiz)552 android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
553 {
554     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
555     if (lpTrack == NULL) {
556         jniThrowException(env, "java/lang/IllegalStateException",
557             "Unable to retrieve AudioTrack pointer for pause()");
558         return;
559     }
560 
561     lpTrack->pause();
562 }
563 
564 
565 // ----------------------------------------------------------------------------
566 static void
android_media_AudioTrack_flush(JNIEnv * env,jobject thiz)567 android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
568 {
569     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
570     if (lpTrack == NULL) {
571         jniThrowException(env, "java/lang/IllegalStateException",
572             "Unable to retrieve AudioTrack pointer for flush()");
573         return;
574     }
575 
576     lpTrack->flush();
577 }
578 
579 // ----------------------------------------------------------------------------
580 static void
android_media_AudioTrack_set_volume(JNIEnv * env,jobject thiz,jfloat leftVol,jfloat rightVol)581 android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
582 {
583     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
584     if (lpTrack == NULL) {
585         jniThrowException(env, "java/lang/IllegalStateException",
586             "Unable to retrieve AudioTrack pointer for setVolume()");
587         return;
588     }
589 
590     lpTrack->setVolume(leftVol, rightVol);
591 }
592 
593 // ----------------------------------------------------------------------------
594 
android_media_AudioTrack_release(JNIEnv * env,jobject thiz)595 static void android_media_AudioTrack_release(JNIEnv *env,  jobject thiz) {
596     setFieldSp(env, thiz, sp<AudioTrack>(nullptr), javaAudioTrackFields.nativeTrackInJavaObj);
597     setFieldSp(env, thiz, sp<AudioTrackJniStorage>(nullptr), javaAudioTrackFields.jniData);
598 }
599 
600 
601 // ----------------------------------------------------------------------------
android_media_AudioTrack_finalize(JNIEnv * env,jobject thiz)602 static void android_media_AudioTrack_finalize(JNIEnv *env,  jobject thiz) {
603     //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
604     android_media_AudioTrack_release(env, thiz);
605 }
606 
607 // overloaded JNI array helper functions (same as in android_media_AudioRecord)
608 static inline
envGetArrayElements(JNIEnv * env,jbyteArray array,jboolean * isCopy)609 jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
610     return env->GetByteArrayElements(array, isCopy);
611 }
612 
613 static inline
envReleaseArrayElements(JNIEnv * env,jbyteArray array,jbyte * elems,jint mode)614 void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
615     env->ReleaseByteArrayElements(array, elems, mode);
616 }
617 
618 static inline
envGetArrayElements(JNIEnv * env,jshortArray array,jboolean * isCopy)619 jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
620     return env->GetShortArrayElements(array, isCopy);
621 }
622 
623 static inline
envReleaseArrayElements(JNIEnv * env,jshortArray array,jshort * elems,jint mode)624 void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
625     env->ReleaseShortArrayElements(array, elems, mode);
626 }
627 
628 static inline
envGetArrayElements(JNIEnv * env,jfloatArray array,jboolean * isCopy)629 jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
630     return env->GetFloatArrayElements(array, isCopy);
631 }
632 
633 static inline
envReleaseArrayElements(JNIEnv * env,jfloatArray array,jfloat * elems,jint mode)634 void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
635     env->ReleaseFloatArrayElements(array, elems, mode);
636 }
637 
638 static inline
interpretWriteSizeError(ssize_t writeSize)639 jint interpretWriteSizeError(ssize_t writeSize) {
640     if (writeSize == WOULD_BLOCK) {
641         return (jint)0;
642     } else if (writeSize == NO_INIT) {
643         return AUDIO_JAVA_DEAD_OBJECT;
644     } else {
645         ALOGE("Error %zd during AudioTrack native read", writeSize);
646         return nativeToJavaStatus(writeSize);
647     }
648 }
649 
650 // ----------------------------------------------------------------------------
651 template <typename T>
writeToTrack(const sp<AudioTrack> & track,jint audioFormat,const T * data,jint offsetInSamples,jint sizeInSamples,bool blocking)652 static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
653                          jint offsetInSamples, jint sizeInSamples, bool blocking) {
654     // give the data to the native AudioTrack object (the data starts at the offset)
655     ssize_t written = 0;
656     // regular write() or copy the data to the AudioTrack's shared memory?
657     size_t sizeInBytes = sizeInSamples * sizeof(T);
658     if (track->sharedBuffer() == 0) {
659         written = track->write(data + offsetInSamples, sizeInBytes, blocking);
660         // for compatibility with earlier behavior of write(), return 0 in this case
661         if (written == (ssize_t) WOULD_BLOCK) {
662             written = 0;
663         }
664     } else {
665         // writing to shared memory, check for capacity
666         if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
667             sizeInBytes = track->sharedBuffer()->size();
668         }
669         memcpy(track->sharedBuffer()->unsecurePointer(), data + offsetInSamples, sizeInBytes);
670         written = sizeInBytes;
671     }
672     if (written >= 0) {
673         return written / sizeof(T);
674     }
675     return interpretWriteSizeError(written);
676 }
677 
678 // ----------------------------------------------------------------------------
679 template <typename T>
android_media_AudioTrack_writeArray(JNIEnv * env,jobject thiz,T javaAudioData,jint offsetInSamples,jint sizeInSamples,jint javaAudioFormat,jboolean isWriteBlocking)680 static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
681                                                 T javaAudioData,
682                                                 jint offsetInSamples, jint sizeInSamples,
683                                                 jint javaAudioFormat,
684                                                 jboolean isWriteBlocking) {
685     //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
686     //        offsetInSamples, sizeInSamples);
687     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
688     if (lpTrack == NULL) {
689         jniThrowException(env, "java/lang/IllegalStateException",
690             "Unable to retrieve AudioTrack pointer for write()");
691         return (jint)AUDIO_JAVA_INVALID_OPERATION;
692     }
693 
694     if (javaAudioData == NULL) {
695         ALOGE("NULL java array of audio data to play");
696         return (jint)AUDIO_JAVA_BAD_VALUE;
697     }
698 
699     // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
700     // a way that it becomes much more efficient. When doing so, we will have to prevent the
701     // AudioSystem callback to be called while in critical section (in case of media server
702     // process crash for instance)
703 
704     // get the pointer for the audio data from the java array
705     auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
706     if (cAudioData == NULL) {
707         ALOGE("Error retrieving source of audio data to play");
708         return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
709     }
710 
711     jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
712             offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
713 
714     envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
715 
716     //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
717     //        (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
718     return samplesWritten;
719 }
720 
721 // ----------------------------------------------------------------------------
android_media_AudioTrack_write_native_bytes(JNIEnv * env,jobject thiz,jobject javaByteBuffer,jint byteOffset,jint sizeInBytes,jint javaAudioFormat,jboolean isWriteBlocking)722 static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env,  jobject thiz,
723         jobject javaByteBuffer, jint byteOffset, jint sizeInBytes,
724         jint javaAudioFormat, jboolean isWriteBlocking) {
725     //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
726     //    offsetInBytes, sizeInBytes);
727     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
728     if (lpTrack == NULL) {
729         jniThrowException(env, "java/lang/IllegalStateException",
730                 "Unable to retrieve AudioTrack pointer for write()");
731         return (jint)AUDIO_JAVA_INVALID_OPERATION;
732     }
733 
734     const jbyte* bytes =
735             reinterpret_cast<const jbyte*>(env->GetDirectBufferAddress(javaByteBuffer));
736     if (bytes == NULL) {
737         ALOGE("Error retrieving source of audio data to play, can't play");
738         return (jint)AUDIO_JAVA_BAD_VALUE;
739     }
740 
741     jint written = writeToTrack(lpTrack, javaAudioFormat, bytes, byteOffset,
742             sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
743 
744     return written;
745 }
746 
747 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_buffer_size_frames(JNIEnv * env,jobject thiz)748 static jint android_media_AudioTrack_get_buffer_size_frames(JNIEnv *env,  jobject thiz) {
749     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
750     if (lpTrack == NULL) {
751         jniThrowException(env, "java/lang/IllegalStateException",
752             "Unable to retrieve AudioTrack pointer for getBufferSizeInFrames()");
753         return (jint)AUDIO_JAVA_ERROR;
754     }
755 
756     ssize_t result = lpTrack->getBufferSizeInFrames();
757     if (result < 0) {
758         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
759             "Internal error detected in getBufferSizeInFrames() = %zd", result);
760         return (jint)AUDIO_JAVA_ERROR;
761     }
762     return (jint)result;
763 }
764 
765 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_buffer_size_frames(JNIEnv * env,jobject thiz,jint bufferSizeInFrames)766 static jint android_media_AudioTrack_set_buffer_size_frames(JNIEnv *env,
767         jobject thiz, jint bufferSizeInFrames) {
768     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
769     if (lpTrack == NULL) {
770         jniThrowException(env, "java/lang/IllegalStateException",
771             "Unable to retrieve AudioTrack pointer for setBufferSizeInFrames()");
772         return (jint)AUDIO_JAVA_ERROR;
773     }
774     // Value will be coerced into the valid range.
775     // But internal values are unsigned, size_t, so we need to clip
776     // against zero here where it is signed.
777     if (bufferSizeInFrames < 0) {
778         bufferSizeInFrames = 0;
779     }
780     ssize_t result = lpTrack->setBufferSizeInFrames(bufferSizeInFrames);
781     if (result < 0) {
782         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
783             "Internal error detected in setBufferSizeInFrames() = %zd", result);
784         return (jint)AUDIO_JAVA_ERROR;
785     }
786     return (jint)result;
787 }
788 
789 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv * env,jobject thiz)790 static jint android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv *env,  jobject thiz) {
791     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
792     if (lpTrack == NULL) {
793         jniThrowException(env, "java/lang/IllegalStateException",
794             "Unable to retrieve AudioTrack pointer for getBufferCapacityInFrames()");
795         return (jint)AUDIO_JAVA_ERROR;
796     }
797 
798     return lpTrack->frameCount();
799 }
800 
801 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_playback_rate(JNIEnv * env,jobject thiz,jint sampleRateInHz)802 static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env,  jobject thiz,
803         jint sampleRateInHz) {
804     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
805     if (lpTrack == NULL) {
806         jniThrowException(env, "java/lang/IllegalStateException",
807             "Unable to retrieve AudioTrack pointer for setSampleRate()");
808         return (jint)AUDIO_JAVA_ERROR;
809     }
810     return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
811 }
812 
813 
814 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_playback_rate(JNIEnv * env,jobject thiz)815 static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env,  jobject thiz) {
816     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
817     if (lpTrack == NULL) {
818         jniThrowException(env, "java/lang/IllegalStateException",
819             "Unable to retrieve AudioTrack pointer for getSampleRate()");
820         return (jint)AUDIO_JAVA_ERROR;
821     }
822     return (jint) lpTrack->getSampleRate();
823 }
824 
825 
826 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_playback_params(JNIEnv * env,jobject thiz,jobject params)827 static void android_media_AudioTrack_set_playback_params(JNIEnv *env,  jobject thiz,
828         jobject params) {
829     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
830     if (lpTrack == NULL) {
831         jniThrowException(env, "java/lang/IllegalStateException",
832             "AudioTrack not initialized");
833         return;
834     }
835 
836     PlaybackParams pbp;
837     pbp.fillFromJobject(env, gPlaybackParamsFields, params);
838 
839     ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
840             pbp.speedSet, pbp.audioRate.mSpeed,
841             pbp.pitchSet, pbp.audioRate.mPitch,
842             pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
843             pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
844 
845     // to simulate partially set params, we do a read-modify-write.
846     // TODO: pass in the valid set mask into AudioTrack.
847     AudioPlaybackRate rate = lpTrack->getPlaybackRate();
848     bool updatedRate = false;
849     if (pbp.speedSet) {
850         rate.mSpeed = pbp.audioRate.mSpeed;
851         updatedRate = true;
852     }
853     if (pbp.pitchSet) {
854         rate.mPitch = pbp.audioRate.mPitch;
855         updatedRate = true;
856     }
857     if (pbp.audioFallbackModeSet) {
858         rate.mFallbackMode = pbp.audioRate.mFallbackMode;
859         updatedRate = true;
860     }
861     if (pbp.audioStretchModeSet) {
862         rate.mStretchMode = pbp.audioRate.mStretchMode;
863         updatedRate = true;
864     }
865     if (updatedRate) {
866         if (lpTrack->setPlaybackRate(rate) != OK) {
867             jniThrowException(env, "java/lang/IllegalArgumentException",
868                     "arguments out of range");
869         }
870     }
871 }
872 
873 
874 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_playback_params(JNIEnv * env,jobject thiz,jobject params)875 static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env,  jobject thiz,
876         jobject params) {
877     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
878     if (lpTrack == NULL) {
879         jniThrowException(env, "java/lang/IllegalStateException",
880             "AudioTrack not initialized");
881         return NULL;
882     }
883 
884     PlaybackParams pbs;
885     pbs.audioRate = lpTrack->getPlaybackRate();
886     pbs.speedSet = true;
887     pbs.pitchSet = true;
888     pbs.audioFallbackModeSet = true;
889     pbs.audioStretchModeSet = true;
890     return pbs.asJobject(env, gPlaybackParamsFields);
891 }
892 
893 
894 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_marker_pos(JNIEnv * env,jobject thiz,jint markerPos)895 static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env,  jobject thiz,
896         jint markerPos) {
897     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
898     if (lpTrack == NULL) {
899         jniThrowException(env, "java/lang/IllegalStateException",
900             "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
901         return (jint)AUDIO_JAVA_ERROR;
902     }
903     return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
904 }
905 
906 
907 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_marker_pos(JNIEnv * env,jobject thiz)908 static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env,  jobject thiz) {
909     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
910     uint32_t markerPos = 0;
911 
912     if (lpTrack == NULL) {
913         jniThrowException(env, "java/lang/IllegalStateException",
914             "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
915         return (jint)AUDIO_JAVA_ERROR;
916     }
917     lpTrack->getMarkerPosition(&markerPos);
918     return (jint)markerPos;
919 }
920 
921 
922 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_pos_update_period(JNIEnv * env,jobject thiz,jint period)923 static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env,  jobject thiz,
924         jint period) {
925     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
926     if (lpTrack == NULL) {
927         jniThrowException(env, "java/lang/IllegalStateException",
928             "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
929         return (jint)AUDIO_JAVA_ERROR;
930     }
931     return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
932 }
933 
934 
935 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_pos_update_period(JNIEnv * env,jobject thiz)936 static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env,  jobject thiz) {
937     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
938     uint32_t period = 0;
939 
940     if (lpTrack == NULL) {
941         jniThrowException(env, "java/lang/IllegalStateException",
942             "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
943         return (jint)AUDIO_JAVA_ERROR;
944     }
945     lpTrack->getPositionUpdatePeriod(&period);
946     return (jint)period;
947 }
948 
949 
950 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_position(JNIEnv * env,jobject thiz,jint position)951 static jint android_media_AudioTrack_set_position(JNIEnv *env,  jobject thiz,
952         jint position) {
953     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
954     if (lpTrack == NULL) {
955         jniThrowException(env, "java/lang/IllegalStateException",
956             "Unable to retrieve AudioTrack pointer for setPosition()");
957         return (jint)AUDIO_JAVA_ERROR;
958     }
959     return nativeToJavaStatus( lpTrack->setPosition(position) );
960 }
961 
962 
963 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_position(JNIEnv * env,jobject thiz)964 static jint android_media_AudioTrack_get_position(JNIEnv *env,  jobject thiz) {
965     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
966     uint32_t position = 0;
967 
968     if (lpTrack == NULL) {
969         jniThrowException(env, "java/lang/IllegalStateException",
970             "Unable to retrieve AudioTrack pointer for getPosition()");
971         return (jint)AUDIO_JAVA_ERROR;
972     }
973     lpTrack->getPosition(&position);
974     return (jint)position;
975 }
976 
977 
978 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_latency(JNIEnv * env,jobject thiz)979 static jint android_media_AudioTrack_get_latency(JNIEnv *env,  jobject thiz) {
980     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
981 
982     if (lpTrack == NULL) {
983         jniThrowException(env, "java/lang/IllegalStateException",
984             "Unable to retrieve AudioTrack pointer for latency()");
985         return (jint)AUDIO_JAVA_ERROR;
986     }
987     return (jint)lpTrack->latency();
988 }
989 
990 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_underrun_count(JNIEnv * env,jobject thiz)991 static jint android_media_AudioTrack_get_underrun_count(JNIEnv *env,  jobject thiz) {
992     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
993 
994     if (lpTrack == NULL) {
995         jniThrowException(env, "java/lang/IllegalStateException",
996             "Unable to retrieve AudioTrack pointer for getUnderrunCount()");
997         return (jint)AUDIO_JAVA_ERROR;
998     }
999     return (jint)lpTrack->getUnderrunCount();
1000 }
1001 
1002 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_flags(JNIEnv * env,jobject thiz)1003 static jint android_media_AudioTrack_get_flags(JNIEnv *env,  jobject thiz) {
1004     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1005 
1006     if (lpTrack == NULL) {
1007         jniThrowException(env, "java/lang/IllegalStateException",
1008             "Unable to retrieve AudioTrack pointer for getFlags()");
1009         return (jint)AUDIO_JAVA_ERROR;
1010     }
1011     return (jint)lpTrack->getFlags();
1012 }
1013 
1014 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_timestamp(JNIEnv * env,jobject thiz,jlongArray jTimestamp)1015 static jint android_media_AudioTrack_get_timestamp(JNIEnv *env,  jobject thiz, jlongArray jTimestamp) {
1016     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1017 
1018     if (lpTrack == NULL) {
1019         ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
1020         return (jint)AUDIO_JAVA_ERROR;
1021     }
1022     AudioTimestamp timestamp;
1023     status_t status = lpTrack->getTimestamp(timestamp);
1024     if (status == OK) {
1025         jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
1026         if (nTimestamp == NULL) {
1027             ALOGE("Unable to get array for getTimestamp()");
1028             return (jint)AUDIO_JAVA_ERROR;
1029         }
1030         nTimestamp[0] = (jlong) timestamp.mPosition;
1031         nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
1032         env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
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 = (jfloat *)env->GetPrimitiveArrayCritical(level, NULL);
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->ReleasePrimitiveArrayCritical(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 = (jint *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
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->ReleasePrimitiveArrayCritical(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[IJZILjava/lang/Object;Ljava/lang/String;)I",
1459          (void *)android_media_AudioTrack_setup},
1460         {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
1461         {"native_release", "()V", (void *)android_media_AudioTrack_release},
1462         {"native_write_byte", "([BIIIZ)I", (void *)android_media_AudioTrack_writeArray<jbyteArray>},
1463         {"native_write_native_bytes", "(Ljava/nio/ByteBuffer;IIIZ)I",
1464          (void *)android_media_AudioTrack_write_native_bytes},
1465         {"native_write_short", "([SIIIZ)I",
1466          (void *)android_media_AudioTrack_writeArray<jshortArray>},
1467         {"native_write_float", "([FIIIZ)I",
1468          (void *)android_media_AudioTrack_writeArray<jfloatArray>},
1469         {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
1470         {"native_get_buffer_size_frames", "()I",
1471          (void *)android_media_AudioTrack_get_buffer_size_frames},
1472         {"native_set_buffer_size_frames", "(I)I",
1473          (void *)android_media_AudioTrack_set_buffer_size_frames},
1474         {"native_get_buffer_capacity_frames", "()I",
1475          (void *)android_media_AudioTrack_get_buffer_capacity_frames},
1476         {"native_set_playback_rate", "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
1477         {"native_get_playback_rate", "()I", (void *)android_media_AudioTrack_get_playback_rate},
1478         {"native_set_playback_params", "(Landroid/media/PlaybackParams;)V",
1479          (void *)android_media_AudioTrack_set_playback_params},
1480         {"native_get_playback_params", "()Landroid/media/PlaybackParams;",
1481          (void *)android_media_AudioTrack_get_playback_params},
1482         {"native_set_marker_pos", "(I)I", (void *)android_media_AudioTrack_set_marker_pos},
1483         {"native_get_marker_pos", "()I", (void *)android_media_AudioTrack_get_marker_pos},
1484         {"native_set_pos_update_period", "(I)I",
1485          (void *)android_media_AudioTrack_set_pos_update_period},
1486         {"native_get_pos_update_period", "()I",
1487          (void *)android_media_AudioTrack_get_pos_update_period},
1488         {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
1489         {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
1490         {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
1491         {"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
1492         {"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
1493         {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
1494         {"native_getMetrics", "()Landroid/os/PersistableBundle;",
1495          (void *)android_media_AudioTrack_native_getMetrics},
1496         {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
1497         {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
1498         {"native_get_output_sample_rate", "(I)I",
1499          (void *)android_media_AudioTrack_get_output_sample_rate},
1500         {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
1501         {"native_setAuxEffectSendLevel", "(F)I",
1502          (void *)android_media_AudioTrack_setAuxEffectSendLevel},
1503         {"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
1504         {"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
1505         {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
1506         {"native_enableDeviceCallback", "()V",
1507          (void *)android_media_AudioTrack_enableDeviceCallback},
1508         {"native_disableDeviceCallback", "()V",
1509          (void *)android_media_AudioTrack_disableDeviceCallback},
1510         {"native_applyVolumeShaper",
1511          "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
1512          (void *)android_media_AudioTrack_apply_volume_shaper},
1513         {"native_getVolumeShaperState", "(I)Landroid/media/VolumeShaper$State;",
1514          (void *)android_media_AudioTrack_get_volume_shaper_state},
1515         {"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
1516         {"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
1517         {"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
1518         {"native_set_audio_description_mix_level_db", "(F)I",
1519          (void *)android_media_AudioTrack_setAudioDescriptionMixLeveldB},
1520         {"native_get_audio_description_mix_level_db", "([F)I",
1521          (void *)android_media_AudioTrack_getAudioDescriptionMixLeveldB},
1522         {"native_set_dual_mono_mode", "(I)I", (void *)android_media_AudioTrack_setDualMonoMode},
1523         {"native_get_dual_mono_mode", "([I)I", (void *)android_media_AudioTrack_getDualMonoMode},
1524         {"native_setLogSessionId", "(Ljava/lang/String;)V",
1525          (void *)android_media_AudioTrack_setLogSessionId},
1526         {"native_setPlayerIId", "(I)V", (void *)android_media_AudioTrack_setPlayerIId},
1527         {"native_setStartThresholdInFrames", "(I)I",
1528          (void *)android_media_AudioTrack_setStartThresholdInFrames},
1529         {"native_getStartThresholdInFrames", "()I",
1530          (void *)android_media_AudioTrack_getStartThresholdInFrames},
1531 };
1532 
1533 // field names found in android/media/AudioTrack.java
1534 #define JAVA_POSTEVENT_CALLBACK_NAME                    "postEventFromNative"
1535 #define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME            "mNativeTrackInJavaObj"
1536 #define JAVA_JNIDATA_FIELD_NAME                         "mJniData"
1537 #define JAVA_STREAMTYPE_FIELD_NAME                      "mStreamType"
1538 
1539 // ----------------------------------------------------------------------------
1540 // preconditions:
1541 //    theClass is valid
android_media_getIntConstantFromClass(JNIEnv * pEnv,jclass theClass,const char * className,const char * constName,int * constVal)1542 bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1543                              const char* constName, int* constVal) {
1544     jfieldID javaConst = NULL;
1545     javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1546     if (javaConst != NULL) {
1547         *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1548         return true;
1549     } else {
1550         ALOGE("Can't find %s.%s", className, constName);
1551         return false;
1552     }
1553 }
1554 
1555 // ----------------------------------------------------------------------------
register_android_media_AudioTrack(JNIEnv * env)1556 int register_android_media_AudioTrack(JNIEnv *env)
1557 {
1558     // must be first
1559     int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1560 
1561     javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1562     javaAudioTrackFields.postNativeEventInJava = NULL;
1563 
1564     // Get the AudioTrack class
1565     jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
1566 
1567     // Get the postEvent method
1568     javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1569             audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1570             "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1571 
1572     // Get the variables fields
1573     //      nativeTrackInJavaObj
1574     javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1575             audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
1576     //      jniData
1577     javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1578             audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
1579     //      fieldStreamType
1580     javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1581             audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
1582 
1583     env->DeleteLocalRef(audioTrackClass);
1584 
1585     // initialize PlaybackParams field info
1586     gPlaybackParamsFields.init(env);
1587 
1588     gVolumeShaperFields.init(env);
1589 
1590     // optional check that the TunerConfiguration class and fields exist.
1591     TunerConfigurationHelper::initCheckOrDie(env);
1592 
1593     return res;
1594 }
1595 
1596 
1597 // ----------------------------------------------------------------------------
1598