blob: 7a5c38385f323f5faef615e7f236fbabd495fb88 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Wei Jia071a8b72015-03-09 16:38:25 -070020#include "android_media_AudioTrack.h"
21
Steven Moreland2279b252017-07-19 09:50:45 -070022#include <nativehelper/JNIHelp.h>
jiabinfcd4cbf2020-08-21 18:07:27 -070023#include <nativehelper/ScopedUtfChars.h>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080024#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
Glenn Kastenc81d31c2012-03-13 14:46:23 -070026#include <utils/Log.h>
Jean-Michel Trivi157cba42019-01-25 18:40:03 -080027#include <media/AudioParameter.h>
Glenn Kastenc81d31c2012-03-13 14:46:23 -070028#include <media/AudioSystem.h>
29#include <media/AudioTrack.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
Jean-Michel Trivi03f51392018-08-31 15:47:13 -070031#include <android-base/macros.h>
Mathias Agopian07952722009-05-19 19:08:10 -070032#include <binder/MemoryHeapBase.h>
33#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
jiabina02129b2020-02-25 14:04:36 -080035#include "android_media_AudioAttributes.h"
Eric Laurentbc11a692014-05-16 12:19:25 -070036#include "android_media_AudioErrors.h"
jiabina02129b2020-02-25 14:04:36 -080037#include "android_media_AudioFormat.h"
38#include "android_media_AudioTrackCallback.h"
39#include "android_media_DeviceCallback.h"
Ray Essick510225b2018-01-24 14:27:16 -080040#include "android_media_MediaMetricsJNI.h"
Wei Jia2d61e2b2015-05-08 15:23:28 -070041#include "android_media_PlaybackParams.h"
Andy Hung035d4ec2017-01-24 13:45:02 -080042#include "android_media_VolumeShaper.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
Ben Wagner85ea32b2016-03-16 17:10:42 -040044#include <cinttypes>
45
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046// ----------------------------------------------------------------------------
47
48using namespace android;
49
Ivan Lozano330d8762017-08-08 12:51:06 -070050using ::android::media::VolumeShaper;
51
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052// ----------------------------------------------------------------------------
53static const char* const kClassPathName = "android/media/AudioTrack";
54
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070055struct audio_track_fields_t {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 // these fields provide access from C++ to the...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 jmethodID postNativeEventInJava; //... event post callback method
Eric Laurent83b36852009-07-28 07:49:22 -070058 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070060 jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061};
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070062static audio_track_fields_t javaAudioTrackFields;
Wei Jia2d61e2b2015-05-08 15:23:28 -070063static PlaybackParams::fields_t gPlaybackParamsFields;
Andy Hung035d4ec2017-01-24 13:45:02 -080064static VolumeShaperHelper::fields_t gVolumeShaperFields;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
66struct audiotrack_callback_cookie {
67 jclass audioTrack_class;
68 jobject audioTrack_ref;
Eric Laurent532bc1c2012-04-20 12:45:03 -070069 bool busy;
70 Condition cond;
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -080071 bool isOffload;
Eric Laurent532bc1c2012-04-20 12:45:03 -070072};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073
Glenn Kasten3d301cb2012-01-16 14:46:54 -080074// keep these values in sync with AudioTrack.java
75#define MODE_STATIC 0
76#define MODE_STREAM 1
77
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078// ----------------------------------------------------------------------------
79class AudioTrackJniStorage {
jiabina02129b2020-02-25 14:04:36 -080080public:
81 sp<MemoryHeapBase> mMemHeap;
82 sp<MemoryBase> mMemBase;
83 audiotrack_callback_cookie mCallbackData{};
84 sp<JNIDeviceCallback> mDeviceCallback;
85 sp<JNIAudioTrackCallback> mAudioTrackCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
87 bool allocSharedMem(int sizeInBytes) {
88 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
89 if (mMemHeap->getHeapID() < 0) {
90 return false;
91 }
92 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
93 return true;
94 }
95};
96
Andy Hung59dffec2020-01-14 17:29:03 -080097class TunerConfigurationHelper {
98 JNIEnv *const mEnv;
99 jobject const mTunerConfiguration;
100
101 struct Ids {
102 Ids(JNIEnv *env)
103 : mClass(FindClassOrDie(env, "android/media/AudioTrack$TunerConfiguration")),
104 mContentId(GetFieldIDOrDie(env, mClass, "mContentId", "I")),
105 mSyncId(GetFieldIDOrDie(env, mClass, "mSyncId", "I")) {}
106 const jclass mClass;
107 const jfieldID mContentId;
108 const jfieldID mSyncId;
109 };
110
111 static const Ids &getIds(JNIEnv *env) {
112 // Meyer's singleton, initializes first time control passes through
113 // declaration in a block and is thread-safe per ISO/IEC 14882:2011 6.7.4.
114 static Ids ids(env);
115 return ids;
116 }
117
118public:
119 TunerConfigurationHelper(JNIEnv *env, jobject tunerConfiguration)
120 : mEnv(env), mTunerConfiguration(tunerConfiguration) {}
121
122 int32_t getContentId() const {
123 if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
124 const Ids &ids = getIds(mEnv);
125 return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mContentId);
126 }
127
128 int32_t getSyncId() const {
129 if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
130 const Ids &ids = getIds(mEnv);
131 return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mSyncId);
132 }
133
134 // optional check to confirm class and field ids can be found.
135 static void initCheckOrDie(JNIEnv *env) { (void)getIds(env); }
136};
137
Eric Laurent532bc1c2012-04-20 12:45:03 -0700138static Mutex sLock;
139static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141// ----------------------------------------------------------------------------
142#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
143
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -0700144#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM (-16)
145#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK (-17)
146#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT (-18)
147#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE (-19)
148#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED (-20)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150// ----------------------------------------------------------------------------
Glenn Kastene46a86f2011-06-01 15:20:35 -0700151static void audioCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700152
153 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
154 {
155 Mutex::Autolock l(sLock);
156 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
157 return;
158 }
159 callbackInfo->busy = true;
160 }
161
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700162 // used as default argument when event callback doesn't have any, or number of
163 // frames for EVENT_CAN_WRITE_MORE_DATA
164 int arg = 0;
165 bool postEvent = false;
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700166 switch (event) {
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800167 // Offload only events
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700168 case AudioTrack::EVENT_CAN_WRITE_MORE_DATA:
169 // this event will read the info return parameter of the callback:
170 // for JNI offload, use the returned size to indicate:
171 // 1/ no data is returned through callback, as it's all done through write()
172 // 2/ do not wait as AudioTrack does when it receives 0 bytes
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800173 if (callbackInfo->isOffload) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700174 AudioTrack::Buffer* pBuffer = (AudioTrack::Buffer*) info;
175 const size_t availableForWrite = pBuffer->size;
176 arg = availableForWrite > INT32_MAX ? INT32_MAX : (int) availableForWrite;
177 pBuffer->size = 0;
178 }
179 FALLTHROUGH_INTENDED;
180 case AudioTrack::EVENT_STREAM_END:
181 case AudioTrack::EVENT_NEW_IAUDIOTRACK: // a.k.a. tear down
182 if (callbackInfo->isOffload) {
183 postEvent = true;
184 }
185 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800187 // PCM and offload events
188 case AudioTrack::EVENT_MARKER:
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700189 case AudioTrack::EVENT_NEW_POS:
190 postEvent = true;
191 break;
192 default:
193 // event will not be posted
194 break;
195 }
196
197 if (postEvent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 JNIEnv *env = AndroidRuntime::getJNIEnv();
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700199 if (env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 env->CallStaticVoidMethod(
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800201 callbackInfo->audioTrack_class,
202 javaAudioTrackFields.postNativeEventInJava,
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700203 callbackInfo->audioTrack_ref, event, arg, 0, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 if (env->ExceptionCheck()) {
205 env->ExceptionDescribe();
206 env->ExceptionClear();
207 }
208 }
209 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700210
Eric Laurent532bc1c2012-04-20 12:45:03 -0700211 {
212 Mutex::Autolock l(sLock);
213 callbackInfo->busy = false;
214 callbackInfo->cond.broadcast();
215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216}
217
218
219// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700220static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
221{
222 Mutex::Autolock l(sLock);
223 AudioTrack* const at =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000224 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700225 return sp<AudioTrack>(at);
226}
227
228static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
229{
230 Mutex::Autolock l(sLock);
231 sp<AudioTrack> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000232 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700233 if (at.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800234 at->incStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700235 }
236 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800237 old->decStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700238 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000239 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700240 return old;
241}
Wei Jia071a8b72015-03-09 16:38:25 -0700242
243// ----------------------------------------------------------------------------
244sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
245 return getAudioTrack(env, audioTrackObj);
246}
247
Eric Laurent532bc1c2012-04-20 12:45:03 -0700248// ----------------------------------------------------------------------------
Andy Hung59dffec2020-01-14 17:29:03 -0800249static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
250 jobject jaa, jintArray jSampleRate,
251 jint channelPositionMask, jint channelIndexMask,
252 jint audioFormat, jint buffSizeInBytes, jint memoryMode,
253 jintArray jSession, jlong nativeAudioTrack,
254 jboolean offload, jint encapsulationMode,
jiabinfcd4cbf2020-08-21 18:07:27 -0700255 jobject tunerConfiguration, jstring opPackageName) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700256 ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
Andy Hung59dffec2020-01-14 17:29:03 -0800257 " nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p",
258 jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
259 nativeAudioTrack, offload, encapsulationMode, tunerConfiguration);
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700260
261 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000262 ALOGE("Error creating AudioTrack: invalid session ID pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700263 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent619346f2010-06-21 09:27:30 -0700264 }
265
Andy Hung59dffec2020-01-14 17:29:03 -0800266 // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
267 if (tunerConfiguration != nullptr) {
268 const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
269 ALOGE("Error creating AudioTrack: unsupported tuner contentId:%d syncId:%d",
270 tunerHelper.getContentId(), tunerHelper.getSyncId());
271 return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
272 }
273 // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
274 if (encapsulationMode != 0 /* ENCAPSULATION_MODE_NONE */) {
275 ALOGE("Error creating AudioTrack: unsupported encapsulationMode %d", encapsulationMode);
276 return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
277 }
278
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700279 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
280 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000281 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700282 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700283 }
Glenn Kasten33b84042016-03-08 12:02:55 -0800284 audio_session_t sessionId = (audio_session_t) nSession[0];
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700285 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
286 nSession = NULL;
287
Paul McLean9b09e532016-01-26 14:43:35 -0700288 AudioTrackJniStorage* lpJniStorage = NULL;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700289
Paul McLean9b09e532016-01-26 14:43:35 -0700290 jclass clazz = env->GetObjectClass(thiz);
291 if (clazz == NULL) {
292 ALOGE("Can't find %s when setting up callback.", kClassPathName);
293 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
294 }
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700295
Paul McLean9b09e532016-01-26 14:43:35 -0700296 // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
Andy Hung59dffec2020-01-14 17:29:03 -0800297 sp<AudioTrack> lpTrack;
Paul McLean9b09e532016-01-26 14:43:35 -0700298 if (nativeAudioTrack == 0) {
299 if (jaa == 0) {
300 ALOGE("Error creating AudioTrack: invalid audio attributes");
301 return (jint) AUDIO_JAVA_ERROR;
302 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700303
Paul McLean9b09e532016-01-26 14:43:35 -0700304 if (jSampleRate == 0) {
305 ALOGE("Error creating AudioTrack: invalid sample rates");
306 return (jint) AUDIO_JAVA_ERROR;
307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308
Paul McLean9b09e532016-01-26 14:43:35 -0700309 int* sampleRates = env->GetIntArrayElements(jSampleRate, NULL);
310 int sampleRateInHertz = sampleRates[0];
311 env->ReleaseIntArrayElements(jSampleRate, sampleRates, JNI_ABORT);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700312
Paul McLean9b09e532016-01-26 14:43:35 -0700313 // Invalid channel representations are caught by !audio_is_output_channel() below.
314 audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
315 channelPositionMask, channelIndexMask);
316 if (!audio_is_output_channel(nativeChannelMask)) {
317 ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
318 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
319 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700320
Paul McLean9b09e532016-01-26 14:43:35 -0700321 uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
322
323 // check the format.
324 // This function was called from Java, so we compare the format against the Java constants
325 audio_format_t format = audioFormatToNative(audioFormat);
326 if (format == AUDIO_FORMAT_INVALID) {
327 ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
328 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
329 }
330
331 // compute the frame count
332 size_t frameCount;
jiabinf2d8e9c2018-02-23 17:44:56 -0800333 if (audio_has_proportional_frames(format)) {
Paul McLean9b09e532016-01-26 14:43:35 -0700334 const size_t bytesPerSample = audio_bytes_per_sample(format);
335 frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
336 } else {
337 frameCount = buffSizeInBytes;
338 }
339
340 // create the native AudioTrack object
jiabinfcd4cbf2020-08-21 18:07:27 -0700341 ScopedUtfChars opPackageNameStr(env, opPackageName);
342 lpTrack = new AudioTrack(opPackageNameStr.c_str());
Paul McLean9b09e532016-01-26 14:43:35 -0700343
344 // read the AudioAttributes values
François Gaffieb4691282018-07-09 13:07:32 +0200345 auto paa = JNIAudioAttributeHelper::makeUnique();
346 jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
347 if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
348 return jStatus;
349 }
Paul McLean9b09e532016-01-26 14:43:35 -0700350 ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
351 paa->usage, paa->content_type, paa->flags, paa->tags);
352
353 // initialize the callback information:
354 // this data will be passed with every AudioTrack callback
355 lpJniStorage = new AudioTrackJniStorage();
356 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
357 // we use a weak reference so the AudioTrack object can be garbage collected.
358 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800359 lpJniStorage->mCallbackData.isOffload = offload;
Paul McLean9b09e532016-01-26 14:43:35 -0700360 lpJniStorage->mCallbackData.busy = false;
361
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800362 audio_offload_info_t offloadInfo;
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700363 if (offload == JNI_TRUE) {
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800364 offloadInfo = AUDIO_INFO_INITIALIZER;
365 offloadInfo.format = format;
366 offloadInfo.sample_rate = sampleRateInHertz;
367 offloadInfo.channel_mask = nativeChannelMask;
368 offloadInfo.has_video = false;
369 offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
370 }
371
Paul McLean9b09e532016-01-26 14:43:35 -0700372 // initialize the native AudioTrack object
373 status_t status = NO_ERROR;
374 switch (memoryMode) {
375 case MODE_STREAM:
jiabinfcd4cbf2020-08-21 18:07:27 -0700376 status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed
377 // in paa (last argument)
378 sampleRateInHertz,
379 format, // word length, PCM
380 nativeChannelMask, offload ? 0 : frameCount,
381 offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
382 : AUDIO_OUTPUT_FLAG_NONE,
383 audioCallback,
384 &(lpJniStorage->mCallbackData), // callback, callback data (user)
385 0, // notificationFrames == 0 since not using EVENT_MORE_DATA
386 // to feed the AudioTrack
387 0, // shared mem
388 true, // thread can call Java
389 sessionId, // audio session ID
390 offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK
391 : AudioTrack::TRANSFER_SYNC,
392 offload ? &offloadInfo : NULL, -1, -1, // default uid, pid values
393 paa.get());
Paul McLean9b09e532016-01-26 14:43:35 -0700394 break;
395
396 case MODE_STATIC:
397 // AudioTrack is using shared memory
398
399 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
400 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
401 goto native_init_failure;
402 }
403
jiabinfcd4cbf2020-08-21 18:07:27 -0700404 status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed
405 // in paa (last argument)
406 sampleRateInHertz,
407 format, // word length, PCM
408 nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE,
409 audioCallback,
410 &(lpJniStorage->mCallbackData), // callback, callback data (user)
411 0, // notificationFrames == 0 since not using EVENT_MORE_DATA
412 // to feed the AudioTrack
413 lpJniStorage->mMemBase, // shared mem
414 true, // thread can call Java
415 sessionId, // audio session ID
416 AudioTrack::TRANSFER_SHARED,
417 NULL, // default offloadInfo
418 -1, -1, // default uid, pid values
419 paa.get());
Paul McLean9b09e532016-01-26 14:43:35 -0700420 break;
421
422 default:
423 ALOGE("Unknown mode %d", memoryMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 goto native_init_failure;
425 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700426
Paul McLean9b09e532016-01-26 14:43:35 -0700427 if (status != NO_ERROR) {
428 ALOGE("Error %d initializing AudioTrack", status);
429 goto native_init_failure;
430 }
Andy Hungac5c3e62020-04-27 09:22:37 -0700431 // Set caller name so it can be logged in destructor.
432 // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA
433 lpTrack->setCallerName("java");
Paul McLean9b09e532016-01-26 14:43:35 -0700434 } else { // end if (nativeAudioTrack == 0)
435 lpTrack = (AudioTrack*)nativeAudioTrack;
436 // TODO: We need to find out which members of the Java AudioTrack might
437 // need to be initialized from the Native AudioTrack
438 // these are directly returned from getters:
439 // mSampleRate
440 // mAudioFormat
441 // mStreamType
442 // mChannelConfiguration
443 // mChannelCount
444 // mState (?)
445 // mPlayState (?)
446 // these may be used internally (Java AudioTrack.audioParamCheck():
447 // mChannelMask
448 // mChannelIndexMask
449 // mDataLoadMode
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800450
Paul McLean9b09e532016-01-26 14:43:35 -0700451 // initialize the callback information:
452 // this data will be passed with every AudioTrack callback
453 lpJniStorage = new AudioTrackJniStorage();
454 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
455 // we use a weak reference so the AudioTrack object can be garbage collected.
456 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
457 lpJniStorage->mCallbackData.busy = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 }
jiabina02129b2020-02-25 14:04:36 -0800459 lpJniStorage->mAudioTrackCallback =
460 new JNIAudioTrackCallback(env, thiz, lpJniStorage->mCallbackData.audioTrack_ref,
461 javaAudioTrackFields.postNativeEventInJava);
462 lpTrack->setAudioTrackCallback(lpJniStorage->mAudioTrackCallback);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700464 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
465 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000466 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700467 goto native_init_failure;
468 }
Eric Laurent619346f2010-06-21 09:27:30 -0700469 // read the audio session ID back from AudioTrack in case we create a new session
470 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700471 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
472 nSession = NULL;
473
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800474 {
475 const jint elements[1] = { (jint) lpTrack->getSampleRate() };
476 env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
477 }
478
Eric Laurent532bc1c2012-04-20 12:45:03 -0700479 { // scope for the lock
480 Mutex::Autolock l(sLock);
481 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
482 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700483 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 // of the Java object (in mNativeTrackInJavaObj)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700485 setAudioTrack(env, thiz, lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 // save the JNI resources so we can free them later
Ashok Bhat075e9a12014-01-06 13:45:09 +0000488 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
489 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700491 // since we had audio attributes, the stream type was derived from them during the
492 // creation of the native AudioTrack: push the same value to the Java object
493 env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700494
Eric Laurentbc11a692014-05-16 12:19:25 -0700495 return (jint) AUDIO_JAVA_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 // failures:
498native_init_failure:
Eric Laurent619346f2010-06-21 09:27:30 -0700499 if (nSession != NULL) {
500 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
501 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700502 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
503 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 delete lpJniStorage;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000505 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700506
Glenn Kasten14d226a2015-05-18 13:53:39 -0700507 // lpTrack goes out of scope, so reference count drops to zero
Ashok Bhat075e9a12014-01-06 13:45:09 +0000508 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509}
510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511// ----------------------------------------------------------------------------
Michael Chan2de156d2018-04-24 14:33:57 +1000512static jboolean
513android_media_AudioTrack_is_direct_output_supported(JNIEnv *env, jobject thiz,
514 jint encoding, jint sampleRate,
515 jint channelMask, jint channelIndexMask,
516 jint contentType, jint usage, jint flags) {
517 audio_config_base_t config = {};
518 audio_attributes_t attributes = {};
519 config.format = static_cast<audio_format_t>(audioFormatToNative(encoding));
520 config.sample_rate = static_cast<uint32_t>(sampleRate);
521 config.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
522 attributes.content_type = static_cast<audio_content_type_t>(contentType);
523 attributes.usage = static_cast<audio_usage_t>(usage);
524 attributes.flags = static_cast<audio_flags_mask_t>(flags);
525 // ignore source and tags attributes as they don't affect querying whether output is supported
526 return AudioTrack::isDirectOutputSupported(config, attributes);
527}
528
529// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530static void
531android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
532{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700533 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
534 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 jniThrowException(env, "java/lang/IllegalStateException",
536 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700537 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 lpTrack->start();
541}
542
543
544// ----------------------------------------------------------------------------
545static void
546android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
547{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700548 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
549 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 jniThrowException(env, "java/lang/IllegalStateException",
551 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700552 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
554
555 lpTrack->stop();
556}
557
558
559// ----------------------------------------------------------------------------
560static void
561android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
562{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700563 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
564 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 jniThrowException(env, "java/lang/IllegalStateException",
566 "Unable to retrieve AudioTrack pointer for pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700567 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 }
569
570 lpTrack->pause();
571}
572
573
574// ----------------------------------------------------------------------------
575static void
576android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
577{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700578 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
579 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 jniThrowException(env, "java/lang/IllegalStateException",
581 "Unable to retrieve AudioTrack pointer for flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700582 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 }
584
585 lpTrack->flush();
586}
587
588// ----------------------------------------------------------------------------
589static void
590android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
591{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700592 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
593 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 jniThrowException(env, "java/lang/IllegalStateException",
595 "Unable to retrieve AudioTrack pointer for setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700596 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 }
598
599 lpTrack->setVolume(leftVol, rightVol);
600}
601
602// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700603
Eric Laurent532bc1c2012-04-20 12:45:03 -0700604#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800605static void android_media_AudioTrack_release(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700606 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
607 if (lpTrack == NULL) {
608 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700610 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 // delete the JNI data
Ashok Bhat075e9a12014-01-06 13:45:09 +0000613 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 thiz, javaAudioTrackFields.jniData);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700615 // reset the native resources in the Java object so any attempt to access
616 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000617 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 if (pJniStorage) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700620 Mutex::Autolock l(sLock);
621 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
Steve Block71f2cf12011-10-20 11:56:00 +0100622 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700623 while (lpCookie->busy) {
624 if (lpCookie->cond.waitRelative(sLock,
625 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
626 NO_ERROR) {
627 break;
628 }
629 }
630 sAudioTrackCallBackCookies.remove(lpCookie);
631 // delete global refs created in native_setup
632 env->DeleteGlobalRef(lpCookie->audioTrack_class);
633 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 delete pJniStorage;
635 }
636}
637
Glenn Kasten18db49a2012-03-12 16:29:55 -0700638
Eric Laurent532bc1c2012-04-20 12:45:03 -0700639// ----------------------------------------------------------------------------
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800640static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
641 //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
642 android_media_AudioTrack_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643}
644
Andy Hung4aacc902015-04-14 15:01:29 -0700645// overloaded JNI array helper functions (same as in android_media_AudioRecord)
646static inline
647jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
648 return env->GetByteArrayElements(array, isCopy);
649}
650
651static inline
652void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
653 env->ReleaseByteArrayElements(array, elems, mode);
654}
655
656static inline
657jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
658 return env->GetShortArrayElements(array, isCopy);
659}
660
661static inline
662void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
663 env->ReleaseShortArrayElements(array, elems, mode);
664}
665
666static inline
667jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
668 return env->GetFloatArrayElements(array, isCopy);
669}
670
671static inline
672void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
673 env->ReleaseFloatArrayElements(array, elems, mode);
674}
675
Eric Laurent219de732016-05-23 12:41:50 -0700676static inline
677jint interpretWriteSizeError(ssize_t writeSize) {
678 if (writeSize == WOULD_BLOCK) {
679 return (jint)0;
680 } else if (writeSize == NO_INIT) {
681 return AUDIO_JAVA_DEAD_OBJECT;
682 } else {
683 ALOGE("Error %zd during AudioTrack native read", writeSize);
684 return nativeToJavaStatus(writeSize);
685 }
686}
687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700689template <typename T>
690static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
691 jint offsetInSamples, jint sizeInSamples, bool blocking) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700692 // give the data to the native AudioTrack object (the data starts at the offset)
693 ssize_t written = 0;
694 // regular write() or copy the data to the AudioTrack's shared memory?
Andy Hung4aacc902015-04-14 15:01:29 -0700695 size_t sizeInBytes = sizeInSamples * sizeof(T);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700696 if (track->sharedBuffer() == 0) {
Andy Hung4aacc902015-04-14 15:01:29 -0700697 written = track->write(data + offsetInSamples, sizeInBytes, blocking);
Glenn Kasten9b53db32013-07-10 14:13:39 -0700698 // for compatibility with earlier behavior of write(), return 0 in this case
699 if (written == (ssize_t) WOULD_BLOCK) {
700 written = 0;
701 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700702 } else {
Andy Hung2c0e17c2015-01-12 15:07:14 -0800703 // writing to shared memory, check for capacity
704 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
705 sizeInBytes = track->sharedBuffer()->size();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700706 }
Ytai Ben-Tsvi2c9d8f62019-09-05 15:14:31 -0700707 memcpy(track->sharedBuffer()->unsecurePointer(), data + offsetInSamples, sizeInBytes);
Andy Hung2c0e17c2015-01-12 15:07:14 -0800708 written = sizeInBytes;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700709 }
Eric Laurent219de732016-05-23 12:41:50 -0700710 if (written >= 0) {
Andy Hung4aacc902015-04-14 15:01:29 -0700711 return written / sizeof(T);
712 }
Eric Laurent219de732016-05-23 12:41:50 -0700713 return interpretWriteSizeError(written);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700714}
715
716// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700717template <typename T>
718static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
719 T javaAudioData,
720 jint offsetInSamples, jint sizeInSamples,
721 jint javaAudioFormat,
722 jboolean isWriteBlocking) {
723 //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
724 // offsetInSamples, sizeInSamples);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700725 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 if (lpTrack == NULL) {
727 jniThrowException(env, "java/lang/IllegalStateException",
728 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700729 return (jint)AUDIO_JAVA_INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 }
731
Andy Hung4aacc902015-04-14 15:01:29 -0700732 if (javaAudioData == NULL) {
733 ALOGE("NULL java array of audio data to play");
734 return (jint)AUDIO_JAVA_BAD_VALUE;
735 }
736
Eric Laurent421ddc02011-03-07 14:52:59 -0800737 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
738 // a way that it becomes much more efficient. When doing so, we will have to prevent the
739 // AudioSystem callback to be called while in critical section (in case of media server
740 // process crash for instance)
Andy Hung4aacc902015-04-14 15:01:29 -0700741
742 // get the pointer for the audio data from the java array
743 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
744 if (cAudioData == NULL) {
745 ALOGE("Error retrieving source of audio data to play");
746 return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 }
748
Andy Hung4aacc902015-04-14 15:01:29 -0700749 jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
750 offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751
Andy Hung4aacc902015-04-14 15:01:29 -0700752 envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753
Andy Hung4aacc902015-04-14 15:01:29 -0700754 //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
755 // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
756 return samplesWritten;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757}
758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759// ----------------------------------------------------------------------------
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800760static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
Orion Hodson9b909c32018-11-23 11:05:27 +0000761 jobject javaByteBuffer, jint byteOffset, jint sizeInBytes,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800762 jint javaAudioFormat, jboolean isWriteBlocking) {
763 //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
764 // offsetInBytes, sizeInBytes);
765 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
766 if (lpTrack == NULL) {
767 jniThrowException(env, "java/lang/IllegalStateException",
768 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700769 return (jint)AUDIO_JAVA_INVALID_OPERATION;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800770 }
771
Orion Hodson9b909c32018-11-23 11:05:27 +0000772 const jbyte* bytes =
773 reinterpret_cast<const jbyte*>(env->GetDirectBufferAddress(javaByteBuffer));
774 if (bytes == NULL) {
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800775 ALOGE("Error retrieving source of audio data to play, can't play");
Eric Laurentbc11a692014-05-16 12:19:25 -0700776 return (jint)AUDIO_JAVA_BAD_VALUE;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800777 }
778
Orion Hodson9b909c32018-11-23 11:05:27 +0000779 jint written = writeToTrack(lpTrack, javaAudioFormat, bytes, byteOffset,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800780 sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
781
782 return written;
783}
784
785// ----------------------------------------------------------------------------
Phil Burk10a33e42016-01-08 12:40:41 -0800786static jint android_media_AudioTrack_get_buffer_size_frames(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700787 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
788 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 jniThrowException(env, "java/lang/IllegalStateException",
Phil Burk10a33e42016-01-08 12:40:41 -0800790 "Unable to retrieve AudioTrack pointer for getBufferSizeInFrames()");
791 return (jint)AUDIO_JAVA_ERROR;
792 }
793
794 ssize_t result = lpTrack->getBufferSizeInFrames();
795 if (result < 0) {
Ben Wagner85ea32b2016-03-16 17:10:42 -0400796 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
797 "Internal error detected in getBufferSizeInFrames() = %zd", result);
Phil Burk10a33e42016-01-08 12:40:41 -0800798 return (jint)AUDIO_JAVA_ERROR;
799 }
800 return (jint)result;
801}
802
803// ----------------------------------------------------------------------------
804static jint android_media_AudioTrack_set_buffer_size_frames(JNIEnv *env,
805 jobject thiz, jint bufferSizeInFrames) {
806 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
807 if (lpTrack == NULL) {
808 jniThrowException(env, "java/lang/IllegalStateException",
809 "Unable to retrieve AudioTrack pointer for setBufferSizeInFrames()");
810 return (jint)AUDIO_JAVA_ERROR;
811 }
812 // Value will be coerced into the valid range.
813 // But internal values are unsigned, size_t, so we need to clip
814 // against zero here where it is signed.
815 if (bufferSizeInFrames < 0) {
816 bufferSizeInFrames = 0;
817 }
818 ssize_t result = lpTrack->setBufferSizeInFrames(bufferSizeInFrames);
819 if (result < 0) {
Ben Wagner85ea32b2016-03-16 17:10:42 -0400820 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
821 "Internal error detected in setBufferSizeInFrames() = %zd", result);
Phil Burk10a33e42016-01-08 12:40:41 -0800822 return (jint)AUDIO_JAVA_ERROR;
823 }
824 return (jint)result;
825}
826
827// ----------------------------------------------------------------------------
828static jint android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv *env, jobject thiz) {
829 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
830 if (lpTrack == NULL) {
831 jniThrowException(env, "java/lang/IllegalStateException",
832 "Unable to retrieve AudioTrack pointer for getBufferCapacityInFrames()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700833 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700835
836 return lpTrack->frameCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837}
838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700840static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 jint sampleRateInHz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700842 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
843 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 jniThrowException(env, "java/lang/IllegalStateException",
845 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700846 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700848 return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849}
850
851
852// ----------------------------------------------------------------------------
853static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700854 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
855 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 jniThrowException(env, "java/lang/IllegalStateException",
857 "Unable to retrieve AudioTrack pointer for getSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700858 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700860 return (jint) lpTrack->getSampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861}
862
863
864// ----------------------------------------------------------------------------
Wei Jia2d61e2b2015-05-08 15:23:28 -0700865static void android_media_AudioTrack_set_playback_params(JNIEnv *env, jobject thiz,
866 jobject params) {
Andy Hung263b4c92015-04-16 11:16:29 -0700867 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
868 if (lpTrack == NULL) {
869 jniThrowException(env, "java/lang/IllegalStateException",
870 "AudioTrack not initialized");
871 return;
872 }
873
Andy Hung973b8852015-05-13 15:15:25 -0700874 PlaybackParams pbp;
875 pbp.fillFromJobject(env, gPlaybackParamsFields, params);
Andy Hungfe48e0d2015-04-27 18:14:02 -0700876
Wei Jia2d61e2b2015-05-08 15:23:28 -0700877 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
Andy Hung973b8852015-05-13 15:15:25 -0700878 pbp.speedSet, pbp.audioRate.mSpeed,
879 pbp.pitchSet, pbp.audioRate.mPitch,
880 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
881 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
Andy Hungfe48e0d2015-04-27 18:14:02 -0700882
Andy Hung973b8852015-05-13 15:15:25 -0700883 // to simulate partially set params, we do a read-modify-write.
884 // TODO: pass in the valid set mask into AudioTrack.
885 AudioPlaybackRate rate = lpTrack->getPlaybackRate();
886 bool updatedRate = false;
887 if (pbp.speedSet) {
888 rate.mSpeed = pbp.audioRate.mSpeed;
889 updatedRate = true;
890 }
891 if (pbp.pitchSet) {
892 rate.mPitch = pbp.audioRate.mPitch;
893 updatedRate = true;
894 }
895 if (pbp.audioFallbackModeSet) {
896 rate.mFallbackMode = pbp.audioRate.mFallbackMode;
897 updatedRate = true;
898 }
899 if (pbp.audioStretchModeSet) {
900 rate.mStretchMode = pbp.audioRate.mStretchMode;
901 updatedRate = true;
902 }
903 if (updatedRate) {
904 if (lpTrack->setPlaybackRate(rate) != OK) {
905 jniThrowException(env, "java/lang/IllegalArgumentException",
906 "arguments out of range");
907 }
Andy Hung263b4c92015-04-16 11:16:29 -0700908 }
909}
910
911
912// ----------------------------------------------------------------------------
Wei Jia2d61e2b2015-05-08 15:23:28 -0700913static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env, jobject thiz,
914 jobject params) {
Andy Hung263b4c92015-04-16 11:16:29 -0700915 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
916 if (lpTrack == NULL) {
917 jniThrowException(env, "java/lang/IllegalStateException",
918 "AudioTrack not initialized");
Andy Hungfe48e0d2015-04-27 18:14:02 -0700919 return NULL;
Andy Hung263b4c92015-04-16 11:16:29 -0700920 }
921
Wei Jia2d61e2b2015-05-08 15:23:28 -0700922 PlaybackParams pbs;
Andy Hungfe48e0d2015-04-27 18:14:02 -0700923 pbs.audioRate = lpTrack->getPlaybackRate();
924 pbs.speedSet = true;
925 pbs.pitchSet = true;
926 pbs.audioFallbackModeSet = true;
927 pbs.audioStretchModeSet = true;
Wei Jia2d61e2b2015-05-08 15:23:28 -0700928 return pbs.asJobject(env, gPlaybackParamsFields);
Andy Hung263b4c92015-04-16 11:16:29 -0700929}
930
931
932// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700933static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 jint markerPos) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700935 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
936 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 jniThrowException(env, "java/lang/IllegalStateException",
938 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700939 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700941 return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942}
943
944
945// ----------------------------------------------------------------------------
946static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700947 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700949
Eric Laurent532bc1c2012-04-20 12:45:03 -0700950 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 jniThrowException(env, "java/lang/IllegalStateException",
952 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700953 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700955 lpTrack->getMarkerPosition(&markerPos);
956 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957}
958
959
960// ----------------------------------------------------------------------------
961static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
962 jint period) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700963 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
964 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 jniThrowException(env, "java/lang/IllegalStateException",
966 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700967 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700968 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700969 return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970}
971
972
973// ----------------------------------------------------------------------------
974static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700975 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700977
Eric Laurent532bc1c2012-04-20 12:45:03 -0700978 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 jniThrowException(env, "java/lang/IllegalStateException",
980 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700981 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700983 lpTrack->getPositionUpdatePeriod(&period);
984 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985}
986
987
988// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700989static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 jint position) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700991 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
992 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 jniThrowException(env, "java/lang/IllegalStateException",
994 "Unable to retrieve AudioTrack pointer for setPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700995 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700997 return nativeToJavaStatus( lpTrack->setPosition(position) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998}
999
1000
1001// ----------------------------------------------------------------------------
1002static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001003 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 uint32_t position = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -07001005
Eric Laurent532bc1c2012-04-20 12:45:03 -07001006 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 jniThrowException(env, "java/lang/IllegalStateException",
1008 "Unable to retrieve AudioTrack pointer for getPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001009 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
Eric Laurent532bc1c2012-04-20 12:45:03 -07001011 lpTrack->getPosition(&position);
1012 return (jint)position;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013}
1014
1015
1016// ----------------------------------------------------------------------------
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001017static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
1018 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1019
1020 if (lpTrack == NULL) {
1021 jniThrowException(env, "java/lang/IllegalStateException",
1022 "Unable to retrieve AudioTrack pointer for latency()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001023 return (jint)AUDIO_JAVA_ERROR;
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001024 }
1025 return (jint)lpTrack->latency();
1026}
1027
Phil Burk03f61bb2016-01-17 21:49:58 +00001028// ----------------------------------------------------------------------------
1029static jint android_media_AudioTrack_get_underrun_count(JNIEnv *env, jobject thiz) {
1030 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1031
1032 if (lpTrack == NULL) {
1033 jniThrowException(env, "java/lang/IllegalStateException",
1034 "Unable to retrieve AudioTrack pointer for getUnderrunCount()");
1035 return (jint)AUDIO_JAVA_ERROR;
1036 }
1037 return (jint)lpTrack->getUnderrunCount();
1038}
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001039
1040// ----------------------------------------------------------------------------
Andy Hungebc2c142017-01-12 19:20:29 -08001041static jint android_media_AudioTrack_get_flags(JNIEnv *env, jobject thiz) {
1042 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1043
1044 if (lpTrack == NULL) {
1045 jniThrowException(env, "java/lang/IllegalStateException",
1046 "Unable to retrieve AudioTrack pointer for getFlags()");
1047 return (jint)AUDIO_JAVA_ERROR;
1048 }
1049 return (jint)lpTrack->getFlags();
1050}
1051
1052// ----------------------------------------------------------------------------
Glenn Kasten948c2e62013-09-04 13:51:29 -07001053static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
1054 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1055
1056 if (lpTrack == NULL) {
1057 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001058 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -07001059 }
1060 AudioTimestamp timestamp;
1061 status_t status = lpTrack->getTimestamp(timestamp);
1062 if (status == OK) {
1063 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
1064 if (nTimestamp == NULL) {
1065 ALOGE("Unable to get array for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001066 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -07001067 }
1068 nTimestamp[0] = (jlong) timestamp.mPosition;
1069 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
1070 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
1071 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001072 return (jint) nativeToJavaStatus(status);
Glenn Kasten948c2e62013-09-04 13:51:29 -07001073}
1074
Ray Essick510225b2018-01-24 14:27:16 -08001075// ----------------------------------------------------------------------------
1076static jobject
1077android_media_AudioTrack_native_getMetrics(JNIEnv *env, jobject thiz)
1078{
1079 ALOGD("android_media_AudioTrack_native_getMetrics");
1080
1081 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1082
1083 if (lpTrack == NULL) {
1084 ALOGE("Unable to retrieve AudioTrack pointer for getMetrics()");
1085 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1086 return (jobject) NULL;
1087 }
1088
1089 // get what we have for the metrics from the track
Ray Essick81fbc5b2019-12-07 06:24:59 -08001090 mediametrics::Item *item = NULL;
Ray Essick510225b2018-01-24 14:27:16 -08001091
1092 status_t err = lpTrack->getMetrics(item);
1093 if (err != OK) {
1094 ALOGE("getMetrics failed");
1095 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1096 return (jobject) NULL;
1097 }
1098
1099 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
1100
1101 // housekeeping
1102 delete item;
1103 item = NULL;
1104
1105 return mybundle;
1106}
1107
Glenn Kasten948c2e62013-09-04 13:51:29 -07001108
1109// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
1111 jint loopStart, jint loopEnd, jint loopCount) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001112 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1113 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 jniThrowException(env, "java/lang/IllegalStateException",
1115 "Unable to retrieve AudioTrack pointer for setLoop()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001116 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001118 return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119}
1120
1121
1122// ----------------------------------------------------------------------------
1123static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001124 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1125 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 jniThrowException(env, "java/lang/IllegalStateException",
1127 "Unable to retrieve AudioTrack pointer for reload()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001128 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001130 return nativeToJavaStatus( lpTrack->reload() );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131}
1132
1133
1134// ----------------------------------------------------------------------------
1135static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
1136 jint javaStreamType) {
Glenn Kasten85fbc872012-11-14 13:21:09 -08001137 uint32_t afSamplingRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 // convert the stream type from Java to native value
Jean-Michel Trivieac84382014-02-04 14:50:40 -08001139 // FIXME: code duplication with android_media_AudioTrack_setup()
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001140 audio_stream_type_t nativeStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -08001141 switch (javaStreamType) {
1142 case AUDIO_STREAM_VOICE_CALL:
1143 case AUDIO_STREAM_SYSTEM:
1144 case AUDIO_STREAM_RING:
1145 case AUDIO_STREAM_MUSIC:
1146 case AUDIO_STREAM_ALARM:
1147 case AUDIO_STREAM_NOTIFICATION:
1148 case AUDIO_STREAM_BLUETOOTH_SCO:
1149 case AUDIO_STREAM_DTMF:
1150 nativeStreamType = (audio_stream_type_t) javaStreamType;
1151 break;
1152 default:
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001153 nativeStreamType = AUDIO_STREAM_DEFAULT;
Glenn Kasten29a09092012-01-16 14:37:12 -08001154 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 }
1156
Glenn Kasten8f81d082012-11-28 14:37:48 -08001157 status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
1158 if (status != NO_ERROR) {
1159 ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
1160 "in AudioTrack JNI", status, nativeStreamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 return DEFAULT_OUTPUT_SAMPLE_RATE;
1162 } else {
1163 return afSamplingRate;
1164 }
1165}
1166
1167
1168// ----------------------------------------------------------------------------
1169// returns the minimum required size for the successful creation of a streaming AudioTrack
1170// returns -1 if there was an error querying the hardware.
1171static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
Glenn Kasten5b8fd442013-11-14 09:44:14 -08001172 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +08001173
Glenn Kasten659a9712014-01-08 11:38:33 -08001174 size_t frameCount;
1175 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
1176 sampleRateInHertz);
1177 if (status != NO_ERROR) {
1178 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
1179 sampleRateInHertz, status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 return -1;
1181 }
Glenn Kastenfe834d32014-01-08 14:49:08 -08001182 const audio_format_t format = audioFormatToNative(audioFormat);
Phil Burk43f4b272016-01-27 15:35:20 -08001183 if (audio_has_proportional_frames(format)) {
Eric Laurentff0d9f02014-06-09 17:23:02 -07001184 const size_t bytesPerSample = audio_bytes_per_sample(format);
1185 return frameCount * channelCount * bytesPerSample;
1186 } else {
1187 return frameCount;
1188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189}
1190
Eric Laurent7070b362010-07-16 07:43:46 -07001191// ----------------------------------------------------------------------------
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001192static jint
Eric Laurent7070b362010-07-16 07:43:46 -07001193android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
1194{
Eric Laurent532bc1c2012-04-20 12:45:03 -07001195 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Eric Laurent7070b362010-07-16 07:43:46 -07001196 if (lpTrack == NULL ) {
1197 jniThrowException(env, "java/lang/IllegalStateException",
1198 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001199 return -1;
Eric Laurent7070b362010-07-16 07:43:46 -07001200 }
1201
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001202 status_t status = lpTrack->setAuxEffectSendLevel(level);
1203 if (status != NO_ERROR) {
1204 ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
1205 level, status);
1206 }
1207 return (jint) status;
Eric Laurent7070b362010-07-16 07:43:46 -07001208}
1209
1210// ----------------------------------------------------------------------------
1211static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
1212 jint effectId) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001213 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1214 if (lpTrack == NULL) {
Eric Laurent7070b362010-07-16 07:43:46 -07001215 jniThrowException(env, "java/lang/IllegalStateException",
1216 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001217 return (jint)AUDIO_JAVA_ERROR;
Eric Laurent7070b362010-07-16 07:43:46 -07001218 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001219 return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
Eric Laurent7070b362010-07-16 07:43:46 -07001220}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221
Paul McLean88e1d862015-04-06 16:36:51 -07001222static jboolean android_media_AudioTrack_setOutputDevice(
1223 JNIEnv *env, jobject thiz, jint device_id) {
1224
1225 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Paul McLeancef696e2015-05-21 08:51:18 -07001226 if (lpTrack == 0) {
1227 return false;
1228 }
Paul McLean88e1d862015-04-06 16:36:51 -07001229 return lpTrack->setOutputDevice(device_id) == NO_ERROR;
1230}
1231
Eric Laurent4bcdba82015-05-01 11:37:49 -07001232static jint android_media_AudioTrack_getRoutedDeviceId(
1233 JNIEnv *env, jobject thiz) {
1234
1235 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1236 if (lpTrack == NULL) {
1237 return 0;
1238 }
1239 return (jint)lpTrack->getRoutedDeviceId();
1240}
1241
1242static void android_media_AudioTrack_enableDeviceCallback(
1243 JNIEnv *env, jobject thiz) {
1244
1245 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1246 if (lpTrack == NULL) {
1247 return;
1248 }
1249 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1250 thiz, javaAudioTrackFields.jniData);
1251 if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
1252 return;
1253 }
1254 pJniStorage->mDeviceCallback =
1255 new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
1256 javaAudioTrackFields.postNativeEventInJava);
1257 lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
1258}
1259
1260static void android_media_AudioTrack_disableDeviceCallback(
1261 JNIEnv *env, jobject thiz) {
1262
1263 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1264 if (lpTrack == NULL) {
1265 return;
1266 }
1267 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1268 thiz, javaAudioTrackFields.jniData);
1269 if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
1270 return;
1271 }
1272 lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
1273 pJniStorage->mDeviceCallback.clear();
1274}
1275
Andy Hung035d4ec2017-01-24 13:45:02 -08001276// Pass through the arguments to the AudioFlinger track implementation.
1277static jint android_media_AudioTrack_apply_volume_shaper(JNIEnv *env, jobject thiz,
1278 jobject jconfig, jobject joperation) {
1279 // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
1280 const int VOLUME_SHAPER_INVALID_OPERATION = -38;
1281
1282 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1283 if (lpTrack == nullptr) {
1284 return (jint)VOLUME_SHAPER_INVALID_OPERATION;
1285 }
1286
1287 sp<VolumeShaper::Configuration> configuration;
1288 sp<VolumeShaper::Operation> operation;
1289 if (jconfig != nullptr) {
1290 configuration = VolumeShaperHelper::convertJobjectToConfiguration(
1291 env, gVolumeShaperFields, jconfig);
1292 ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
1293 }
1294 if (joperation != nullptr) {
1295 operation = VolumeShaperHelper::convertJobjectToOperation(
1296 env, gVolumeShaperFields, joperation);
1297 ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
1298 }
1299 VolumeShaper::Status status = lpTrack->applyVolumeShaper(configuration, operation);
1300 if (status == INVALID_OPERATION) {
1301 status = VOLUME_SHAPER_INVALID_OPERATION;
1302 }
1303 return (jint)status; // if status < 0 an error, else a VolumeShaper id
1304}
1305
1306// Pass through the arguments to the AudioFlinger track implementation.
1307static jobject android_media_AudioTrack_get_volume_shaper_state(JNIEnv *env, jobject thiz,
1308 jint id) {
1309 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1310 if (lpTrack == nullptr) {
1311 return (jobject)nullptr;
1312 }
1313
1314 sp<VolumeShaper::State> state = lpTrack->getVolumeShaperState((int)id);
1315 if (state.get() == nullptr) {
1316 return (jobject)nullptr;
1317 }
1318 return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
1319}
Eric Laurent4bcdba82015-05-01 11:37:49 -07001320
Previr Rangroo58822be2017-11-28 17:53:54 +11001321static int android_media_AudioTrack_setPresentation(
1322 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
1323 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1324 if (lpTrack == NULL) {
1325 jniThrowException(env, "java/lang/IllegalStateException",
1326 "AudioTrack not initialized");
1327 return (jint)AUDIO_JAVA_ERROR;
1328 }
1329
1330 return (jint)lpTrack->selectPresentation((int)presentationId, (int)programId);
1331}
1332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333// ----------------------------------------------------------------------------
Eric Laurent2dc54832018-11-20 17:49:43 -08001334static jint android_media_AudioTrack_get_port_id(JNIEnv *env, jobject thiz) {
1335 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1336 if (lpTrack == NULL) {
1337 jniThrowException(env, "java/lang/IllegalStateException",
1338 "AudioTrack not initialized");
1339 return (jint)AUDIO_PORT_HANDLE_NONE;
1340 }
1341 return (jint)lpTrack->getPortId();
1342}
1343
1344// ----------------------------------------------------------------------------
Jean-Michel Trivi157cba42019-01-25 18:40:03 -08001345static void android_media_AudioTrack_set_delay_padding(JNIEnv *env, jobject thiz,
1346 jint delayInFrames, jint paddingInFrames) {
1347 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1348 if (lpTrack == NULL) {
1349 jniThrowException(env, "java/lang/IllegalStateException",
1350 "AudioTrack not initialized");
1351 return;
1352 }
1353 AudioParameter param = AudioParameter();
1354 param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), (int) delayInFrames);
1355 param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), (int) paddingInFrames);
1356 lpTrack->setParameters(param.toString());
1357}
1358
Andy Hungc33c9082020-01-17 14:05:06 -08001359static jint android_media_AudioTrack_setAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
1360 jfloat level) {
1361 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1362 if (lpTrack == nullptr) {
1363 jniThrowException(env, "java/lang/IllegalStateException", "AudioTrack not initialized");
1364 return (jint)AUDIO_JAVA_ERROR;
1365 }
1366
1367 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1368 return (jint)AUDIO_JAVA_ERROR;
1369}
1370
1371static jint android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
1372 jfloatArray level) {
1373 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1374 if (lpTrack == nullptr) {
1375 ALOGE("%s: AudioTrack not initialized", __func__);
1376 return (jint)AUDIO_JAVA_ERROR;
1377 }
1378 jfloat *nativeLevel = (jfloat *)env->GetPrimitiveArrayCritical(level, NULL);
1379 if (nativeLevel == nullptr) {
1380 ALOGE("%s: Cannot retrieve level pointer", __func__);
1381 return (jint)AUDIO_JAVA_ERROR;
1382 }
1383
1384 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1385 // By contract we can return -infinity if unsupported.
1386 *nativeLevel = -std::numeric_limits<float>::infinity();
1387 env->ReleasePrimitiveArrayCritical(level, nativeLevel, 0 /* mode */);
1388 nativeLevel = nullptr;
1389 return (jint)AUDIO_JAVA_SUCCESS;
1390}
1391
1392static jint android_media_AudioTrack_setDualMonoMode(JNIEnv *env, jobject thiz, jint dualMonoMode) {
1393 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1394 if (lpTrack == nullptr) {
1395 jniThrowException(env, "java/lang/IllegalStateException", "AudioTrack not initialized");
1396 return (jint)AUDIO_JAVA_ERROR;
1397 }
1398
1399 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1400 return (jint)AUDIO_JAVA_ERROR;
1401}
1402
1403static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
1404 jintArray dualMonoMode) {
1405 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1406 if (lpTrack == nullptr) {
1407 ALOGE("%s: AudioTrack not initialized", __func__);
1408 return (jint)AUDIO_JAVA_ERROR;
1409 }
1410 jfloat *nativeDualMonoMode = (jfloat *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
1411 if (nativeDualMonoMode == nullptr) {
1412 ALOGE("%s: Cannot retrieve dualMonoMode pointer", __func__);
1413 return (jint)AUDIO_JAVA_ERROR;
1414 }
1415
1416 // TODO: replace in r-dev or r-tv-dev with code if HW is able to select dual mono mode.
1417 // By contract we can return DUAL_MONO_MODE_OFF if unsupported.
1418 *nativeDualMonoMode = 0; // DUAL_MONO_MODE_OFF for now.
1419 env->ReleasePrimitiveArrayCritical(dualMonoMode, nativeDualMonoMode, 0 /* mode */);
1420 nativeDualMonoMode = nullptr;
1421 return (jint)AUDIO_JAVA_SUCCESS;
1422}
1423
Jean-Michel Trivi157cba42019-01-25 18:40:03 -08001424// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425// ----------------------------------------------------------------------------
Daniel Micay76f6a862015-09-19 17:31:01 -04001426static const JNINativeMethod gMethods[] = {
Andy Hung59dffec2020-01-14 17:29:03 -08001427 // name, signature, funcPtr
1428 {"native_is_direct_output_supported", "(IIIIIII)Z",
1429 (void *)android_media_AudioTrack_is_direct_output_supported},
1430 {"native_start", "()V", (void *)android_media_AudioTrack_start},
1431 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
1432 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
1433 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
jiabinfcd4cbf2020-08-21 18:07:27 -07001434 {"native_setup",
1435 "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;Ljava/lang/String;)I",
Andy Hung59dffec2020-01-14 17:29:03 -08001436 (void *)android_media_AudioTrack_setup},
1437 {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
1438 {"native_release", "()V", (void *)android_media_AudioTrack_release},
1439 {"native_write_byte", "([BIIIZ)I", (void *)android_media_AudioTrack_writeArray<jbyteArray>},
1440 {"native_write_native_bytes", "(Ljava/nio/ByteBuffer;IIIZ)I",
1441 (void *)android_media_AudioTrack_write_native_bytes},
1442 {"native_write_short", "([SIIIZ)I",
1443 (void *)android_media_AudioTrack_writeArray<jshortArray>},
1444 {"native_write_float", "([FIIIZ)I",
1445 (void *)android_media_AudioTrack_writeArray<jfloatArray>},
1446 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
1447 {"native_get_buffer_size_frames", "()I",
1448 (void *)android_media_AudioTrack_get_buffer_size_frames},
1449 {"native_set_buffer_size_frames", "(I)I",
1450 (void *)android_media_AudioTrack_set_buffer_size_frames},
1451 {"native_get_buffer_capacity_frames", "()I",
1452 (void *)android_media_AudioTrack_get_buffer_capacity_frames},
1453 {"native_set_playback_rate", "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
1454 {"native_get_playback_rate", "()I", (void *)android_media_AudioTrack_get_playback_rate},
1455 {"native_set_playback_params", "(Landroid/media/PlaybackParams;)V",
1456 (void *)android_media_AudioTrack_set_playback_params},
1457 {"native_get_playback_params", "()Landroid/media/PlaybackParams;",
1458 (void *)android_media_AudioTrack_get_playback_params},
1459 {"native_set_marker_pos", "(I)I", (void *)android_media_AudioTrack_set_marker_pos},
1460 {"native_get_marker_pos", "()I", (void *)android_media_AudioTrack_get_marker_pos},
1461 {"native_set_pos_update_period", "(I)I",
1462 (void *)android_media_AudioTrack_set_pos_update_period},
1463 {"native_get_pos_update_period", "()I",
1464 (void *)android_media_AudioTrack_get_pos_update_period},
1465 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
1466 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
1467 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
1468 {"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
1469 {"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
1470 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
1471 {"native_getMetrics", "()Landroid/os/PersistableBundle;",
1472 (void *)android_media_AudioTrack_native_getMetrics},
1473 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
1474 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
1475 {"native_get_output_sample_rate", "(I)I",
1476 (void *)android_media_AudioTrack_get_output_sample_rate},
1477 {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
1478 {"native_setAuxEffectSendLevel", "(F)I",
1479 (void *)android_media_AudioTrack_setAuxEffectSendLevel},
1480 {"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
1481 {"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
1482 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
1483 {"native_enableDeviceCallback", "()V",
1484 (void *)android_media_AudioTrack_enableDeviceCallback},
1485 {"native_disableDeviceCallback", "()V",
1486 (void *)android_media_AudioTrack_disableDeviceCallback},
1487 {"native_applyVolumeShaper",
1488 "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
1489 (void *)android_media_AudioTrack_apply_volume_shaper},
1490 {"native_getVolumeShaperState", "(I)Landroid/media/VolumeShaper$State;",
1491 (void *)android_media_AudioTrack_get_volume_shaper_state},
1492 {"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
1493 {"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
1494 {"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
Andy Hungc33c9082020-01-17 14:05:06 -08001495 {"native_set_audio_description_mix_level_db", "(F)I",
1496 (void *)android_media_AudioTrack_setAudioDescriptionMixLeveldB},
1497 {"native_get_audio_description_mix_level_db", "([F)I",
1498 (void *)android_media_AudioTrack_getAudioDescriptionMixLeveldB},
1499 {"native_set_dual_mono_mode", "(I)I", (void *)android_media_AudioTrack_setDualMonoMode},
1500 {"native_get_dual_mono_mode", "([I)I", (void *)android_media_AudioTrack_getDualMonoMode},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501};
1502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503// field names found in android/media/AudioTrack.java
1504#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
1506#define JAVA_JNIDATA_FIELD_NAME "mJniData"
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001507#define JAVA_STREAMTYPE_FIELD_NAME "mStreamType"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509// ----------------------------------------------------------------------------
1510// preconditions:
1511// theClass is valid
1512bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1513 const char* constName, int* constVal) {
1514 jfieldID javaConst = NULL;
1515 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1516 if (javaConst != NULL) {
1517 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1518 return true;
1519 } else {
Steve Block3762c312012-01-06 19:20:56 +00001520 ALOGE("Can't find %s.%s", className, constName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 return false;
1522 }
1523}
1524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525// ----------------------------------------------------------------------------
1526int register_android_media_AudioTrack(JNIEnv *env)
1527{
Glenn Kasten931fde42016-01-07 15:59:38 -08001528 // must be first
1529 int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1532 javaAudioTrackFields.postNativeEventInJava = NULL;
1533
1534 // Get the AudioTrack class
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001535 jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536
1537 // Get the postEvent method
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001538 javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1539 audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1540 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541
1542 // Get the variables fields
1543 // nativeTrackInJavaObj
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001544 javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1545 audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001546 // jniData
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001547 javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1548 audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001549 // fieldStreamType
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001550 javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1551 audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001552
Andy Hungfe48e0d2015-04-27 18:14:02 -07001553 env->DeleteLocalRef(audioTrackClass);
1554
Wei Jia2d61e2b2015-05-08 15:23:28 -07001555 // initialize PlaybackParams field info
1556 gPlaybackParamsFields.init(env);
Andy Hungfe48e0d2015-04-27 18:14:02 -07001557
Andy Hung035d4ec2017-01-24 13:45:02 -08001558 gVolumeShaperFields.init(env);
Andy Hung59dffec2020-01-14 17:29:03 -08001559
1560 // optional check that the TunerConfiguration class and fields exist.
1561 TunerConfigurationHelper::initCheckOrDie(env);
1562
Glenn Kasten931fde42016-01-07 15:59:38 -08001563 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564}
1565
1566
1567// ----------------------------------------------------------------------------