blob: a888b43a4854d051266e5da31b33b6a3b14ce0a2 [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>
Andreas Gampeed6b9df2014-11-20 22:02:20 -080023#include "core_jni_helpers.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
Glenn Kastenc81d31c2012-03-13 14:46:23 -070025#include <utils/Log.h>
Jean-Michel Trivi157cba42019-01-25 18:40:03 -080026#include <media/AudioParameter.h>
Glenn Kastenc81d31c2012-03-13 14:46:23 -070027#include <media/AudioSystem.h>
28#include <media/AudioTrack.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
Jean-Michel Trivi03f51392018-08-31 15:47:13 -070030#include <android-base/macros.h>
Mathias Agopian07952722009-05-19 19:08:10 -070031#include <binder/MemoryHeapBase.h>
32#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
Glenn Kastenfe834d32014-01-08 14:49:08 -080034#include "android_media_AudioFormat.h"
Eric Laurentbc11a692014-05-16 12:19:25 -070035#include "android_media_AudioErrors.h"
Ray Essick510225b2018-01-24 14:27:16 -080036#include "android_media_MediaMetricsJNI.h"
Wei Jia2d61e2b2015-05-08 15:23:28 -070037#include "android_media_PlaybackParams.h"
Eric Laurent4bcdba82015-05-01 11:37:49 -070038#include "android_media_DeviceCallback.h"
Andy Hung035d4ec2017-01-24 13:45:02 -080039#include "android_media_VolumeShaper.h"
François Gaffieb4691282018-07-09 13:07:32 +020040#include "android_media_AudioAttributes.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
Ben Wagner85ea32b2016-03-16 17:10:42 -040042#include <cinttypes>
43
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044// ----------------------------------------------------------------------------
45
46using namespace android;
47
Ivan Lozano330d8762017-08-08 12:51:06 -070048using ::android::media::VolumeShaper;
49
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050// ----------------------------------------------------------------------------
51static const char* const kClassPathName = "android/media/AudioTrack";
52
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070053struct audio_track_fields_t {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 // these fields provide access from C++ to the...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 jmethodID postNativeEventInJava; //... event post callback method
Eric Laurent83b36852009-07-28 07:49:22 -070056 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070058 jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059};
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070060static audio_track_fields_t javaAudioTrackFields;
Wei Jia2d61e2b2015-05-08 15:23:28 -070061static PlaybackParams::fields_t gPlaybackParamsFields;
Andy Hung035d4ec2017-01-24 13:45:02 -080062static VolumeShaperHelper::fields_t gVolumeShaperFields;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
64struct audiotrack_callback_cookie {
65 jclass audioTrack_class;
66 jobject audioTrack_ref;
Eric Laurent532bc1c2012-04-20 12:45:03 -070067 bool busy;
68 Condition cond;
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -080069 bool isOffload;
Eric Laurent532bc1c2012-04-20 12:45:03 -070070};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
Glenn Kasten3d301cb2012-01-16 14:46:54 -080072// keep these values in sync with AudioTrack.java
73#define MODE_STATIC 0
74#define MODE_STREAM 1
75
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076// ----------------------------------------------------------------------------
77class AudioTrackJniStorage {
78 public:
79 sp<MemoryHeapBase> mMemHeap;
80 sp<MemoryBase> mMemBase;
81 audiotrack_callback_cookie mCallbackData;
Eric Laurent4bcdba82015-05-01 11:37:49 -070082 sp<JNIDeviceCallback> mDeviceCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
84 AudioTrackJniStorage() {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -070085 mCallbackData.audioTrack_class = 0;
86 mCallbackData.audioTrack_ref = 0;
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -080087 mCallbackData.isOffload = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 }
89
90 ~AudioTrackJniStorage() {
91 mMemBase.clear();
92 mMemHeap.clear();
93 }
94
95 bool allocSharedMem(int sizeInBytes) {
96 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
97 if (mMemHeap->getHeapID() < 0) {
98 return false;
99 }
100 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
101 return true;
102 }
103};
104
Andy Hung59dffec2020-01-14 17:29:03 -0800105class TunerConfigurationHelper {
106 JNIEnv *const mEnv;
107 jobject const mTunerConfiguration;
108
109 struct Ids {
110 Ids(JNIEnv *env)
111 : mClass(FindClassOrDie(env, "android/media/AudioTrack$TunerConfiguration")),
112 mContentId(GetFieldIDOrDie(env, mClass, "mContentId", "I")),
113 mSyncId(GetFieldIDOrDie(env, mClass, "mSyncId", "I")) {}
114 const jclass mClass;
115 const jfieldID mContentId;
116 const jfieldID mSyncId;
117 };
118
119 static const Ids &getIds(JNIEnv *env) {
120 // Meyer's singleton, initializes first time control passes through
121 // declaration in a block and is thread-safe per ISO/IEC 14882:2011 6.7.4.
122 static Ids ids(env);
123 return ids;
124 }
125
126public:
127 TunerConfigurationHelper(JNIEnv *env, jobject tunerConfiguration)
128 : mEnv(env), mTunerConfiguration(tunerConfiguration) {}
129
130 int32_t getContentId() const {
131 if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
132 const Ids &ids = getIds(mEnv);
133 return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mContentId);
134 }
135
136 int32_t getSyncId() const {
137 if (mEnv == nullptr || mTunerConfiguration == nullptr) return 0;
138 const Ids &ids = getIds(mEnv);
139 return (int32_t)mEnv->GetIntField(mTunerConfiguration, ids.mSyncId);
140 }
141
142 // optional check to confirm class and field ids can be found.
143 static void initCheckOrDie(JNIEnv *env) { (void)getIds(env); }
144};
145
Eric Laurent532bc1c2012-04-20 12:45:03 -0700146static Mutex sLock;
147static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149// ----------------------------------------------------------------------------
150#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
151
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -0700152#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM (-16)
153#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK (-17)
154#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT (-18)
155#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE (-19)
156#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED (-20)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158// ----------------------------------------------------------------------------
Glenn Kastene46a86f2011-06-01 15:20:35 -0700159static void audioCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700160
161 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
162 {
163 Mutex::Autolock l(sLock);
164 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
165 return;
166 }
167 callbackInfo->busy = true;
168 }
169
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700170 // used as default argument when event callback doesn't have any, or number of
171 // frames for EVENT_CAN_WRITE_MORE_DATA
172 int arg = 0;
173 bool postEvent = false;
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700174 switch (event) {
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800175 // Offload only events
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700176 case AudioTrack::EVENT_CAN_WRITE_MORE_DATA:
177 // this event will read the info return parameter of the callback:
178 // for JNI offload, use the returned size to indicate:
179 // 1/ no data is returned through callback, as it's all done through write()
180 // 2/ do not wait as AudioTrack does when it receives 0 bytes
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800181 if (callbackInfo->isOffload) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700182 AudioTrack::Buffer* pBuffer = (AudioTrack::Buffer*) info;
183 const size_t availableForWrite = pBuffer->size;
184 arg = availableForWrite > INT32_MAX ? INT32_MAX : (int) availableForWrite;
185 pBuffer->size = 0;
186 }
187 FALLTHROUGH_INTENDED;
188 case AudioTrack::EVENT_STREAM_END:
189 case AudioTrack::EVENT_NEW_IAUDIOTRACK: // a.k.a. tear down
190 if (callbackInfo->isOffload) {
191 postEvent = true;
192 }
193 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800195 // PCM and offload events
196 case AudioTrack::EVENT_MARKER:
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700197 case AudioTrack::EVENT_NEW_POS:
198 postEvent = true;
199 break;
200 default:
201 // event will not be posted
202 break;
203 }
204
205 if (postEvent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 JNIEnv *env = AndroidRuntime::getJNIEnv();
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700207 if (env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 env->CallStaticVoidMethod(
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800209 callbackInfo->audioTrack_class,
210 javaAudioTrackFields.postNativeEventInJava,
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700211 callbackInfo->audioTrack_ref, event, arg, 0, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 if (env->ExceptionCheck()) {
213 env->ExceptionDescribe();
214 env->ExceptionClear();
215 }
216 }
217 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700218
Eric Laurent532bc1c2012-04-20 12:45:03 -0700219 {
220 Mutex::Autolock l(sLock);
221 callbackInfo->busy = false;
222 callbackInfo->cond.broadcast();
223 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224}
225
226
227// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700228static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
229{
230 Mutex::Autolock l(sLock);
231 AudioTrack* const at =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000232 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700233 return sp<AudioTrack>(at);
234}
235
236static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
237{
238 Mutex::Autolock l(sLock);
239 sp<AudioTrack> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000240 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700241 if (at.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800242 at->incStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700243 }
244 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800245 old->decStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700246 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000247 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700248 return old;
249}
Wei Jia071a8b72015-03-09 16:38:25 -0700250
251// ----------------------------------------------------------------------------
252sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
253 return getAudioTrack(env, audioTrackObj);
254}
255
Eric Laurent532bc1c2012-04-20 12:45:03 -0700256// ----------------------------------------------------------------------------
Andy Hung59dffec2020-01-14 17:29:03 -0800257static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
258 jobject jaa, jintArray jSampleRate,
259 jint channelPositionMask, jint channelIndexMask,
260 jint audioFormat, jint buffSizeInBytes, jint memoryMode,
261 jintArray jSession, jlong nativeAudioTrack,
262 jboolean offload, jint encapsulationMode,
263 jobject tunerConfiguration) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700264 ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
Andy Hung59dffec2020-01-14 17:29:03 -0800265 " nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p",
266 jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
267 nativeAudioTrack, offload, encapsulationMode, tunerConfiguration);
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700268
269 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000270 ALOGE("Error creating AudioTrack: invalid session ID pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700271 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent619346f2010-06-21 09:27:30 -0700272 }
273
Andy Hung59dffec2020-01-14 17:29:03 -0800274 // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
275 if (tunerConfiguration != nullptr) {
276 const TunerConfigurationHelper tunerHelper(env, tunerConfiguration);
277 ALOGE("Error creating AudioTrack: unsupported tuner contentId:%d syncId:%d",
278 tunerHelper.getContentId(), tunerHelper.getSyncId());
279 return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
280 }
281 // TODO: replace when we land matching AudioTrack::set() in frameworks/av in r or r-tv-dev.
282 if (encapsulationMode != 0 /* ENCAPSULATION_MODE_NONE */) {
283 ALOGE("Error creating AudioTrack: unsupported encapsulationMode %d", encapsulationMode);
284 return (jint)AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
285 }
286
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700287 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
288 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000289 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700290 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700291 }
Glenn Kasten33b84042016-03-08 12:02:55 -0800292 audio_session_t sessionId = (audio_session_t) nSession[0];
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700293 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
294 nSession = NULL;
295
Paul McLean9b09e532016-01-26 14:43:35 -0700296 AudioTrackJniStorage* lpJniStorage = NULL;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700297
Paul McLean9b09e532016-01-26 14:43:35 -0700298 jclass clazz = env->GetObjectClass(thiz);
299 if (clazz == NULL) {
300 ALOGE("Can't find %s when setting up callback.", kClassPathName);
301 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
302 }
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700303
Paul McLean9b09e532016-01-26 14:43:35 -0700304 // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
Andy Hung59dffec2020-01-14 17:29:03 -0800305 sp<AudioTrack> lpTrack;
Paul McLean9b09e532016-01-26 14:43:35 -0700306 if (nativeAudioTrack == 0) {
307 if (jaa == 0) {
308 ALOGE("Error creating AudioTrack: invalid audio attributes");
309 return (jint) AUDIO_JAVA_ERROR;
310 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700311
Paul McLean9b09e532016-01-26 14:43:35 -0700312 if (jSampleRate == 0) {
313 ALOGE("Error creating AudioTrack: invalid sample rates");
314 return (jint) AUDIO_JAVA_ERROR;
315 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316
Paul McLean9b09e532016-01-26 14:43:35 -0700317 int* sampleRates = env->GetIntArrayElements(jSampleRate, NULL);
318 int sampleRateInHertz = sampleRates[0];
319 env->ReleaseIntArrayElements(jSampleRate, sampleRates, JNI_ABORT);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700320
Paul McLean9b09e532016-01-26 14:43:35 -0700321 // Invalid channel representations are caught by !audio_is_output_channel() below.
322 audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
323 channelPositionMask, channelIndexMask);
324 if (!audio_is_output_channel(nativeChannelMask)) {
325 ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
326 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
327 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700328
Paul McLean9b09e532016-01-26 14:43:35 -0700329 uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
330
331 // check the format.
332 // This function was called from Java, so we compare the format against the Java constants
333 audio_format_t format = audioFormatToNative(audioFormat);
334 if (format == AUDIO_FORMAT_INVALID) {
335 ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
336 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
337 }
338
339 // compute the frame count
340 size_t frameCount;
jiabinf2d8e9c2018-02-23 17:44:56 -0800341 if (audio_has_proportional_frames(format)) {
Paul McLean9b09e532016-01-26 14:43:35 -0700342 const size_t bytesPerSample = audio_bytes_per_sample(format);
343 frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
344 } else {
345 frameCount = buffSizeInBytes;
346 }
347
348 // create the native AudioTrack object
349 lpTrack = new AudioTrack();
350
351 // read the AudioAttributes values
François Gaffieb4691282018-07-09 13:07:32 +0200352 auto paa = JNIAudioAttributeHelper::makeUnique();
353 jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
354 if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
355 return jStatus;
356 }
Paul McLean9b09e532016-01-26 14:43:35 -0700357 ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
358 paa->usage, paa->content_type, paa->flags, paa->tags);
359
360 // initialize the callback information:
361 // this data will be passed with every AudioTrack callback
362 lpJniStorage = new AudioTrackJniStorage();
363 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
364 // we use a weak reference so the AudioTrack object can be garbage collected.
365 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800366 lpJniStorage->mCallbackData.isOffload = offload;
Paul McLean9b09e532016-01-26 14:43:35 -0700367 lpJniStorage->mCallbackData.busy = false;
368
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800369 audio_offload_info_t offloadInfo;
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700370 if (offload == JNI_TRUE) {
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800371 offloadInfo = AUDIO_INFO_INITIALIZER;
372 offloadInfo.format = format;
373 offloadInfo.sample_rate = sampleRateInHertz;
374 offloadInfo.channel_mask = nativeChannelMask;
375 offloadInfo.has_video = false;
376 offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
377 }
378
Paul McLean9b09e532016-01-26 14:43:35 -0700379 // initialize the native AudioTrack object
380 status_t status = NO_ERROR;
381 switch (memoryMode) {
382 case MODE_STREAM:
Paul McLean9b09e532016-01-26 14:43:35 -0700383 status = lpTrack->set(
384 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
385 sampleRateInHertz,
386 format,// word length, PCM
387 nativeChannelMask,
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700388 offload ? 0 : frameCount,
389 offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_NONE,
Paul McLean9b09e532016-01-26 14:43:35 -0700390 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
391 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
392 0,// shared mem
393 true,// thread can call Java
394 sessionId,// audio session ID
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700395 offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC,
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800396 offload ? &offloadInfo : NULL,
Paul McLean9b09e532016-01-26 14:43:35 -0700397 -1, -1, // default uid, pid values
François Gaffieb4691282018-07-09 13:07:32 +0200398 paa.get());
Jean-Michel Trivi03f51392018-08-31 15:47:13 -0700399
Paul McLean9b09e532016-01-26 14:43:35 -0700400 break;
401
402 case MODE_STATIC:
403 // AudioTrack is using shared memory
404
405 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
406 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
407 goto native_init_failure;
408 }
409
410 status = lpTrack->set(
411 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
412 sampleRateInHertz,
413 format,// word length, PCM
414 nativeChannelMask,
415 frameCount,
416 AUDIO_OUTPUT_FLAG_NONE,
417 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
418 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
419 lpJniStorage->mMemBase,// shared mem
420 true,// thread can call Java
421 sessionId,// audio session ID
422 AudioTrack::TRANSFER_SHARED,
423 NULL, // default offloadInfo
424 -1, -1, // default uid, pid values
François Gaffieb4691282018-07-09 13:07:32 +0200425 paa.get());
Paul McLean9b09e532016-01-26 14:43:35 -0700426 break;
427
428 default:
429 ALOGE("Unknown mode %d", memoryMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 goto native_init_failure;
431 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700432
Paul McLean9b09e532016-01-26 14:43:35 -0700433 if (status != NO_ERROR) {
434 ALOGE("Error %d initializing AudioTrack", status);
435 goto native_init_failure;
436 }
437 } else { // end if (nativeAudioTrack == 0)
438 lpTrack = (AudioTrack*)nativeAudioTrack;
439 // TODO: We need to find out which members of the Java AudioTrack might
440 // need to be initialized from the Native AudioTrack
441 // these are directly returned from getters:
442 // mSampleRate
443 // mAudioFormat
444 // mStreamType
445 // mChannelConfiguration
446 // mChannelCount
447 // mState (?)
448 // mPlayState (?)
449 // these may be used internally (Java AudioTrack.audioParamCheck():
450 // mChannelMask
451 // mChannelIndexMask
452 // mDataLoadMode
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800453
Paul McLean9b09e532016-01-26 14:43:35 -0700454 // initialize the callback information:
455 // this data will be passed with every AudioTrack callback
456 lpJniStorage = new AudioTrackJniStorage();
457 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
458 // we use a weak reference so the AudioTrack object can be garbage collected.
459 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
460 lpJniStorage->mCallbackData.busy = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 }
462
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700463 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
464 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000465 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700466 goto native_init_failure;
467 }
Eric Laurent619346f2010-06-21 09:27:30 -0700468 // read the audio session ID back from AudioTrack in case we create a new session
469 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700470 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
471 nSession = NULL;
472
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800473 {
474 const jint elements[1] = { (jint) lpTrack->getSampleRate() };
475 env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
476 }
477
Eric Laurent532bc1c2012-04-20 12:45:03 -0700478 { // scope for the lock
479 Mutex::Autolock l(sLock);
480 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
481 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700482 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 // of the Java object (in mNativeTrackInJavaObj)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700484 setAudioTrack(env, thiz, lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 // save the JNI resources so we can free them later
Ashok Bhat075e9a12014-01-06 13:45:09 +0000487 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
488 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700490 // since we had audio attributes, the stream type was derived from them during the
491 // creation of the native AudioTrack: push the same value to the Java object
492 env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700493
Eric Laurentbc11a692014-05-16 12:19:25 -0700494 return (jint) AUDIO_JAVA_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 // failures:
497native_init_failure:
Eric Laurent619346f2010-06-21 09:27:30 -0700498 if (nSession != NULL) {
499 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
500 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700501 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
502 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 delete lpJniStorage;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000504 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700505
Glenn Kasten14d226a2015-05-18 13:53:39 -0700506 // lpTrack goes out of scope, so reference count drops to zero
Ashok Bhat075e9a12014-01-06 13:45:09 +0000507 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508}
509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510// ----------------------------------------------------------------------------
Michael Chan2de156d2018-04-24 14:33:57 +1000511static jboolean
512android_media_AudioTrack_is_direct_output_supported(JNIEnv *env, jobject thiz,
513 jint encoding, jint sampleRate,
514 jint channelMask, jint channelIndexMask,
515 jint contentType, jint usage, jint flags) {
516 audio_config_base_t config = {};
517 audio_attributes_t attributes = {};
518 config.format = static_cast<audio_format_t>(audioFormatToNative(encoding));
519 config.sample_rate = static_cast<uint32_t>(sampleRate);
520 config.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
521 attributes.content_type = static_cast<audio_content_type_t>(contentType);
522 attributes.usage = static_cast<audio_usage_t>(usage);
523 attributes.flags = static_cast<audio_flags_mask_t>(flags);
524 // ignore source and tags attributes as they don't affect querying whether output is supported
525 return AudioTrack::isDirectOutputSupported(config, attributes);
526}
527
528// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529static void
530android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
531{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700532 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
533 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 jniThrowException(env, "java/lang/IllegalStateException",
535 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700536 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 lpTrack->start();
540}
541
542
543// ----------------------------------------------------------------------------
544static void
545android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
546{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700547 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
548 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 jniThrowException(env, "java/lang/IllegalStateException",
550 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700551 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 }
553
554 lpTrack->stop();
555}
556
557
558// ----------------------------------------------------------------------------
559static void
560android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
561{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700562 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
563 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 jniThrowException(env, "java/lang/IllegalStateException",
565 "Unable to retrieve AudioTrack pointer for pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700566 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568
569 lpTrack->pause();
570}
571
572
573// ----------------------------------------------------------------------------
574static void
575android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
576{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700577 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
578 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 jniThrowException(env, "java/lang/IllegalStateException",
580 "Unable to retrieve AudioTrack pointer for flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700581 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 }
583
584 lpTrack->flush();
585}
586
587// ----------------------------------------------------------------------------
588static void
589android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
590{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700591 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
592 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 jniThrowException(env, "java/lang/IllegalStateException",
594 "Unable to retrieve AudioTrack pointer for setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700595 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 }
597
598 lpTrack->setVolume(leftVol, rightVol);
599}
600
601// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700602
Eric Laurent532bc1c2012-04-20 12:45:03 -0700603#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800604static void android_media_AudioTrack_release(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700605 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
606 if (lpTrack == NULL) {
607 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700609 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 // delete the JNI data
Ashok Bhat075e9a12014-01-06 13:45:09 +0000612 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 thiz, javaAudioTrackFields.jniData);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700614 // reset the native resources in the Java object so any attempt to access
615 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000616 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 if (pJniStorage) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700619 Mutex::Autolock l(sLock);
620 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
Steve Block71f2cf12011-10-20 11:56:00 +0100621 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700622 while (lpCookie->busy) {
623 if (lpCookie->cond.waitRelative(sLock,
624 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
625 NO_ERROR) {
626 break;
627 }
628 }
629 sAudioTrackCallBackCookies.remove(lpCookie);
630 // delete global refs created in native_setup
631 env->DeleteGlobalRef(lpCookie->audioTrack_class);
632 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 delete pJniStorage;
634 }
635}
636
Glenn Kasten18db49a2012-03-12 16:29:55 -0700637
Eric Laurent532bc1c2012-04-20 12:45:03 -0700638// ----------------------------------------------------------------------------
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800639static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
640 //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
641 android_media_AudioTrack_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642}
643
Andy Hung4aacc902015-04-14 15:01:29 -0700644// overloaded JNI array helper functions (same as in android_media_AudioRecord)
645static inline
646jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
647 return env->GetByteArrayElements(array, isCopy);
648}
649
650static inline
651void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
652 env->ReleaseByteArrayElements(array, elems, mode);
653}
654
655static inline
656jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
657 return env->GetShortArrayElements(array, isCopy);
658}
659
660static inline
661void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
662 env->ReleaseShortArrayElements(array, elems, mode);
663}
664
665static inline
666jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
667 return env->GetFloatArrayElements(array, isCopy);
668}
669
670static inline
671void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
672 env->ReleaseFloatArrayElements(array, elems, mode);
673}
674
Eric Laurent219de732016-05-23 12:41:50 -0700675static inline
676jint interpretWriteSizeError(ssize_t writeSize) {
677 if (writeSize == WOULD_BLOCK) {
678 return (jint)0;
679 } else if (writeSize == NO_INIT) {
680 return AUDIO_JAVA_DEAD_OBJECT;
681 } else {
682 ALOGE("Error %zd during AudioTrack native read", writeSize);
683 return nativeToJavaStatus(writeSize);
684 }
685}
686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700688template <typename T>
689static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
690 jint offsetInSamples, jint sizeInSamples, bool blocking) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700691 // give the data to the native AudioTrack object (the data starts at the offset)
692 ssize_t written = 0;
693 // regular write() or copy the data to the AudioTrack's shared memory?
Andy Hung4aacc902015-04-14 15:01:29 -0700694 size_t sizeInBytes = sizeInSamples * sizeof(T);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700695 if (track->sharedBuffer() == 0) {
Andy Hung4aacc902015-04-14 15:01:29 -0700696 written = track->write(data + offsetInSamples, sizeInBytes, blocking);
Glenn Kasten9b53db32013-07-10 14:13:39 -0700697 // for compatibility with earlier behavior of write(), return 0 in this case
698 if (written == (ssize_t) WOULD_BLOCK) {
699 written = 0;
700 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700701 } else {
Andy Hung2c0e17c2015-01-12 15:07:14 -0800702 // writing to shared memory, check for capacity
703 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
704 sizeInBytes = track->sharedBuffer()->size();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700705 }
Ytai Ben-Tsvi2c9d8f62019-09-05 15:14:31 -0700706 memcpy(track->sharedBuffer()->unsecurePointer(), data + offsetInSamples, sizeInBytes);
Andy Hung2c0e17c2015-01-12 15:07:14 -0800707 written = sizeInBytes;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700708 }
Eric Laurent219de732016-05-23 12:41:50 -0700709 if (written >= 0) {
Andy Hung4aacc902015-04-14 15:01:29 -0700710 return written / sizeof(T);
711 }
Eric Laurent219de732016-05-23 12:41:50 -0700712 return interpretWriteSizeError(written);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700713}
714
715// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700716template <typename T>
717static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
718 T javaAudioData,
719 jint offsetInSamples, jint sizeInSamples,
720 jint javaAudioFormat,
721 jboolean isWriteBlocking) {
722 //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
723 // offsetInSamples, sizeInSamples);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700724 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 if (lpTrack == NULL) {
726 jniThrowException(env, "java/lang/IllegalStateException",
727 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700728 return (jint)AUDIO_JAVA_INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 }
730
Andy Hung4aacc902015-04-14 15:01:29 -0700731 if (javaAudioData == NULL) {
732 ALOGE("NULL java array of audio data to play");
733 return (jint)AUDIO_JAVA_BAD_VALUE;
734 }
735
Eric Laurent421ddc02011-03-07 14:52:59 -0800736 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
737 // a way that it becomes much more efficient. When doing so, we will have to prevent the
738 // AudioSystem callback to be called while in critical section (in case of media server
739 // process crash for instance)
Andy Hung4aacc902015-04-14 15:01:29 -0700740
741 // get the pointer for the audio data from the java array
742 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
743 if (cAudioData == NULL) {
744 ALOGE("Error retrieving source of audio data to play");
745 return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 }
747
Andy Hung4aacc902015-04-14 15:01:29 -0700748 jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
749 offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750
Andy Hung4aacc902015-04-14 15:01:29 -0700751 envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752
Andy Hung4aacc902015-04-14 15:01:29 -0700753 //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
754 // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
755 return samplesWritten;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756}
757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758// ----------------------------------------------------------------------------
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800759static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
Orion Hodson9b909c32018-11-23 11:05:27 +0000760 jobject javaByteBuffer, jint byteOffset, jint sizeInBytes,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800761 jint javaAudioFormat, jboolean isWriteBlocking) {
762 //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
763 // offsetInBytes, sizeInBytes);
764 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
765 if (lpTrack == NULL) {
766 jniThrowException(env, "java/lang/IllegalStateException",
767 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700768 return (jint)AUDIO_JAVA_INVALID_OPERATION;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800769 }
770
Orion Hodson9b909c32018-11-23 11:05:27 +0000771 const jbyte* bytes =
772 reinterpret_cast<const jbyte*>(env->GetDirectBufferAddress(javaByteBuffer));
773 if (bytes == NULL) {
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800774 ALOGE("Error retrieving source of audio data to play, can't play");
Eric Laurentbc11a692014-05-16 12:19:25 -0700775 return (jint)AUDIO_JAVA_BAD_VALUE;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800776 }
777
Orion Hodson9b909c32018-11-23 11:05:27 +0000778 jint written = writeToTrack(lpTrack, javaAudioFormat, bytes, byteOffset,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800779 sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
780
781 return written;
782}
783
784// ----------------------------------------------------------------------------
Phil Burk10a33e42016-01-08 12:40:41 -0800785static jint android_media_AudioTrack_get_buffer_size_frames(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700786 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
787 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 jniThrowException(env, "java/lang/IllegalStateException",
Phil Burk10a33e42016-01-08 12:40:41 -0800789 "Unable to retrieve AudioTrack pointer for getBufferSizeInFrames()");
790 return (jint)AUDIO_JAVA_ERROR;
791 }
792
793 ssize_t result = lpTrack->getBufferSizeInFrames();
794 if (result < 0) {
Ben Wagner85ea32b2016-03-16 17:10:42 -0400795 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
796 "Internal error detected in getBufferSizeInFrames() = %zd", result);
Phil Burk10a33e42016-01-08 12:40:41 -0800797 return (jint)AUDIO_JAVA_ERROR;
798 }
799 return (jint)result;
800}
801
802// ----------------------------------------------------------------------------
803static jint android_media_AudioTrack_set_buffer_size_frames(JNIEnv *env,
804 jobject thiz, jint bufferSizeInFrames) {
805 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
806 if (lpTrack == NULL) {
807 jniThrowException(env, "java/lang/IllegalStateException",
808 "Unable to retrieve AudioTrack pointer for setBufferSizeInFrames()");
809 return (jint)AUDIO_JAVA_ERROR;
810 }
811 // Value will be coerced into the valid range.
812 // But internal values are unsigned, size_t, so we need to clip
813 // against zero here where it is signed.
814 if (bufferSizeInFrames < 0) {
815 bufferSizeInFrames = 0;
816 }
817 ssize_t result = lpTrack->setBufferSizeInFrames(bufferSizeInFrames);
818 if (result < 0) {
Ben Wagner85ea32b2016-03-16 17:10:42 -0400819 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
820 "Internal error detected in setBufferSizeInFrames() = %zd", result);
Phil Burk10a33e42016-01-08 12:40:41 -0800821 return (jint)AUDIO_JAVA_ERROR;
822 }
823 return (jint)result;
824}
825
826// ----------------------------------------------------------------------------
827static jint android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv *env, jobject thiz) {
828 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
829 if (lpTrack == NULL) {
830 jniThrowException(env, "java/lang/IllegalStateException",
831 "Unable to retrieve AudioTrack pointer for getBufferCapacityInFrames()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700832 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700834
835 return lpTrack->frameCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836}
837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700839static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 jint sampleRateInHz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700841 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
842 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 jniThrowException(env, "java/lang/IllegalStateException",
844 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700845 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700847 return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848}
849
850
851// ----------------------------------------------------------------------------
852static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700853 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
854 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 jniThrowException(env, "java/lang/IllegalStateException",
856 "Unable to retrieve AudioTrack pointer for getSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700857 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700859 return (jint) lpTrack->getSampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860}
861
862
863// ----------------------------------------------------------------------------
Wei Jia2d61e2b2015-05-08 15:23:28 -0700864static void android_media_AudioTrack_set_playback_params(JNIEnv *env, jobject thiz,
865 jobject params) {
Andy Hung263b4c92015-04-16 11:16:29 -0700866 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
867 if (lpTrack == NULL) {
868 jniThrowException(env, "java/lang/IllegalStateException",
869 "AudioTrack not initialized");
870 return;
871 }
872
Andy Hung973b8852015-05-13 15:15:25 -0700873 PlaybackParams pbp;
874 pbp.fillFromJobject(env, gPlaybackParamsFields, params);
Andy Hungfe48e0d2015-04-27 18:14:02 -0700875
Wei Jia2d61e2b2015-05-08 15:23:28 -0700876 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
Andy Hung973b8852015-05-13 15:15:25 -0700877 pbp.speedSet, pbp.audioRate.mSpeed,
878 pbp.pitchSet, pbp.audioRate.mPitch,
879 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
880 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
Andy Hungfe48e0d2015-04-27 18:14:02 -0700881
Andy Hung973b8852015-05-13 15:15:25 -0700882 // to simulate partially set params, we do a read-modify-write.
883 // TODO: pass in the valid set mask into AudioTrack.
884 AudioPlaybackRate rate = lpTrack->getPlaybackRate();
885 bool updatedRate = false;
886 if (pbp.speedSet) {
887 rate.mSpeed = pbp.audioRate.mSpeed;
888 updatedRate = true;
889 }
890 if (pbp.pitchSet) {
891 rate.mPitch = pbp.audioRate.mPitch;
892 updatedRate = true;
893 }
894 if (pbp.audioFallbackModeSet) {
895 rate.mFallbackMode = pbp.audioRate.mFallbackMode;
896 updatedRate = true;
897 }
898 if (pbp.audioStretchModeSet) {
899 rate.mStretchMode = pbp.audioRate.mStretchMode;
900 updatedRate = true;
901 }
902 if (updatedRate) {
903 if (lpTrack->setPlaybackRate(rate) != OK) {
904 jniThrowException(env, "java/lang/IllegalArgumentException",
905 "arguments out of range");
906 }
Andy Hung263b4c92015-04-16 11:16:29 -0700907 }
908}
909
910
911// ----------------------------------------------------------------------------
Wei Jia2d61e2b2015-05-08 15:23:28 -0700912static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env, jobject thiz,
913 jobject params) {
Andy Hung263b4c92015-04-16 11:16:29 -0700914 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
915 if (lpTrack == NULL) {
916 jniThrowException(env, "java/lang/IllegalStateException",
917 "AudioTrack not initialized");
Andy Hungfe48e0d2015-04-27 18:14:02 -0700918 return NULL;
Andy Hung263b4c92015-04-16 11:16:29 -0700919 }
920
Wei Jia2d61e2b2015-05-08 15:23:28 -0700921 PlaybackParams pbs;
Andy Hungfe48e0d2015-04-27 18:14:02 -0700922 pbs.audioRate = lpTrack->getPlaybackRate();
923 pbs.speedSet = true;
924 pbs.pitchSet = true;
925 pbs.audioFallbackModeSet = true;
926 pbs.audioStretchModeSet = true;
Wei Jia2d61e2b2015-05-08 15:23:28 -0700927 return pbs.asJobject(env, gPlaybackParamsFields);
Andy Hung263b4c92015-04-16 11:16:29 -0700928}
929
930
931// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700932static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 jint markerPos) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700934 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
935 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 jniThrowException(env, "java/lang/IllegalStateException",
937 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700938 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700940 return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941}
942
943
944// ----------------------------------------------------------------------------
945static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700946 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700948
Eric Laurent532bc1c2012-04-20 12:45:03 -0700949 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 jniThrowException(env, "java/lang/IllegalStateException",
951 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700952 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700954 lpTrack->getMarkerPosition(&markerPos);
955 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956}
957
958
959// ----------------------------------------------------------------------------
960static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
961 jint period) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700962 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
963 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 jniThrowException(env, "java/lang/IllegalStateException",
965 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700966 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700967 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700968 return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969}
970
971
972// ----------------------------------------------------------------------------
973static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700974 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700976
Eric Laurent532bc1c2012-04-20 12:45:03 -0700977 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 jniThrowException(env, "java/lang/IllegalStateException",
979 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700980 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700982 lpTrack->getPositionUpdatePeriod(&period);
983 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984}
985
986
987// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700988static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 jint position) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700990 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
991 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 jniThrowException(env, "java/lang/IllegalStateException",
993 "Unable to retrieve AudioTrack pointer for setPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700994 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700996 return nativeToJavaStatus( lpTrack->setPosition(position) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997}
998
999
1000// ----------------------------------------------------------------------------
1001static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001002 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 uint32_t position = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -07001004
Eric Laurent532bc1c2012-04-20 12:45:03 -07001005 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 jniThrowException(env, "java/lang/IllegalStateException",
1007 "Unable to retrieve AudioTrack pointer for getPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001008 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
Eric Laurent532bc1c2012-04-20 12:45:03 -07001010 lpTrack->getPosition(&position);
1011 return (jint)position;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012}
1013
1014
1015// ----------------------------------------------------------------------------
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001016static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
1017 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1018
1019 if (lpTrack == NULL) {
1020 jniThrowException(env, "java/lang/IllegalStateException",
1021 "Unable to retrieve AudioTrack pointer for latency()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001022 return (jint)AUDIO_JAVA_ERROR;
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001023 }
1024 return (jint)lpTrack->latency();
1025}
1026
Phil Burk03f61bb2016-01-17 21:49:58 +00001027// ----------------------------------------------------------------------------
1028static jint android_media_AudioTrack_get_underrun_count(JNIEnv *env, jobject thiz) {
1029 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1030
1031 if (lpTrack == NULL) {
1032 jniThrowException(env, "java/lang/IllegalStateException",
1033 "Unable to retrieve AudioTrack pointer for getUnderrunCount()");
1034 return (jint)AUDIO_JAVA_ERROR;
1035 }
1036 return (jint)lpTrack->getUnderrunCount();
1037}
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001038
1039// ----------------------------------------------------------------------------
Andy Hungebc2c142017-01-12 19:20:29 -08001040static jint android_media_AudioTrack_get_flags(JNIEnv *env, jobject thiz) {
1041 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1042
1043 if (lpTrack == NULL) {
1044 jniThrowException(env, "java/lang/IllegalStateException",
1045 "Unable to retrieve AudioTrack pointer for getFlags()");
1046 return (jint)AUDIO_JAVA_ERROR;
1047 }
1048 return (jint)lpTrack->getFlags();
1049}
1050
1051// ----------------------------------------------------------------------------
Glenn Kasten948c2e62013-09-04 13:51:29 -07001052static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
1053 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1054
1055 if (lpTrack == NULL) {
1056 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001057 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -07001058 }
1059 AudioTimestamp timestamp;
1060 status_t status = lpTrack->getTimestamp(timestamp);
1061 if (status == OK) {
1062 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
1063 if (nTimestamp == NULL) {
1064 ALOGE("Unable to get array for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001065 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -07001066 }
1067 nTimestamp[0] = (jlong) timestamp.mPosition;
1068 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
1069 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
1070 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001071 return (jint) nativeToJavaStatus(status);
Glenn Kasten948c2e62013-09-04 13:51:29 -07001072}
1073
Ray Essick510225b2018-01-24 14:27:16 -08001074// ----------------------------------------------------------------------------
1075static jobject
1076android_media_AudioTrack_native_getMetrics(JNIEnv *env, jobject thiz)
1077{
1078 ALOGD("android_media_AudioTrack_native_getMetrics");
1079
1080 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1081
1082 if (lpTrack == NULL) {
1083 ALOGE("Unable to retrieve AudioTrack pointer for getMetrics()");
1084 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1085 return (jobject) NULL;
1086 }
1087
1088 // get what we have for the metrics from the track
Ray Essick81fbc5b2019-12-07 06:24:59 -08001089 mediametrics::Item *item = NULL;
Ray Essick510225b2018-01-24 14:27:16 -08001090
1091 status_t err = lpTrack->getMetrics(item);
1092 if (err != OK) {
1093 ALOGE("getMetrics failed");
1094 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1095 return (jobject) NULL;
1096 }
1097
1098 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
1099
1100 // housekeeping
1101 delete item;
1102 item = NULL;
1103
1104 return mybundle;
1105}
1106
Glenn Kasten948c2e62013-09-04 13:51:29 -07001107
1108// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
1110 jint loopStart, jint loopEnd, jint loopCount) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001111 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1112 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 jniThrowException(env, "java/lang/IllegalStateException",
1114 "Unable to retrieve AudioTrack pointer for setLoop()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001115 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001117 return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118}
1119
1120
1121// ----------------------------------------------------------------------------
1122static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001123 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1124 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 jniThrowException(env, "java/lang/IllegalStateException",
1126 "Unable to retrieve AudioTrack pointer for reload()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001127 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001129 return nativeToJavaStatus( lpTrack->reload() );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130}
1131
1132
1133// ----------------------------------------------------------------------------
1134static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
1135 jint javaStreamType) {
Glenn Kasten85fbc872012-11-14 13:21:09 -08001136 uint32_t afSamplingRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 // convert the stream type from Java to native value
Jean-Michel Trivieac84382014-02-04 14:50:40 -08001138 // FIXME: code duplication with android_media_AudioTrack_setup()
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001139 audio_stream_type_t nativeStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -08001140 switch (javaStreamType) {
1141 case AUDIO_STREAM_VOICE_CALL:
1142 case AUDIO_STREAM_SYSTEM:
1143 case AUDIO_STREAM_RING:
1144 case AUDIO_STREAM_MUSIC:
1145 case AUDIO_STREAM_ALARM:
1146 case AUDIO_STREAM_NOTIFICATION:
1147 case AUDIO_STREAM_BLUETOOTH_SCO:
1148 case AUDIO_STREAM_DTMF:
1149 nativeStreamType = (audio_stream_type_t) javaStreamType;
1150 break;
1151 default:
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001152 nativeStreamType = AUDIO_STREAM_DEFAULT;
Glenn Kasten29a09092012-01-16 14:37:12 -08001153 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 }
1155
Glenn Kasten8f81d082012-11-28 14:37:48 -08001156 status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
1157 if (status != NO_ERROR) {
1158 ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
1159 "in AudioTrack JNI", status, nativeStreamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 return DEFAULT_OUTPUT_SAMPLE_RATE;
1161 } else {
1162 return afSamplingRate;
1163 }
1164}
1165
1166
1167// ----------------------------------------------------------------------------
1168// returns the minimum required size for the successful creation of a streaming AudioTrack
1169// returns -1 if there was an error querying the hardware.
1170static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
Glenn Kasten5b8fd442013-11-14 09:44:14 -08001171 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +08001172
Glenn Kasten659a9712014-01-08 11:38:33 -08001173 size_t frameCount;
1174 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
1175 sampleRateInHertz);
1176 if (status != NO_ERROR) {
1177 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
1178 sampleRateInHertz, status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 return -1;
1180 }
Glenn Kastenfe834d32014-01-08 14:49:08 -08001181 const audio_format_t format = audioFormatToNative(audioFormat);
Phil Burk43f4b272016-01-27 15:35:20 -08001182 if (audio_has_proportional_frames(format)) {
Eric Laurentff0d9f02014-06-09 17:23:02 -07001183 const size_t bytesPerSample = audio_bytes_per_sample(format);
1184 return frameCount * channelCount * bytesPerSample;
1185 } else {
1186 return frameCount;
1187 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188}
1189
Eric Laurent7070b362010-07-16 07:43:46 -07001190// ----------------------------------------------------------------------------
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001191static jint
Eric Laurent7070b362010-07-16 07:43:46 -07001192android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
1193{
Eric Laurent532bc1c2012-04-20 12:45:03 -07001194 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Eric Laurent7070b362010-07-16 07:43:46 -07001195 if (lpTrack == NULL ) {
1196 jniThrowException(env, "java/lang/IllegalStateException",
1197 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001198 return -1;
Eric Laurent7070b362010-07-16 07:43:46 -07001199 }
1200
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001201 status_t status = lpTrack->setAuxEffectSendLevel(level);
1202 if (status != NO_ERROR) {
1203 ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
1204 level, status);
1205 }
1206 return (jint) status;
Eric Laurent7070b362010-07-16 07:43:46 -07001207}
1208
1209// ----------------------------------------------------------------------------
1210static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
1211 jint effectId) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001212 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1213 if (lpTrack == NULL) {
Eric Laurent7070b362010-07-16 07:43:46 -07001214 jniThrowException(env, "java/lang/IllegalStateException",
1215 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001216 return (jint)AUDIO_JAVA_ERROR;
Eric Laurent7070b362010-07-16 07:43:46 -07001217 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001218 return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
Eric Laurent7070b362010-07-16 07:43:46 -07001219}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220
Paul McLean88e1d862015-04-06 16:36:51 -07001221static jboolean android_media_AudioTrack_setOutputDevice(
1222 JNIEnv *env, jobject thiz, jint device_id) {
1223
1224 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Paul McLeancef696e2015-05-21 08:51:18 -07001225 if (lpTrack == 0) {
1226 return false;
1227 }
Paul McLean88e1d862015-04-06 16:36:51 -07001228 return lpTrack->setOutputDevice(device_id) == NO_ERROR;
1229}
1230
Eric Laurent4bcdba82015-05-01 11:37:49 -07001231static jint android_media_AudioTrack_getRoutedDeviceId(
1232 JNIEnv *env, jobject thiz) {
1233
1234 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1235 if (lpTrack == NULL) {
1236 return 0;
1237 }
1238 return (jint)lpTrack->getRoutedDeviceId();
1239}
1240
1241static void android_media_AudioTrack_enableDeviceCallback(
1242 JNIEnv *env, jobject thiz) {
1243
1244 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1245 if (lpTrack == NULL) {
1246 return;
1247 }
1248 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1249 thiz, javaAudioTrackFields.jniData);
1250 if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
1251 return;
1252 }
1253 pJniStorage->mDeviceCallback =
1254 new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
1255 javaAudioTrackFields.postNativeEventInJava);
1256 lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
1257}
1258
1259static void android_media_AudioTrack_disableDeviceCallback(
1260 JNIEnv *env, jobject thiz) {
1261
1262 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1263 if (lpTrack == NULL) {
1264 return;
1265 }
1266 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1267 thiz, javaAudioTrackFields.jniData);
1268 if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
1269 return;
1270 }
1271 lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
1272 pJniStorage->mDeviceCallback.clear();
1273}
1274
Andy Hung035d4ec2017-01-24 13:45:02 -08001275// Pass through the arguments to the AudioFlinger track implementation.
1276static jint android_media_AudioTrack_apply_volume_shaper(JNIEnv *env, jobject thiz,
1277 jobject jconfig, jobject joperation) {
1278 // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
1279 const int VOLUME_SHAPER_INVALID_OPERATION = -38;
1280
1281 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1282 if (lpTrack == nullptr) {
1283 return (jint)VOLUME_SHAPER_INVALID_OPERATION;
1284 }
1285
1286 sp<VolumeShaper::Configuration> configuration;
1287 sp<VolumeShaper::Operation> operation;
1288 if (jconfig != nullptr) {
1289 configuration = VolumeShaperHelper::convertJobjectToConfiguration(
1290 env, gVolumeShaperFields, jconfig);
1291 ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
1292 }
1293 if (joperation != nullptr) {
1294 operation = VolumeShaperHelper::convertJobjectToOperation(
1295 env, gVolumeShaperFields, joperation);
1296 ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
1297 }
1298 VolumeShaper::Status status = lpTrack->applyVolumeShaper(configuration, operation);
1299 if (status == INVALID_OPERATION) {
1300 status = VOLUME_SHAPER_INVALID_OPERATION;
1301 }
1302 return (jint)status; // if status < 0 an error, else a VolumeShaper id
1303}
1304
1305// Pass through the arguments to the AudioFlinger track implementation.
1306static jobject android_media_AudioTrack_get_volume_shaper_state(JNIEnv *env, jobject thiz,
1307 jint id) {
1308 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1309 if (lpTrack == nullptr) {
1310 return (jobject)nullptr;
1311 }
1312
1313 sp<VolumeShaper::State> state = lpTrack->getVolumeShaperState((int)id);
1314 if (state.get() == nullptr) {
1315 return (jobject)nullptr;
1316 }
1317 return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
1318}
Eric Laurent4bcdba82015-05-01 11:37:49 -07001319
Previr Rangroo58822be2017-11-28 17:53:54 +11001320static int android_media_AudioTrack_setPresentation(
1321 JNIEnv *env, jobject thiz, jint presentationId, jint programId) {
1322 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1323 if (lpTrack == NULL) {
1324 jniThrowException(env, "java/lang/IllegalStateException",
1325 "AudioTrack not initialized");
1326 return (jint)AUDIO_JAVA_ERROR;
1327 }
1328
1329 return (jint)lpTrack->selectPresentation((int)presentationId, (int)programId);
1330}
1331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332// ----------------------------------------------------------------------------
Eric Laurent2dc54832018-11-20 17:49:43 -08001333static jint android_media_AudioTrack_get_port_id(JNIEnv *env, jobject thiz) {
1334 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1335 if (lpTrack == NULL) {
1336 jniThrowException(env, "java/lang/IllegalStateException",
1337 "AudioTrack not initialized");
1338 return (jint)AUDIO_PORT_HANDLE_NONE;
1339 }
1340 return (jint)lpTrack->getPortId();
1341}
1342
1343// ----------------------------------------------------------------------------
Jean-Michel Trivi157cba42019-01-25 18:40:03 -08001344static void android_media_AudioTrack_set_delay_padding(JNIEnv *env, jobject thiz,
1345 jint delayInFrames, jint paddingInFrames) {
1346 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1347 if (lpTrack == NULL) {
1348 jniThrowException(env, "java/lang/IllegalStateException",
1349 "AudioTrack not initialized");
1350 return;
1351 }
1352 AudioParameter param = AudioParameter();
1353 param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), (int) delayInFrames);
1354 param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), (int) paddingInFrames);
1355 lpTrack->setParameters(param.toString());
1356}
1357
Andy Hungc33c9082020-01-17 14:05:06 -08001358static jint android_media_AudioTrack_setAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
1359 jfloat level) {
1360 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1361 if (lpTrack == nullptr) {
1362 jniThrowException(env, "java/lang/IllegalStateException", "AudioTrack not initialized");
1363 return (jint)AUDIO_JAVA_ERROR;
1364 }
1365
1366 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1367 return (jint)AUDIO_JAVA_ERROR;
1368}
1369
1370static jint android_media_AudioTrack_getAudioDescriptionMixLeveldB(JNIEnv *env, jobject thiz,
1371 jfloatArray level) {
1372 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1373 if (lpTrack == nullptr) {
1374 ALOGE("%s: AudioTrack not initialized", __func__);
1375 return (jint)AUDIO_JAVA_ERROR;
1376 }
1377 jfloat *nativeLevel = (jfloat *)env->GetPrimitiveArrayCritical(level, NULL);
1378 if (nativeLevel == nullptr) {
1379 ALOGE("%s: Cannot retrieve level pointer", __func__);
1380 return (jint)AUDIO_JAVA_ERROR;
1381 }
1382
1383 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1384 // By contract we can return -infinity if unsupported.
1385 *nativeLevel = -std::numeric_limits<float>::infinity();
1386 env->ReleasePrimitiveArrayCritical(level, nativeLevel, 0 /* mode */);
1387 nativeLevel = nullptr;
1388 return (jint)AUDIO_JAVA_SUCCESS;
1389}
1390
1391static jint android_media_AudioTrack_setDualMonoMode(JNIEnv *env, jobject thiz, jint dualMonoMode) {
1392 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1393 if (lpTrack == nullptr) {
1394 jniThrowException(env, "java/lang/IllegalStateException", "AudioTrack not initialized");
1395 return (jint)AUDIO_JAVA_ERROR;
1396 }
1397
1398 // TODO: replace in r-dev or r-tv-dev with code if HW is able to set audio mix level.
1399 return (jint)AUDIO_JAVA_ERROR;
1400}
1401
1402static jint android_media_AudioTrack_getDualMonoMode(JNIEnv *env, jobject thiz,
1403 jintArray dualMonoMode) {
1404 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1405 if (lpTrack == nullptr) {
1406 ALOGE("%s: AudioTrack not initialized", __func__);
1407 return (jint)AUDIO_JAVA_ERROR;
1408 }
1409 jfloat *nativeDualMonoMode = (jfloat *)env->GetPrimitiveArrayCritical(dualMonoMode, NULL);
1410 if (nativeDualMonoMode == nullptr) {
1411 ALOGE("%s: Cannot retrieve dualMonoMode pointer", __func__);
1412 return (jint)AUDIO_JAVA_ERROR;
1413 }
1414
1415 // TODO: replace in r-dev or r-tv-dev with code if HW is able to select dual mono mode.
1416 // By contract we can return DUAL_MONO_MODE_OFF if unsupported.
1417 *nativeDualMonoMode = 0; // DUAL_MONO_MODE_OFF for now.
1418 env->ReleasePrimitiveArrayCritical(dualMonoMode, nativeDualMonoMode, 0 /* mode */);
1419 nativeDualMonoMode = nullptr;
1420 return (jint)AUDIO_JAVA_SUCCESS;
1421}
1422
Jean-Michel Trivi157cba42019-01-25 18:40:03 -08001423// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424// ----------------------------------------------------------------------------
Daniel Micay76f6a862015-09-19 17:31:01 -04001425static const JNINativeMethod gMethods[] = {
Andy Hung59dffec2020-01-14 17:29:03 -08001426 // name, signature, funcPtr
1427 {"native_is_direct_output_supported", "(IIIIIII)Z",
1428 (void *)android_media_AudioTrack_is_direct_output_supported},
1429 {"native_start", "()V", (void *)android_media_AudioTrack_start},
1430 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
1431 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
1432 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
1433 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;)I",
1434 (void *)android_media_AudioTrack_setup},
1435 {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
1436 {"native_release", "()V", (void *)android_media_AudioTrack_release},
1437 {"native_write_byte", "([BIIIZ)I", (void *)android_media_AudioTrack_writeArray<jbyteArray>},
1438 {"native_write_native_bytes", "(Ljava/nio/ByteBuffer;IIIZ)I",
1439 (void *)android_media_AudioTrack_write_native_bytes},
1440 {"native_write_short", "([SIIIZ)I",
1441 (void *)android_media_AudioTrack_writeArray<jshortArray>},
1442 {"native_write_float", "([FIIIZ)I",
1443 (void *)android_media_AudioTrack_writeArray<jfloatArray>},
1444 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
1445 {"native_get_buffer_size_frames", "()I",
1446 (void *)android_media_AudioTrack_get_buffer_size_frames},
1447 {"native_set_buffer_size_frames", "(I)I",
1448 (void *)android_media_AudioTrack_set_buffer_size_frames},
1449 {"native_get_buffer_capacity_frames", "()I",
1450 (void *)android_media_AudioTrack_get_buffer_capacity_frames},
1451 {"native_set_playback_rate", "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
1452 {"native_get_playback_rate", "()I", (void *)android_media_AudioTrack_get_playback_rate},
1453 {"native_set_playback_params", "(Landroid/media/PlaybackParams;)V",
1454 (void *)android_media_AudioTrack_set_playback_params},
1455 {"native_get_playback_params", "()Landroid/media/PlaybackParams;",
1456 (void *)android_media_AudioTrack_get_playback_params},
1457 {"native_set_marker_pos", "(I)I", (void *)android_media_AudioTrack_set_marker_pos},
1458 {"native_get_marker_pos", "()I", (void *)android_media_AudioTrack_get_marker_pos},
1459 {"native_set_pos_update_period", "(I)I",
1460 (void *)android_media_AudioTrack_set_pos_update_period},
1461 {"native_get_pos_update_period", "()I",
1462 (void *)android_media_AudioTrack_get_pos_update_period},
1463 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
1464 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
1465 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
1466 {"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
1467 {"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
1468 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
1469 {"native_getMetrics", "()Landroid/os/PersistableBundle;",
1470 (void *)android_media_AudioTrack_native_getMetrics},
1471 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
1472 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
1473 {"native_get_output_sample_rate", "(I)I",
1474 (void *)android_media_AudioTrack_get_output_sample_rate},
1475 {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
1476 {"native_setAuxEffectSendLevel", "(F)I",
1477 (void *)android_media_AudioTrack_setAuxEffectSendLevel},
1478 {"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
1479 {"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice},
1480 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
1481 {"native_enableDeviceCallback", "()V",
1482 (void *)android_media_AudioTrack_enableDeviceCallback},
1483 {"native_disableDeviceCallback", "()V",
1484 (void *)android_media_AudioTrack_disableDeviceCallback},
1485 {"native_applyVolumeShaper",
1486 "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
1487 (void *)android_media_AudioTrack_apply_volume_shaper},
1488 {"native_getVolumeShaperState", "(I)Landroid/media/VolumeShaper$State;",
1489 (void *)android_media_AudioTrack_get_volume_shaper_state},
1490 {"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
1491 {"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
1492 {"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
Andy Hungc33c9082020-01-17 14:05:06 -08001493 {"native_set_audio_description_mix_level_db", "(F)I",
1494 (void *)android_media_AudioTrack_setAudioDescriptionMixLeveldB},
1495 {"native_get_audio_description_mix_level_db", "([F)I",
1496 (void *)android_media_AudioTrack_getAudioDescriptionMixLeveldB},
1497 {"native_set_dual_mono_mode", "(I)I", (void *)android_media_AudioTrack_setDualMonoMode},
1498 {"native_get_dual_mono_mode", "([I)I", (void *)android_media_AudioTrack_getDualMonoMode},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499};
1500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501// field names found in android/media/AudioTrack.java
1502#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
1504#define JAVA_JNIDATA_FIELD_NAME "mJniData"
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001505#define JAVA_STREAMTYPE_FIELD_NAME "mStreamType"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507// ----------------------------------------------------------------------------
1508// preconditions:
1509// theClass is valid
1510bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1511 const char* constName, int* constVal) {
1512 jfieldID javaConst = NULL;
1513 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1514 if (javaConst != NULL) {
1515 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1516 return true;
1517 } else {
Steve Block3762c312012-01-06 19:20:56 +00001518 ALOGE("Can't find %s.%s", className, constName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 return false;
1520 }
1521}
1522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523// ----------------------------------------------------------------------------
1524int register_android_media_AudioTrack(JNIEnv *env)
1525{
Glenn Kasten931fde42016-01-07 15:59:38 -08001526 // must be first
1527 int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1530 javaAudioTrackFields.postNativeEventInJava = NULL;
1531
1532 // Get the AudioTrack class
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001533 jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534
1535 // Get the postEvent method
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001536 javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1537 audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1538 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539
1540 // Get the variables fields
1541 // nativeTrackInJavaObj
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001542 javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1543 audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001544 // jniData
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001545 javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1546 audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001547 // fieldStreamType
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001548 javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1549 audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001550
Andy Hungfe48e0d2015-04-27 18:14:02 -07001551 env->DeleteLocalRef(audioTrackClass);
1552
Wei Jia2d61e2b2015-05-08 15:23:28 -07001553 // initialize PlaybackParams field info
1554 gPlaybackParamsFields.init(env);
Andy Hungfe48e0d2015-04-27 18:14:02 -07001555
Andy Hung035d4ec2017-01-24 13:45:02 -08001556 gVolumeShaperFields.init(env);
Andy Hung59dffec2020-01-14 17:29:03 -08001557
1558 // optional check that the TunerConfiguration class and fields exist.
1559 TunerConfigurationHelper::initCheckOrDie(env);
1560
Glenn Kasten931fde42016-01-07 15:59:38 -08001561 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562}
1563
1564
1565// ----------------------------------------------------------------------------