• 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 #undef ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION // TODO:remove this and fix code
17 //#define LOG_NDEBUG 0
18 
19 #define LOG_TAG "AudioTrack-JNI"
20 
21 #include "android_media_AudioTrack.h"
22 
23 #include <android-base/macros.h>
24 #include <android_os_Parcel.h>
25 #include <binder/MemoryBase.h>
26 #include <binder/MemoryHeapBase.h>
27 #include <media/AudioParameter.h>
28 #include <media/AudioSystem.h>
29 #include <media/AudioTrack.h>
30 #include <nativehelper/JNIHelp.h>
31 #include <nativehelper/ScopedUtfChars.h>
32 #include <utils/Log.h>
33 
34 #include <cinttypes>
35 
36 #include "android_media_AudioAttributes.h"
37 #include "android_media_AudioErrors.h"
38 #include "android_media_AudioFormat.h"
39 #include "android_media_AudioTrackCallback.h"
40 #include "android_media_DeviceCallback.h"
41 #include "android_media_JNIUtils.h"
42 #include "android_media_MediaMetricsJNI.h"
43 #include "android_media_PlaybackParams.h"
44 #include "android_media_VolumeShaper.h"
45 #include "core_jni_helpers.h"
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,jobject jAttributionSource,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, jobject jAttributionSource,
249                                            jlong nativeAudioTrack, jboolean offload,
250                                            jint encapsulationMode, jobject tunerConfiguration,
251                                            jstring opPackageName) {
252     ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
253           " nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p",
254           jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
255           nativeAudioTrack, offload, encapsulationMode, tunerConfiguration);
256 
257     if (jSession == NULL) {
258         ALOGE("Error creating AudioTrack: invalid session ID pointer");
259         return (jint) AUDIO_JAVA_ERROR;
260     }
261 
262     const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
263 
264     jint* nSession = env->GetIntArrayElements(jSession, nullptr /* isCopy */);
265     if (nSession == NULL) {
266         ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
267         return (jint) AUDIO_JAVA_ERROR;
268     }
269     audio_session_t sessionId = (audio_session_t) nSession[0];
270     env->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
271     nSession = NULL;
272 
273 
274     jclass clazz = env->GetObjectClass(thiz);
275     if (clazz == NULL) {
276         ALOGE("Can't find %s when setting up callback.", kClassPathName);
277         return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
278     }
279 
280     // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
281     sp<AudioTrack> lpTrack;
282     const auto lpJniStorage = sp<AudioTrackJniStorage>::make(clazz, weak_this, offload);
283     if (nativeAudioTrack == 0) {
284         if (jaa == 0) {
285             ALOGE("Error creating AudioTrack: invalid audio attributes");
286             return (jint) AUDIO_JAVA_ERROR;
287         }
288 
289         if (jSampleRate == 0) {
290             ALOGE("Error creating AudioTrack: invalid sample rates");
291             return (jint) AUDIO_JAVA_ERROR;
292         }
293 
294         int* sampleRates = env->GetIntArrayElements(jSampleRate, NULL);
295         int sampleRateInHertz = sampleRates[0];
296         env->ReleaseIntArrayElements(jSampleRate, sampleRates, JNI_ABORT);
297 
298         // Invalid channel representations are caught by !audio_is_output_channel() below.
299         audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
300                 channelPositionMask, channelIndexMask);
301         if (!audio_is_output_channel(nativeChannelMask)) {
302             ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
303             return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
304         }
305 
306         uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
307 
308         // check the format.
309         // This function was called from Java, so we compare the format against the Java constants
310         audio_format_t format = audioFormatToNative(audioFormat);
311         if (format == AUDIO_FORMAT_INVALID) {
312             ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
313             return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
314         }
315 
316         // compute the frame count
317         size_t frameCount;
318         if (audio_has_proportional_frames(format)) {
319             const size_t bytesPerSample = audio_bytes_per_sample(format);
320             frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
321         } else {
322             frameCount = buffSizeInBytes;
323         }
324 
325         // create the native AudioTrack object
326         ScopedUtfChars opPackageNameStr(env, opPackageName);
327 
328         android::content::AttributionSourceState attributionSource;
329         attributionSource.readFromParcel(parcelForJavaObject(env, jAttributionSource));
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                                   attributionSource, // Passed from Java
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                                   attributionSource, // Passed from Java
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 = env->GetIntArrayElements(jSession, nullptr /* isCopy */);
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->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
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->ReleaseIntArrayElements(jSession, nSession, 0 /* mode */);
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 = env->GetLongArrayElements(jTimestamp, nullptr /* isCopy */);
1026         if (nTimestamp == NULL) {
1027             ALOGE("Unable to get array for getTimestamp()");
1028             return (jint)AUDIO_JAVA_ERROR;
1029         }
1030         nTimestamp[0] = static_cast<jlong>(timestamp.mPosition);
1031         nTimestamp[1] = static_cast<jlong>((timestamp.mTime.tv_sec * 1000000000LL) +
1032                                            timestamp.mTime.tv_nsec);
1033         env->ReleaseLongArrayElements(jTimestamp, nTimestamp, 0 /* mode */);
1034     }
1035     return (jint) nativeToJavaStatus(status);
1036 }
1037 
1038 // ----------------------------------------------------------------------------
1039 static jobject
android_media_AudioTrack_native_getMetrics(JNIEnv * env,jobject thiz)1040 android_media_AudioTrack_native_getMetrics(JNIEnv *env, jobject thiz)
1041 {
1042     ALOGD("android_media_AudioTrack_native_getMetrics");
1043 
1044     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1045 
1046     if (lpTrack == NULL) {
1047         ALOGE("Unable to retrieve AudioTrack pointer for getMetrics()");
1048         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1049         return (jobject) NULL;
1050     }
1051 
1052     // get what we have for the metrics from the track
1053     mediametrics::Item *item = NULL;
1054 
1055     status_t err = lpTrack->getMetrics(item);
1056     if (err != OK) {
1057         ALOGE("getMetrics failed");
1058         jniThrowException(env, "java/lang/IllegalStateException", NULL);
1059         return (jobject) NULL;
1060     }
1061 
1062     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
1063 
1064     // housekeeping
1065     delete item;
1066     item = NULL;
1067 
1068     return mybundle;
1069 }
1070 
1071 
1072 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_loop(JNIEnv * env,jobject thiz,jint loopStart,jint loopEnd,jint loopCount)1073 static jint android_media_AudioTrack_set_loop(JNIEnv *env,  jobject thiz,
1074         jint loopStart, jint loopEnd, jint loopCount) {
1075     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1076     if (lpTrack == NULL) {
1077         jniThrowException(env, "java/lang/IllegalStateException",
1078             "Unable to retrieve AudioTrack pointer for setLoop()");
1079         return (jint)AUDIO_JAVA_ERROR;
1080     }
1081     return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
1082 }
1083 
1084 
1085 // ----------------------------------------------------------------------------
android_media_AudioTrack_reload(JNIEnv * env,jobject thiz)1086 static jint android_media_AudioTrack_reload(JNIEnv *env,  jobject thiz) {
1087     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1088     if (lpTrack == NULL) {
1089         jniThrowException(env, "java/lang/IllegalStateException",
1090             "Unable to retrieve AudioTrack pointer for reload()");
1091         return (jint)AUDIO_JAVA_ERROR;
1092     }
1093     return nativeToJavaStatus( lpTrack->reload() );
1094 }
1095 
1096 
1097 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_output_sample_rate(JNIEnv * env,jobject thiz,jint javaStreamType)1098 static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env,  jobject thiz,
1099         jint javaStreamType) {
1100     uint32_t afSamplingRate;
1101     // convert the stream type from Java to native value
1102     // FIXME: code duplication with android_media_AudioTrack_setup()
1103     audio_stream_type_t nativeStreamType;
1104     switch (javaStreamType) {
1105     case AUDIO_STREAM_VOICE_CALL:
1106     case AUDIO_STREAM_SYSTEM:
1107     case AUDIO_STREAM_RING:
1108     case AUDIO_STREAM_MUSIC:
1109     case AUDIO_STREAM_ALARM:
1110     case AUDIO_STREAM_NOTIFICATION:
1111     case AUDIO_STREAM_BLUETOOTH_SCO:
1112     case AUDIO_STREAM_DTMF:
1113         nativeStreamType = (audio_stream_type_t) javaStreamType;
1114         break;
1115     default:
1116         nativeStreamType = AUDIO_STREAM_DEFAULT;
1117         break;
1118     }
1119 
1120     status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
1121     if (status != NO_ERROR) {
1122         ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
1123               "in AudioTrack JNI", status, nativeStreamType);
1124         return DEFAULT_OUTPUT_SAMPLE_RATE;
1125     } else {
1126         return afSamplingRate;
1127     }
1128 }
1129 
1130 
1131 // ----------------------------------------------------------------------------
1132 // returns the minimum required size for the successful creation of a streaming AudioTrack
1133 // 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)1134 static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env,  jobject thiz,
1135     jint sampleRateInHertz, jint channelCount, jint audioFormat) {
1136 
1137     size_t frameCount;
1138     const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
1139             sampleRateInHertz);
1140     if (status != NO_ERROR) {
1141         ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
1142                 sampleRateInHertz, status);
1143         return -1;
1144     }
1145     const audio_format_t format = audioFormatToNative(audioFormat);
1146     if (audio_has_proportional_frames(format)) {
1147         const size_t bytesPerSample = audio_bytes_per_sample(format);
1148         return frameCount * channelCount * bytesPerSample;
1149     } else {
1150         return frameCount;
1151     }
1152 }
1153 
1154 // ----------------------------------------------------------------------------
1155 static jint
android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv * env,jobject thiz,jfloat level)1156 android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
1157 {
1158     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1159     if (lpTrack == NULL ) {
1160         jniThrowException(env, "java/lang/IllegalStateException",
1161             "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
1162         return -1;
1163     }
1164 
1165     status_t status = lpTrack->setAuxEffectSendLevel(level);
1166     if (status != NO_ERROR) {
1167         ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
1168                 level, status);
1169     }
1170     return (jint) status;
1171 }
1172 
1173 // ----------------------------------------------------------------------------
android_media_AudioTrack_attachAuxEffect(JNIEnv * env,jobject thiz,jint effectId)1174 static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env,  jobject thiz,
1175         jint effectId) {
1176     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1177     if (lpTrack == NULL) {
1178         jniThrowException(env, "java/lang/IllegalStateException",
1179             "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
1180         return (jint)AUDIO_JAVA_ERROR;
1181     }
1182     return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
1183 }
1184 
android_media_AudioTrack_setOutputDevice(JNIEnv * env,jobject thiz,jint device_id)1185 static jboolean android_media_AudioTrack_setOutputDevice(
1186                 JNIEnv *env,  jobject thiz, jint device_id) {
1187 
1188     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1189     if (lpTrack == 0) {
1190         return false;
1191     }
1192     return lpTrack->setOutputDevice(device_id) == NO_ERROR;
1193 }
android_media_AudioTrack_getRoutedDeviceIds(JNIEnv * env,jobject thiz)1194 static jintArray android_media_AudioTrack_getRoutedDeviceIds(JNIEnv *env, jobject thiz) {
1195     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1196     if (lpTrack == NULL) {
1197         return NULL;
1198     }
1199     DeviceIdVector deviceIds = lpTrack->getRoutedDeviceIds();
1200     jintArray result;
1201     result = env->NewIntArray(deviceIds.size());
1202     if (result == NULL) {
1203         return NULL;
1204     }
1205     jint *values = env->GetIntArrayElements(result, 0);
1206     for (unsigned int i = 0; i < deviceIds.size(); i++) {
1207         values[i] = static_cast<jint>(deviceIds[i]);
1208     }
1209     env->ReleaseIntArrayElements(result, values, 0);
1210     return result;
1211 }
1212 
android_media_AudioTrack_enableDeviceCallback(JNIEnv * env,jobject thiz)1213 static void android_media_AudioTrack_enableDeviceCallback(
1214                 JNIEnv *env,  jobject thiz) {
1215 
1216     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1217     if (lpTrack == nullptr) {
1218         return;
1219     }
1220     const auto pJniStorage =
1221             getFieldSp<AudioTrackJniStorage>(env, thiz, javaAudioTrackFields.jniData);
1222     if (pJniStorage == nullptr || pJniStorage->mDeviceCallback != nullptr) {
1223         return;
1224     }
1225 
1226     pJniStorage->mDeviceCallback =
1227             sp<JNIDeviceCallback>::make(env, thiz, pJniStorage->getAudioTrackWeakRef(),
1228                                         javaAudioTrackFields.postNativeEventInJava);
1229     lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
1230 }
1231 
android_media_AudioTrack_disableDeviceCallback(JNIEnv * env,jobject thiz)1232 static void android_media_AudioTrack_disableDeviceCallback(
1233                 JNIEnv *env,  jobject thiz) {
1234 
1235     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1236     if (lpTrack == nullptr) {
1237         return;
1238     }
1239     const auto pJniStorage =
1240             getFieldSp<AudioTrackJniStorage>(env, thiz, javaAudioTrackFields.jniData);
1241 
1242     if (pJniStorage == nullptr || pJniStorage->mDeviceCallback == nullptr) {
1243         return;
1244     }
1245     lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
1246     pJniStorage->mDeviceCallback.clear();
1247 }
1248 
1249 // Pass through the arguments to the AudioFlinger track implementation.
android_media_AudioTrack_apply_volume_shaper(JNIEnv * env,jobject thiz,jobject jconfig,jobject joperation)1250 static jint android_media_AudioTrack_apply_volume_shaper(JNIEnv *env, jobject thiz,
1251         jobject jconfig, jobject joperation) {
1252     // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
1253     const int VOLUME_SHAPER_INVALID_OPERATION = -38;
1254 
1255     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1256     if (lpTrack == nullptr) {
1257         return (jint)VOLUME_SHAPER_INVALID_OPERATION;
1258     }
1259 
1260     sp<VolumeShaper::Configuration> configuration;
1261     sp<VolumeShaper::Operation> operation;
1262     if (jconfig != nullptr) {
1263         configuration = VolumeShaperHelper::convertJobjectToConfiguration(
1264                 env, gVolumeShaperFields, jconfig);
1265         ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
1266     }
1267     if (joperation != nullptr) {
1268         operation = VolumeShaperHelper::convertJobjectToOperation(
1269                 env, gVolumeShaperFields, joperation);
1270         ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
1271     }
1272     VolumeShaper::Status status = lpTrack->applyVolumeShaper(configuration, operation);
1273     if (status == INVALID_OPERATION) {
1274         status = VOLUME_SHAPER_INVALID_OPERATION;
1275     }
1276     return (jint)status; // if status < 0 an error, else a VolumeShaper id
1277 }
1278 
1279 // Pass through the arguments to the AudioFlinger track implementation.
android_media_AudioTrack_get_volume_shaper_state(JNIEnv * env,jobject thiz,jint id)1280 static jobject android_media_AudioTrack_get_volume_shaper_state(JNIEnv *env, jobject thiz,
1281         jint id) {
1282     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1283     if (lpTrack == nullptr) {
1284         return (jobject)nullptr;
1285     }
1286 
1287     sp<VolumeShaper::State> state = lpTrack->getVolumeShaperState((int)id);
1288     if (state.get() == nullptr) {
1289         return (jobject)nullptr;
1290     }
1291     return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
1292 }
1293 
android_media_AudioTrack_setPresentation(JNIEnv * env,jobject thiz,jint presentationId,jint programId)1294 static int android_media_AudioTrack_setPresentation(
1295                                 JNIEnv *env,  jobject thiz, jint presentationId, jint programId) {
1296     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1297     if (lpTrack == NULL) {
1298         jniThrowException(env, "java/lang/IllegalStateException",
1299             "AudioTrack not initialized");
1300         return (jint)AUDIO_JAVA_ERROR;
1301     }
1302 
1303     return (jint)lpTrack->selectPresentation((int)presentationId, (int)programId);
1304 }
1305 
1306 // ----------------------------------------------------------------------------
android_media_AudioTrack_get_port_id(JNIEnv * env,jobject thiz)1307 static jint android_media_AudioTrack_get_port_id(JNIEnv *env,  jobject thiz) {
1308     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1309     if (lpTrack == NULL) {
1310         jniThrowException(env, "java/lang/IllegalStateException",
1311                           "AudioTrack not initialized");
1312         return (jint)AUDIO_PORT_HANDLE_NONE;
1313     }
1314     return (jint)lpTrack->getPortId();
1315 }
1316 
1317 // ----------------------------------------------------------------------------
android_media_AudioTrack_set_delay_padding(JNIEnv * env,jobject thiz,jint delayInFrames,jint paddingInFrames)1318 static void android_media_AudioTrack_set_delay_padding(JNIEnv *env,  jobject thiz,
1319         jint delayInFrames, jint paddingInFrames) {
1320     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1321     if (lpTrack == NULL) {
1322         jniThrowException(env, "java/lang/IllegalStateException",
1323                 "AudioTrack not initialized");
1324         return;
1325     }
1326     AudioParameter param = AudioParameter();
1327     param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), (int) delayInFrames);
1328     param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), (int) paddingInFrames);
1329     lpTrack->setParameters(param.toString());
1330 }
1331 
android_media_AudioTrack_setAudioDescriptionMixLeveldB(JNIEnv * env,jobject thiz,jfloat level)1332 static jint android_media_AudioTrack_setAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
1333                                                                    jfloat level) {
1334     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1335     if (lpTrack == nullptr) {
1336         jniThrowException(env, "java/lang/IllegalStateException", "AudioTrack not initialized");
1337         return (jint)AUDIO_JAVA_ERROR;
1338     }
1339 
1340     return nativeToJavaStatus(lpTrack->setAudioDescriptionMixLevel(level));
1341 }
1342 
android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv * env,jobject thiz,jfloatArray level)1343 static jint android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
1344                                                                    jfloatArray level) {
1345     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1346     if (lpTrack == nullptr) {
1347         ALOGE("%s: AudioTrack not initialized", __func__);
1348         return (jint)AUDIO_JAVA_ERROR;
1349     }
1350     jfloat *nativeLevel = env->GetFloatArrayElements(level, nullptr /* isCopy */);
1351     if (nativeLevel == nullptr) {
1352         ALOGE("%s: Cannot retrieve level pointer", __func__);
1353         return (jint)AUDIO_JAVA_ERROR;
1354     }
1355 
1356     status_t status = lpTrack->getAudioDescriptionMixLevel(reinterpret_cast<float *>(nativeLevel));
1357     env->ReleaseFloatArrayElements(level, nativeLevel, 0 /* mode */);
1358 
1359     return nativeToJavaStatus(status);
1360 }
1361 
android_media_AudioTrack_setDualMonoMode(JNIEnv * env,jobject thiz,jint dualMonoMode)1362 static jint android_media_AudioTrack_setDualMonoMode(JNIEnv *env, jobject thiz, jint dualMonoMode) {
1363     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1364     if (lpTrack == nullptr) {
1365         jniThrowException(env, "java/lang/IllegalStateException", "AudioTrack not initialized");
1366         return (jint)AUDIO_JAVA_ERROR;
1367     }
1368 
1369     return nativeToJavaStatus(
1370             lpTrack->setDualMonoMode(static_cast<audio_dual_mono_mode_t>(dualMonoMode)));
1371 }
1372 
android_media_AudioTrack_getDualMonoMode(JNIEnv * env,jobject thiz,jintArray dualMonoMode)1373 static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
1374                                                      jintArray dualMonoMode) {
1375     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1376     if (lpTrack == nullptr) {
1377         ALOGE("%s: AudioTrack not initialized", __func__);
1378         return (jint)AUDIO_JAVA_ERROR;
1379     }
1380     jint *nativeDualMonoMode = env->GetIntArrayElements(dualMonoMode, nullptr /* isCopy */);
1381     if (nativeDualMonoMode == nullptr) {
1382         ALOGE("%s: Cannot retrieve dualMonoMode pointer", __func__);
1383         return (jint)AUDIO_JAVA_ERROR;
1384     }
1385 
1386     status_t status = lpTrack->getDualMonoMode(
1387             reinterpret_cast<audio_dual_mono_mode_t *>(nativeDualMonoMode));
1388     env->ReleaseIntArrayElements(dualMonoMode, nativeDualMonoMode, 0 /* mode */);
1389 
1390     return nativeToJavaStatus(status);
1391 }
1392 
android_media_AudioTrack_setLogSessionId(JNIEnv * env,jobject thiz,jstring jlogSessionId)1393 static void android_media_AudioTrack_setLogSessionId(JNIEnv *env, jobject thiz,
1394                                                      jstring jlogSessionId) {
1395     sp<AudioTrack> track = getAudioTrack(env, thiz);
1396     if (track == nullptr) {
1397         jniThrowException(env, "java/lang/IllegalStateException",
1398                           "Unable to retrieve AudioTrack pointer for setLogSessionId()");
1399     }
1400     if (jlogSessionId == nullptr) {
1401         ALOGV("%s: logSessionId nullptr", __func__);
1402         track->setLogSessionId(nullptr);
1403         return;
1404     }
1405     ScopedUtfChars logSessionId(env, jlogSessionId);
1406     ALOGV("%s: logSessionId '%s'", __func__, logSessionId.c_str());
1407     track->setLogSessionId(logSessionId.c_str());
1408 }
1409 
android_media_AudioTrack_setPlayerIId(JNIEnv * env,jobject thiz,jint playerIId)1410 static void android_media_AudioTrack_setPlayerIId(JNIEnv *env, jobject thiz, jint playerIId) {
1411     sp<AudioTrack> track = getAudioTrack(env, thiz);
1412     if (track == nullptr) {
1413         jniThrowException(env, "java/lang/IllegalStateException",
1414                           "Unable to retrieve AudioTrack pointer for setPlayerIId()");
1415     }
1416     ALOGV("%s: playerIId %d", __func__, playerIId);
1417     track->setPlayerIId(playerIId);
1418 }
1419 
android_media_AudioTrack_getStartThresholdInFrames(JNIEnv * env,jobject thiz)1420 static jint android_media_AudioTrack_getStartThresholdInFrames(JNIEnv *env, jobject thiz) {
1421     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1422     if (lpTrack == nullptr) {
1423         jniThrowException(env, "java/lang/IllegalStateException",
1424                           "Unable to retrieve AudioTrack pointer for getStartThresholdInFrames()");
1425         return (jint)AUDIO_JAVA_ERROR;
1426     }
1427     const ssize_t result = lpTrack->getStartThresholdInFrames();
1428     if (result <= 0) {
1429         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
1430                              "Internal error detected in getStartThresholdInFrames() = %zd",
1431                              result);
1432         return (jint)AUDIO_JAVA_ERROR;
1433     }
1434     return (jint)result; // this should be a positive value.
1435 }
1436 
android_media_AudioTrack_setStartThresholdInFrames(JNIEnv * env,jobject thiz,jint startThresholdInFrames)1437 static jint android_media_AudioTrack_setStartThresholdInFrames(JNIEnv *env, jobject thiz,
1438                                                                jint startThresholdInFrames) {
1439     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1440     if (lpTrack == nullptr) {
1441         jniThrowException(env, "java/lang/IllegalStateException",
1442                           "Unable to retrieve AudioTrack pointer for setStartThresholdInFrames()");
1443         return (jint)AUDIO_JAVA_ERROR;
1444     }
1445     // non-positive values of startThresholdInFrames are not allowed by the Java layer.
1446     const ssize_t result = lpTrack->setStartThresholdInFrames(startThresholdInFrames);
1447     if (result <= 0) {
1448         jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
1449                              "Internal error detected in setStartThresholdInFrames() = %zd",
1450                              result);
1451         return (jint)AUDIO_JAVA_ERROR;
1452     }
1453     return (jint)result; // this should be a positive value.
1454 }
1455 
1456 // ----------------------------------------------------------------------------
1457 // ----------------------------------------------------------------------------
1458 static const JNINativeMethod gMethods[] = {
1459         // name,              signature,     funcPtr
native_is_direct_output_supported(IIIIIII)1460         {"native_is_direct_output_supported", "(IIIIIII)Z",
1461          (void *)android_media_AudioTrack_is_direct_output_supported},
native_start()1462         {"native_start", "()V", (void *)android_media_AudioTrack_start},
native_stop()1463         {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
native_pause()1464         {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
native_flush()1465         {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
native_setup(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[ILandroid/os/Parcel;JZILjava/lang/Object;Ljava/lang/String;)1466         {"native_setup",
1467          "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[ILandroid/os/Parcel;"
1468          "JZILjava/lang/Object;Ljava/lang/String;)I",
1469          (void *)android_media_AudioTrack_setup},
native_finalize()1470         {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
native_release()1471         {"native_release", "()V", (void *)android_media_AudioTrack_release},
native_write_byte([BIIIZ)1472         {"native_write_byte", "([BIIIZ)I", (void *)android_media_AudioTrack_writeArray<jbyteArray>},
native_write_native_bytes(Ljava/nio/ByteBuffer;IIIZ)1473         {"native_write_native_bytes", "(Ljava/nio/ByteBuffer;IIIZ)I",
1474          (void *)android_media_AudioTrack_write_native_bytes},
native_write_short([SIIIZ)1475         {"native_write_short", "([SIIIZ)I",
1476          (void *)android_media_AudioTrack_writeArray<jshortArray>},
native_write_float([FIIIZ)1477         {"native_write_float", "([FIIIZ)I",
1478          (void *)android_media_AudioTrack_writeArray<jfloatArray>},
native_setVolume(FF)1479         {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
native_get_buffer_size_frames()1480         {"native_get_buffer_size_frames", "()I",
1481          (void *)android_media_AudioTrack_get_buffer_size_frames},
native_set_buffer_size_frames(I)1482         {"native_set_buffer_size_frames", "(I)I",
1483          (void *)android_media_AudioTrack_set_buffer_size_frames},
native_get_buffer_capacity_frames()1484         {"native_get_buffer_capacity_frames", "()I",
1485          (void *)android_media_AudioTrack_get_buffer_capacity_frames},
native_set_playback_rate(I)1486         {"native_set_playback_rate", "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
native_get_playback_rate()1487         {"native_get_playback_rate", "()I", (void *)android_media_AudioTrack_get_playback_rate},
native_set_playback_params(Landroid/media/PlaybackParams;)1488         {"native_set_playback_params", "(Landroid/media/PlaybackParams;)V",
1489          (void *)android_media_AudioTrack_set_playback_params},
native_get_playback_params()1490         {"native_get_playback_params", "()Landroid/media/PlaybackParams;",
1491          (void *)android_media_AudioTrack_get_playback_params},
native_set_marker_pos(I)1492         {"native_set_marker_pos", "(I)I", (void *)android_media_AudioTrack_set_marker_pos},
native_get_marker_pos()1493         {"native_get_marker_pos", "()I", (void *)android_media_AudioTrack_get_marker_pos},
native_set_pos_update_period(I)1494         {"native_set_pos_update_period", "(I)I",
1495          (void *)android_media_AudioTrack_set_pos_update_period},
native_get_pos_update_period()1496         {"native_get_pos_update_period", "()I",
1497          (void *)android_media_AudioTrack_get_pos_update_period},
native_set_position(I)1498         {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
native_get_position()1499         {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
native_get_latency()1500         {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
native_get_underrun_count()1501         {"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
native_get_flags()1502         {"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
native_get_timestamp([J)1503         {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
native_getMetrics()1504         {"native_getMetrics", "()Landroid/os/PersistableBundle;",
1505          (void *)android_media_AudioTrack_native_getMetrics},
native_set_loop(III)1506         {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
native_reload_static()1507         {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
native_get_output_sample_rate(I)1508         {"native_get_output_sample_rate", "(I)I",
1509          (void *)android_media_AudioTrack_get_output_sample_rate},
native_get_min_buff_size(III)1510         {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
native_setAuxEffectSendLevel(F)1511         {"native_setAuxEffectSendLevel", "(F)I",
1512          (void *)android_media_AudioTrack_setAuxEffectSendLevel},
native_attachAuxEffect(I)1513         {"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
native_setOutputDevice(I)1514         {"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
native_getRoutedDeviceIds()1515         {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioTrack_getRoutedDeviceIds},
native_enableDeviceCallback()1516         {"native_enableDeviceCallback", "()V",
1517          (void *)android_media_AudioTrack_enableDeviceCallback},
native_disableDeviceCallback()1518         {"native_disableDeviceCallback", "()V",
1519          (void *)android_media_AudioTrack_disableDeviceCallback},
native_applyVolumeShaper(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)1520         {"native_applyVolumeShaper",
1521          "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
1522          (void *)android_media_AudioTrack_apply_volume_shaper},
native_getVolumeShaperState(I)1523         {"native_getVolumeShaperState", "(I)Landroid/media/VolumeShaper$State;",
1524          (void *)android_media_AudioTrack_get_volume_shaper_state},
native_setPresentation(II)1525         {"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
native_getPortId()1526         {"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
native_set_delay_padding(II)1527         {"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
native_set_audio_description_mix_level_db(F)1528         {"native_set_audio_description_mix_level_db", "(F)I",
1529          (void *)android_media_AudioTrack_setAudioDescriptionMixLeveldB},
native_get_audio_description_mix_level_db([F)1530         {"native_get_audio_description_mix_level_db", "([F)I",
1531          (void *)android_media_AudioTrack_getAudioDescriptionMixLeveldB},
native_set_dual_mono_mode(I)1532         {"native_set_dual_mono_mode", "(I)I", (void *)android_media_AudioTrack_setDualMonoMode},
native_get_dual_mono_mode([I)1533         {"native_get_dual_mono_mode", "([I)I", (void *)android_media_AudioTrack_getDualMonoMode},
native_setLogSessionId(Ljava/lang/String;)1534         {"native_setLogSessionId", "(Ljava/lang/String;)V",
1535          (void *)android_media_AudioTrack_setLogSessionId},
native_setPlayerIId(I)1536         {"native_setPlayerIId", "(I)V", (void *)android_media_AudioTrack_setPlayerIId},
native_setStartThresholdInFrames(I)1537         {"native_setStartThresholdInFrames", "(I)I",
1538          (void *)android_media_AudioTrack_setStartThresholdInFrames},
native_getStartThresholdInFrames()1539         {"native_getStartThresholdInFrames", "()I",
1540          (void *)android_media_AudioTrack_getStartThresholdInFrames},
1541 };
1542 
1543 // field names found in android/media/AudioTrack.java
1544 #define JAVA_POSTEVENT_CALLBACK_NAME                    "postEventFromNative"
1545 #define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME            "mNativeTrackInJavaObj"
1546 #define JAVA_JNIDATA_FIELD_NAME                         "mJniData"
1547 #define JAVA_STREAMTYPE_FIELD_NAME                      "mStreamType"
1548 
1549 // ----------------------------------------------------------------------------
1550 // preconditions:
1551 //    theClass is valid
android_media_getIntConstantFromClass(JNIEnv * pEnv,jclass theClass,const char * className,const char * constName,int * constVal)1552 bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1553                              const char* constName, int* constVal) {
1554     jfieldID javaConst = NULL;
1555     javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1556     if (javaConst != NULL) {
1557         *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1558         return true;
1559     } else {
1560         ALOGE("Can't find %s.%s", className, constName);
1561         return false;
1562     }
1563 }
1564 
1565 // ----------------------------------------------------------------------------
register_android_media_AudioTrack(JNIEnv * env)1566 int register_android_media_AudioTrack(JNIEnv *env)
1567 {
1568     // must be first
1569     int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1570 
1571     javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1572     javaAudioTrackFields.postNativeEventInJava = NULL;
1573 
1574     // Get the AudioTrack class
1575     jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
1576 
1577     // Get the postEvent method
1578     javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1579             audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1580             "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1581 
1582     // Get the variables fields
1583     //      nativeTrackInJavaObj
1584     javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1585             audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
1586     //      jniData
1587     javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1588             audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
1589     //      fieldStreamType
1590     javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1591             audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
1592 
1593     env->DeleteLocalRef(audioTrackClass);
1594 
1595     // initialize PlaybackParams field info
1596     gPlaybackParamsFields.init(env);
1597 
1598     gVolumeShaperFields.init(env);
1599 
1600     // optional check that the TunerConfiguration class and fields exist.
1601     TunerConfigurationHelper::initCheckOrDie(env);
1602 
1603     return res;
1604 }
1605 
1606 
1607 // ----------------------------------------------------------------------------
1608