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