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