blob: 11011b1d7c16441e437907ed4f39bcad2d7e34d5 [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>
23#include <nativehelper/JniConstants.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
Steven Moreland2279b252017-07-19 09:50:45 -070026#include <nativehelper/ScopedBytes.h>
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -080027
Glenn Kastenc81d31c2012-03-13 14:46:23 -070028#include <utils/Log.h>
29#include <media/AudioSystem.h>
30#include <media/AudioTrack.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031
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
Glenn Kastenfe834d32014-01-08 14:49:08 -080035#include "android_media_AudioFormat.h"
Eric Laurentbc11a692014-05-16 12:19:25 -070036#include "android_media_AudioErrors.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"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
Ben Wagner85ea32b2016-03-16 17:10:42 -040041#include <cinttypes>
42
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043// ----------------------------------------------------------------------------
44
45using namespace android;
46
Ivan Lozano330d8762017-08-08 12:51:06 -070047using ::android::media::VolumeShaper;
48
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049// ----------------------------------------------------------------------------
50static const char* const kClassPathName = "android/media/AudioTrack";
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070051static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
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 -070060struct audio_attributes_fields_t {
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070061 jfieldID fieldUsage; // AudioAttributes.mUsage
62 jfieldID fieldContentType; // AudioAttributes.mContentType
63 jfieldID fieldFlags; // AudioAttributes.mFlags
64 jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070065};
66static audio_track_fields_t javaAudioTrackFields;
67static audio_attributes_fields_t javaAudioAttrFields;
Wei Jia2d61e2b2015-05-08 15:23:28 -070068static PlaybackParams::fields_t gPlaybackParamsFields;
Andy Hung035d4ec2017-01-24 13:45:02 -080069static VolumeShaperHelper::fields_t gVolumeShaperFields;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
71struct audiotrack_callback_cookie {
72 jclass audioTrack_class;
73 jobject audioTrack_ref;
Eric Laurent532bc1c2012-04-20 12:45:03 -070074 bool busy;
75 Condition cond;
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -080076 bool isOffload;
Eric Laurent532bc1c2012-04-20 12:45:03 -070077};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
Glenn Kasten3d301cb2012-01-16 14:46:54 -080079// keep these values in sync with AudioTrack.java
80#define MODE_STATIC 0
81#define MODE_STREAM 1
82
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083// ----------------------------------------------------------------------------
84class AudioTrackJniStorage {
85 public:
86 sp<MemoryHeapBase> mMemHeap;
87 sp<MemoryBase> mMemBase;
88 audiotrack_callback_cookie mCallbackData;
Eric Laurent4bcdba82015-05-01 11:37:49 -070089 sp<JNIDeviceCallback> mDeviceCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
91 AudioTrackJniStorage() {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -070092 mCallbackData.audioTrack_class = 0;
93 mCallbackData.audioTrack_ref = 0;
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -080094 mCallbackData.isOffload = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 }
96
97 ~AudioTrackJniStorage() {
98 mMemBase.clear();
99 mMemHeap.clear();
100 }
101
102 bool allocSharedMem(int sizeInBytes) {
103 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
104 if (mMemHeap->getHeapID() < 0) {
105 return false;
106 }
107 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
108 return true;
109 }
110};
111
Eric Laurent532bc1c2012-04-20 12:45:03 -0700112static Mutex sLock;
113static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115// ----------------------------------------------------------------------------
116#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
117
Chih-Hung Hsieh0ca16ef2016-05-19 15:14:54 -0700118#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM (-16)
119#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK (-17)
120#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT (-18)
121#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE (-19)
122#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED (-20)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124// ----------------------------------------------------------------------------
Glenn Kastene46a86f2011-06-01 15:20:35 -0700125static void audioCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700126
127 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
128 {
129 Mutex::Autolock l(sLock);
130 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
131 return;
132 }
133 callbackInfo->busy = true;
134 }
135
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700136 switch (event) {
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800137 // Offload only events
138 case AudioTrack::EVENT_STREAM_END:
139 case AudioTrack::EVENT_MORE_DATA:
140 // a.k.a. tear down
141 case AudioTrack::EVENT_NEW_IAUDIOTRACK:
142 if (callbackInfo->isOffload) {
143 JNIEnv *env = AndroidRuntime::getJNIEnv();
144 if (user != NULL && env != NULL) {
145 env->CallStaticVoidMethod(
146 callbackInfo->audioTrack_class,
147 javaAudioTrackFields.postNativeEventInJava,
148 callbackInfo->audioTrack_ref, event, 0,0, NULL);
149 if (env->ExceptionCheck()) {
150 env->ExceptionDescribe();
151 env->ExceptionClear();
152 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700154 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800156 // PCM and offload events
157 case AudioTrack::EVENT_MARKER:
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700158 case AudioTrack::EVENT_NEW_POS: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700160 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 env->CallStaticVoidMethod(
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800162 callbackInfo->audioTrack_class,
163 javaAudioTrackFields.postNativeEventInJava,
164 callbackInfo->audioTrack_ref, event, 0,0, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 if (env->ExceptionCheck()) {
166 env->ExceptionDescribe();
167 env->ExceptionClear();
168 }
169 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700170 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700172
Eric Laurent532bc1c2012-04-20 12:45:03 -0700173 {
174 Mutex::Autolock l(sLock);
175 callbackInfo->busy = false;
176 callbackInfo->cond.broadcast();
177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178}
179
180
181// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700182static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
183{
184 Mutex::Autolock l(sLock);
185 AudioTrack* const at =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000186 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700187 return sp<AudioTrack>(at);
188}
189
190static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
191{
192 Mutex::Autolock l(sLock);
193 sp<AudioTrack> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000194 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700195 if (at.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800196 at->incStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700197 }
198 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800199 old->decStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700200 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000201 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700202 return old;
203}
Wei Jia071a8b72015-03-09 16:38:25 -0700204
205// ----------------------------------------------------------------------------
206sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
207 return getAudioTrack(env, audioTrackObj);
208}
209
Eric Laurent532bc1c2012-04-20 12:45:03 -0700210// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000211static jint
Paul McLean9b09e532016-01-26 14:43:35 -0700212android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, jobject jaa,
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800213 jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
Paul McLean9b09e532016-01-26 14:43:35 -0700214 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession,
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800215 jlong nativeAudioTrack, jboolean offload) {
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700216
Paul McLean9b09e532016-01-26 14:43:35 -0700217 ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d"
Ben Wagner85ea32b2016-03-16 17:10:42 -0400218 "nativeAudioTrack=0x%" PRIX64,
Paul McLean9b09e532016-01-26 14:43:35 -0700219 jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
220 nativeAudioTrack);
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800221
Paul McLean9b09e532016-01-26 14:43:35 -0700222 sp<AudioTrack> lpTrack = 0;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700223
224 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000225 ALOGE("Error creating AudioTrack: invalid session ID pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700226 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent619346f2010-06-21 09:27:30 -0700227 }
228
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700229 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
230 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000231 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700232 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700233 }
Glenn Kasten33b84042016-03-08 12:02:55 -0800234 audio_session_t sessionId = (audio_session_t) nSession[0];
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700235 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
236 nSession = NULL;
237
Paul McLean9b09e532016-01-26 14:43:35 -0700238 AudioTrackJniStorage* lpJniStorage = NULL;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700239
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700240 audio_attributes_t *paa = NULL;
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700241
Paul McLean9b09e532016-01-26 14:43:35 -0700242 jclass clazz = env->GetObjectClass(thiz);
243 if (clazz == NULL) {
244 ALOGE("Can't find %s when setting up callback.", kClassPathName);
245 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
246 }
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700247
Paul McLean9b09e532016-01-26 14:43:35 -0700248 // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
249 if (nativeAudioTrack == 0) {
250 if (jaa == 0) {
251 ALOGE("Error creating AudioTrack: invalid audio attributes");
252 return (jint) AUDIO_JAVA_ERROR;
253 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700254
Paul McLean9b09e532016-01-26 14:43:35 -0700255 if (jSampleRate == 0) {
256 ALOGE("Error creating AudioTrack: invalid sample rates");
257 return (jint) AUDIO_JAVA_ERROR;
258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
Paul McLean9b09e532016-01-26 14:43:35 -0700260 int* sampleRates = env->GetIntArrayElements(jSampleRate, NULL);
261 int sampleRateInHertz = sampleRates[0];
262 env->ReleaseIntArrayElements(jSampleRate, sampleRates, JNI_ABORT);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700263
Paul McLean9b09e532016-01-26 14:43:35 -0700264 // Invalid channel representations are caught by !audio_is_output_channel() below.
265 audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
266 channelPositionMask, channelIndexMask);
267 if (!audio_is_output_channel(nativeChannelMask)) {
268 ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
269 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
270 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700271
Paul McLean9b09e532016-01-26 14:43:35 -0700272 uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
273
274 // check the format.
275 // This function was called from Java, so we compare the format against the Java constants
276 audio_format_t format = audioFormatToNative(audioFormat);
277 if (format == AUDIO_FORMAT_INVALID) {
278 ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
279 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
280 }
281
282 // compute the frame count
283 size_t frameCount;
284 if (audio_is_linear_pcm(format)) {
285 const size_t bytesPerSample = audio_bytes_per_sample(format);
286 frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
287 } else {
288 frameCount = buffSizeInBytes;
289 }
290
291 // create the native AudioTrack object
292 lpTrack = new AudioTrack();
293
294 // read the AudioAttributes values
295 paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
296 const jstring jtags =
297 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
298 const char* tags = env->GetStringUTFChars(jtags, NULL);
299 // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
300 strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
301 env->ReleaseStringUTFChars(jtags, tags);
302 paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
303 paa->content_type =
304 (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
305 paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
306
307 ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
308 paa->usage, paa->content_type, paa->flags, paa->tags);
309
310 // initialize the callback information:
311 // this data will be passed with every AudioTrack callback
312 lpJniStorage = new AudioTrackJniStorage();
313 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
314 // we use a weak reference so the AudioTrack object can be garbage collected.
315 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800316 lpJniStorage->mCallbackData.isOffload = offload;
Paul McLean9b09e532016-01-26 14:43:35 -0700317 lpJniStorage->mCallbackData.busy = false;
318
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800319 audio_offload_info_t offloadInfo;
320 if (offload) {
321 offloadInfo = AUDIO_INFO_INITIALIZER;
322 offloadInfo.format = format;
323 offloadInfo.sample_rate = sampleRateInHertz;
324 offloadInfo.channel_mask = nativeChannelMask;
325 offloadInfo.has_video = false;
326 offloadInfo.stream_type = AUDIO_STREAM_MUSIC; //required for offload
327 }
328
Paul McLean9b09e532016-01-26 14:43:35 -0700329 // initialize the native AudioTrack object
330 status_t status = NO_ERROR;
331 switch (memoryMode) {
332 case MODE_STREAM:
333
334 status = lpTrack->set(
335 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
336 sampleRateInHertz,
337 format,// word length, PCM
338 nativeChannelMask,
339 frameCount,
340 AUDIO_OUTPUT_FLAG_NONE,
341 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
342 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
343 0,// shared mem
344 true,// thread can call Java
345 sessionId,// audio session ID
346 AudioTrack::TRANSFER_SYNC,
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -0800347 offload ? &offloadInfo : NULL,
Paul McLean9b09e532016-01-26 14:43:35 -0700348 -1, -1, // default uid, pid values
349 paa);
350 break;
351
352 case MODE_STATIC:
353 // AudioTrack is using shared memory
354
355 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
356 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
357 goto native_init_failure;
358 }
359
360 status = lpTrack->set(
361 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
362 sampleRateInHertz,
363 format,// word length, PCM
364 nativeChannelMask,
365 frameCount,
366 AUDIO_OUTPUT_FLAG_NONE,
367 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
368 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
369 lpJniStorage->mMemBase,// shared mem
370 true,// thread can call Java
371 sessionId,// audio session ID
372 AudioTrack::TRANSFER_SHARED,
373 NULL, // default offloadInfo
374 -1, -1, // default uid, pid values
375 paa);
376 break;
377
378 default:
379 ALOGE("Unknown mode %d", memoryMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 goto native_init_failure;
381 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700382
Paul McLean9b09e532016-01-26 14:43:35 -0700383 if (status != NO_ERROR) {
384 ALOGE("Error %d initializing AudioTrack", status);
385 goto native_init_failure;
386 }
387 } else { // end if (nativeAudioTrack == 0)
388 lpTrack = (AudioTrack*)nativeAudioTrack;
389 // TODO: We need to find out which members of the Java AudioTrack might
390 // need to be initialized from the Native AudioTrack
391 // these are directly returned from getters:
392 // mSampleRate
393 // mAudioFormat
394 // mStreamType
395 // mChannelConfiguration
396 // mChannelCount
397 // mState (?)
398 // mPlayState (?)
399 // these may be used internally (Java AudioTrack.audioParamCheck():
400 // mChannelMask
401 // mChannelIndexMask
402 // mDataLoadMode
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800403
Paul McLean9b09e532016-01-26 14:43:35 -0700404 // initialize the callback information:
405 // this data will be passed with every AudioTrack callback
406 lpJniStorage = new AudioTrackJniStorage();
407 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
408 // we use a weak reference so the AudioTrack object can be garbage collected.
409 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
410 lpJniStorage->mCallbackData.busy = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 }
412
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700413 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
414 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000415 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700416 goto native_init_failure;
417 }
Eric Laurent619346f2010-06-21 09:27:30 -0700418 // read the audio session ID back from AudioTrack in case we create a new session
419 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700420 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
421 nSession = NULL;
422
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800423 {
424 const jint elements[1] = { (jint) lpTrack->getSampleRate() };
425 env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
426 }
427
Eric Laurent532bc1c2012-04-20 12:45:03 -0700428 { // scope for the lock
429 Mutex::Autolock l(sLock);
430 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
431 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700432 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 // of the Java object (in mNativeTrackInJavaObj)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700434 setAudioTrack(env, thiz, lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 // save the JNI resources so we can free them later
Ashok Bhat075e9a12014-01-06 13:45:09 +0000437 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
438 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700440 // since we had audio attributes, the stream type was derived from them during the
441 // creation of the native AudioTrack: push the same value to the Java object
442 env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
Paul McLean9b09e532016-01-26 14:43:35 -0700443 if (paa != NULL) {
444 // audio attributes were copied in AudioTrack creation
445 free(paa);
446 paa = NULL;
447 }
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700448
449
Eric Laurentbc11a692014-05-16 12:19:25 -0700450 return (jint) AUDIO_JAVA_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 // failures:
453native_init_failure:
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700454 if (paa != NULL) {
455 free(paa);
456 }
Eric Laurent619346f2010-06-21 09:27:30 -0700457 if (nSession != NULL) {
458 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
459 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700460 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
461 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 delete lpJniStorage;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000463 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700464
Glenn Kasten14d226a2015-05-18 13:53:39 -0700465 // lpTrack goes out of scope, so reference count drops to zero
Ashok Bhat075e9a12014-01-06 13:45:09 +0000466 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467}
468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469// ----------------------------------------------------------------------------
470static void
471android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
472{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700473 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
474 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 jniThrowException(env, "java/lang/IllegalStateException",
476 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700477 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 lpTrack->start();
481}
482
483
484// ----------------------------------------------------------------------------
485static void
486android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
487{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700488 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
489 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 jniThrowException(env, "java/lang/IllegalStateException",
491 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700492 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 }
494
495 lpTrack->stop();
496}
497
498
499// ----------------------------------------------------------------------------
500static void
501android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
502{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700503 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
504 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 jniThrowException(env, "java/lang/IllegalStateException",
506 "Unable to retrieve AudioTrack pointer for pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700507 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 }
509
510 lpTrack->pause();
511}
512
513
514// ----------------------------------------------------------------------------
515static void
516android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
517{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700518 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
519 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 jniThrowException(env, "java/lang/IllegalStateException",
521 "Unable to retrieve AudioTrack pointer for flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700522 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 }
524
525 lpTrack->flush();
526}
527
528// ----------------------------------------------------------------------------
529static void
530android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
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 setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700536 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 }
538
539 lpTrack->setVolume(leftVol, rightVol);
540}
541
542// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700543
Eric Laurent532bc1c2012-04-20 12:45:03 -0700544#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800545static void android_media_AudioTrack_release(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700546 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
547 if (lpTrack == NULL) {
548 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700550 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 // delete the JNI data
Ashok Bhat075e9a12014-01-06 13:45:09 +0000553 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 thiz, javaAudioTrackFields.jniData);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700555 // reset the native resources in the Java object so any attempt to access
556 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000557 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 if (pJniStorage) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700560 Mutex::Autolock l(sLock);
561 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
Steve Block71f2cf12011-10-20 11:56:00 +0100562 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700563 while (lpCookie->busy) {
564 if (lpCookie->cond.waitRelative(sLock,
565 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
566 NO_ERROR) {
567 break;
568 }
569 }
570 sAudioTrackCallBackCookies.remove(lpCookie);
571 // delete global refs created in native_setup
572 env->DeleteGlobalRef(lpCookie->audioTrack_class);
573 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 delete pJniStorage;
575 }
576}
577
Glenn Kasten18db49a2012-03-12 16:29:55 -0700578
Eric Laurent532bc1c2012-04-20 12:45:03 -0700579// ----------------------------------------------------------------------------
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800580static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
581 //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
582 android_media_AudioTrack_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583}
584
Andy Hung4aacc902015-04-14 15:01:29 -0700585// overloaded JNI array helper functions (same as in android_media_AudioRecord)
586static inline
587jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
588 return env->GetByteArrayElements(array, isCopy);
589}
590
591static inline
592void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
593 env->ReleaseByteArrayElements(array, elems, mode);
594}
595
596static inline
597jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
598 return env->GetShortArrayElements(array, isCopy);
599}
600
601static inline
602void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
603 env->ReleaseShortArrayElements(array, elems, mode);
604}
605
606static inline
607jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
608 return env->GetFloatArrayElements(array, isCopy);
609}
610
611static inline
612void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
613 env->ReleaseFloatArrayElements(array, elems, mode);
614}
615
Eric Laurent219de732016-05-23 12:41:50 -0700616static inline
617jint interpretWriteSizeError(ssize_t writeSize) {
618 if (writeSize == WOULD_BLOCK) {
619 return (jint)0;
620 } else if (writeSize == NO_INIT) {
621 return AUDIO_JAVA_DEAD_OBJECT;
622 } else {
623 ALOGE("Error %zd during AudioTrack native read", writeSize);
624 return nativeToJavaStatus(writeSize);
625 }
626}
627
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700629template <typename T>
630static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
631 jint offsetInSamples, jint sizeInSamples, bool blocking) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700632 // give the data to the native AudioTrack object (the data starts at the offset)
633 ssize_t written = 0;
634 // regular write() or copy the data to the AudioTrack's shared memory?
Andy Hung4aacc902015-04-14 15:01:29 -0700635 size_t sizeInBytes = sizeInSamples * sizeof(T);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700636 if (track->sharedBuffer() == 0) {
Andy Hung4aacc902015-04-14 15:01:29 -0700637 written = track->write(data + offsetInSamples, sizeInBytes, blocking);
Glenn Kasten9b53db32013-07-10 14:13:39 -0700638 // for compatibility with earlier behavior of write(), return 0 in this case
639 if (written == (ssize_t) WOULD_BLOCK) {
640 written = 0;
641 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700642 } else {
Andy Hung2c0e17c2015-01-12 15:07:14 -0800643 // writing to shared memory, check for capacity
644 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
645 sizeInBytes = track->sharedBuffer()->size();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700646 }
Andy Hung4aacc902015-04-14 15:01:29 -0700647 memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
Andy Hung2c0e17c2015-01-12 15:07:14 -0800648 written = sizeInBytes;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700649 }
Eric Laurent219de732016-05-23 12:41:50 -0700650 if (written >= 0) {
Andy Hung4aacc902015-04-14 15:01:29 -0700651 return written / sizeof(T);
652 }
Eric Laurent219de732016-05-23 12:41:50 -0700653 return interpretWriteSizeError(written);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700654}
655
656// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700657template <typename T>
658static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
659 T javaAudioData,
660 jint offsetInSamples, jint sizeInSamples,
661 jint javaAudioFormat,
662 jboolean isWriteBlocking) {
663 //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
664 // offsetInSamples, sizeInSamples);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700665 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 if (lpTrack == NULL) {
667 jniThrowException(env, "java/lang/IllegalStateException",
668 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700669 return (jint)AUDIO_JAVA_INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 }
671
Andy Hung4aacc902015-04-14 15:01:29 -0700672 if (javaAudioData == NULL) {
673 ALOGE("NULL java array of audio data to play");
674 return (jint)AUDIO_JAVA_BAD_VALUE;
675 }
676
Eric Laurent421ddc02011-03-07 14:52:59 -0800677 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
678 // a way that it becomes much more efficient. When doing so, we will have to prevent the
679 // AudioSystem callback to be called while in critical section (in case of media server
680 // process crash for instance)
Andy Hung4aacc902015-04-14 15:01:29 -0700681
682 // get the pointer for the audio data from the java array
683 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
684 if (cAudioData == NULL) {
685 ALOGE("Error retrieving source of audio data to play");
686 return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 }
688
Andy Hung4aacc902015-04-14 15:01:29 -0700689 jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
690 offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691
Andy Hung4aacc902015-04-14 15:01:29 -0700692 envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693
Andy Hung4aacc902015-04-14 15:01:29 -0700694 //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
695 // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
696 return samplesWritten;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697}
698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699// ----------------------------------------------------------------------------
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800700static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -0700701 jbyteArray javaBytes, jint byteOffset, jint sizeInBytes,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800702 jint javaAudioFormat, jboolean isWriteBlocking) {
703 //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
704 // offsetInBytes, sizeInBytes);
705 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
706 if (lpTrack == NULL) {
707 jniThrowException(env, "java/lang/IllegalStateException",
708 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700709 return (jint)AUDIO_JAVA_INVALID_OPERATION;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800710 }
711
712 ScopedBytesRO bytes(env, javaBytes);
713 if (bytes.get() == NULL) {
714 ALOGE("Error retrieving source of audio data to play, can't play");
Eric Laurentbc11a692014-05-16 12:19:25 -0700715 return (jint)AUDIO_JAVA_BAD_VALUE;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800716 }
717
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -0700718 jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800719 sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
720
721 return written;
722}
723
724// ----------------------------------------------------------------------------
Phil Burk10a33e42016-01-08 12:40:41 -0800725static jint android_media_AudioTrack_get_buffer_size_frames(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700726 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
727 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 jniThrowException(env, "java/lang/IllegalStateException",
Phil Burk10a33e42016-01-08 12:40:41 -0800729 "Unable to retrieve AudioTrack pointer for getBufferSizeInFrames()");
730 return (jint)AUDIO_JAVA_ERROR;
731 }
732
733 ssize_t result = lpTrack->getBufferSizeInFrames();
734 if (result < 0) {
Ben Wagner85ea32b2016-03-16 17:10:42 -0400735 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
736 "Internal error detected in getBufferSizeInFrames() = %zd", result);
Phil Burk10a33e42016-01-08 12:40:41 -0800737 return (jint)AUDIO_JAVA_ERROR;
738 }
739 return (jint)result;
740}
741
742// ----------------------------------------------------------------------------
743static jint android_media_AudioTrack_set_buffer_size_frames(JNIEnv *env,
744 jobject thiz, jint bufferSizeInFrames) {
745 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
746 if (lpTrack == NULL) {
747 jniThrowException(env, "java/lang/IllegalStateException",
748 "Unable to retrieve AudioTrack pointer for setBufferSizeInFrames()");
749 return (jint)AUDIO_JAVA_ERROR;
750 }
751 // Value will be coerced into the valid range.
752 // But internal values are unsigned, size_t, so we need to clip
753 // against zero here where it is signed.
754 if (bufferSizeInFrames < 0) {
755 bufferSizeInFrames = 0;
756 }
757 ssize_t result = lpTrack->setBufferSizeInFrames(bufferSizeInFrames);
758 if (result < 0) {
Ben Wagner85ea32b2016-03-16 17:10:42 -0400759 jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
760 "Internal error detected in setBufferSizeInFrames() = %zd", result);
Phil Burk10a33e42016-01-08 12:40:41 -0800761 return (jint)AUDIO_JAVA_ERROR;
762 }
763 return (jint)result;
764}
765
766// ----------------------------------------------------------------------------
767static jint android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv *env, jobject thiz) {
768 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
769 if (lpTrack == NULL) {
770 jniThrowException(env, "java/lang/IllegalStateException",
771 "Unable to retrieve AudioTrack pointer for getBufferCapacityInFrames()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700772 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700774
775 return lpTrack->frameCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776}
777
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700779static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 jint sampleRateInHz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700781 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
782 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 jniThrowException(env, "java/lang/IllegalStateException",
784 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700785 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700787 return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788}
789
790
791// ----------------------------------------------------------------------------
792static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700793 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
794 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 jniThrowException(env, "java/lang/IllegalStateException",
796 "Unable to retrieve AudioTrack pointer for getSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700797 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700799 return (jint) lpTrack->getSampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800}
801
802
803// ----------------------------------------------------------------------------
Wei Jia2d61e2b2015-05-08 15:23:28 -0700804static void android_media_AudioTrack_set_playback_params(JNIEnv *env, jobject thiz,
805 jobject params) {
Andy Hung263b4c92015-04-16 11:16:29 -0700806 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
807 if (lpTrack == NULL) {
808 jniThrowException(env, "java/lang/IllegalStateException",
809 "AudioTrack not initialized");
810 return;
811 }
812
Andy Hung973b8852015-05-13 15:15:25 -0700813 PlaybackParams pbp;
814 pbp.fillFromJobject(env, gPlaybackParamsFields, params);
Andy Hungfe48e0d2015-04-27 18:14:02 -0700815
Wei Jia2d61e2b2015-05-08 15:23:28 -0700816 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
Andy Hung973b8852015-05-13 15:15:25 -0700817 pbp.speedSet, pbp.audioRate.mSpeed,
818 pbp.pitchSet, pbp.audioRate.mPitch,
819 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
820 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
Andy Hungfe48e0d2015-04-27 18:14:02 -0700821
Andy Hung973b8852015-05-13 15:15:25 -0700822 // to simulate partially set params, we do a read-modify-write.
823 // TODO: pass in the valid set mask into AudioTrack.
824 AudioPlaybackRate rate = lpTrack->getPlaybackRate();
825 bool updatedRate = false;
826 if (pbp.speedSet) {
827 rate.mSpeed = pbp.audioRate.mSpeed;
828 updatedRate = true;
829 }
830 if (pbp.pitchSet) {
831 rate.mPitch = pbp.audioRate.mPitch;
832 updatedRate = true;
833 }
834 if (pbp.audioFallbackModeSet) {
835 rate.mFallbackMode = pbp.audioRate.mFallbackMode;
836 updatedRate = true;
837 }
838 if (pbp.audioStretchModeSet) {
839 rate.mStretchMode = pbp.audioRate.mStretchMode;
840 updatedRate = true;
841 }
842 if (updatedRate) {
843 if (lpTrack->setPlaybackRate(rate) != OK) {
844 jniThrowException(env, "java/lang/IllegalArgumentException",
845 "arguments out of range");
846 }
Andy Hung263b4c92015-04-16 11:16:29 -0700847 }
848}
849
850
851// ----------------------------------------------------------------------------
Wei Jia2d61e2b2015-05-08 15:23:28 -0700852static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env, jobject thiz,
853 jobject params) {
Andy Hung263b4c92015-04-16 11:16:29 -0700854 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
855 if (lpTrack == NULL) {
856 jniThrowException(env, "java/lang/IllegalStateException",
857 "AudioTrack not initialized");
Andy Hungfe48e0d2015-04-27 18:14:02 -0700858 return NULL;
Andy Hung263b4c92015-04-16 11:16:29 -0700859 }
860
Wei Jia2d61e2b2015-05-08 15:23:28 -0700861 PlaybackParams pbs;
Andy Hungfe48e0d2015-04-27 18:14:02 -0700862 pbs.audioRate = lpTrack->getPlaybackRate();
863 pbs.speedSet = true;
864 pbs.pitchSet = true;
865 pbs.audioFallbackModeSet = true;
866 pbs.audioStretchModeSet = true;
Wei Jia2d61e2b2015-05-08 15:23:28 -0700867 return pbs.asJobject(env, gPlaybackParamsFields);
Andy Hung263b4c92015-04-16 11:16:29 -0700868}
869
870
871// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700872static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 jint markerPos) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700874 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
875 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 jniThrowException(env, "java/lang/IllegalStateException",
877 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700878 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700880 return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881}
882
883
884// ----------------------------------------------------------------------------
885static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700886 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700888
Eric Laurent532bc1c2012-04-20 12:45:03 -0700889 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 jniThrowException(env, "java/lang/IllegalStateException",
891 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700892 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700894 lpTrack->getMarkerPosition(&markerPos);
895 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896}
897
898
899// ----------------------------------------------------------------------------
900static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
901 jint period) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700902 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
903 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 jniThrowException(env, "java/lang/IllegalStateException",
905 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700906 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700907 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700908 return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909}
910
911
912// ----------------------------------------------------------------------------
913static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700914 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700916
Eric Laurent532bc1c2012-04-20 12:45:03 -0700917 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 jniThrowException(env, "java/lang/IllegalStateException",
919 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700920 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700922 lpTrack->getPositionUpdatePeriod(&period);
923 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924}
925
926
927// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700928static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800929 jint position) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700930 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
931 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 jniThrowException(env, "java/lang/IllegalStateException",
933 "Unable to retrieve AudioTrack pointer for setPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700934 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700936 return nativeToJavaStatus( lpTrack->setPosition(position) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937}
938
939
940// ----------------------------------------------------------------------------
941static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700942 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 uint32_t position = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700944
Eric Laurent532bc1c2012-04-20 12:45:03 -0700945 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 jniThrowException(env, "java/lang/IllegalStateException",
947 "Unable to retrieve AudioTrack pointer for getPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700948 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700950 lpTrack->getPosition(&position);
951 return (jint)position;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952}
953
954
955// ----------------------------------------------------------------------------
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100956static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
957 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
958
959 if (lpTrack == NULL) {
960 jniThrowException(env, "java/lang/IllegalStateException",
961 "Unable to retrieve AudioTrack pointer for latency()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700962 return (jint)AUDIO_JAVA_ERROR;
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100963 }
964 return (jint)lpTrack->latency();
965}
966
Phil Burk03f61bb2016-01-17 21:49:58 +0000967// ----------------------------------------------------------------------------
968static jint android_media_AudioTrack_get_underrun_count(JNIEnv *env, jobject thiz) {
969 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
970
971 if (lpTrack == NULL) {
972 jniThrowException(env, "java/lang/IllegalStateException",
973 "Unable to retrieve AudioTrack pointer for getUnderrunCount()");
974 return (jint)AUDIO_JAVA_ERROR;
975 }
976 return (jint)lpTrack->getUnderrunCount();
977}
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100978
979// ----------------------------------------------------------------------------
Andy Hungebc2c142017-01-12 19:20:29 -0800980static jint android_media_AudioTrack_get_flags(JNIEnv *env, jobject thiz) {
981 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
982
983 if (lpTrack == NULL) {
984 jniThrowException(env, "java/lang/IllegalStateException",
985 "Unable to retrieve AudioTrack pointer for getFlags()");
986 return (jint)AUDIO_JAVA_ERROR;
987 }
988 return (jint)lpTrack->getFlags();
989}
990
991// ----------------------------------------------------------------------------
Glenn Kasten948c2e62013-09-04 13:51:29 -0700992static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
993 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
994
995 if (lpTrack == NULL) {
996 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700997 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -0700998 }
999 AudioTimestamp timestamp;
1000 status_t status = lpTrack->getTimestamp(timestamp);
1001 if (status == OK) {
1002 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
1003 if (nTimestamp == NULL) {
1004 ALOGE("Unable to get array for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001005 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -07001006 }
1007 nTimestamp[0] = (jlong) timestamp.mPosition;
1008 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
1009 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
1010 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001011 return (jint) nativeToJavaStatus(status);
Glenn Kasten948c2e62013-09-04 13:51:29 -07001012}
1013
1014
1015// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
1017 jint loopStart, jint loopEnd, jint loopCount) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001018 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1019 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 jniThrowException(env, "java/lang/IllegalStateException",
1021 "Unable to retrieve AudioTrack pointer for setLoop()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001022 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001024 return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025}
1026
1027
1028// ----------------------------------------------------------------------------
1029static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001030 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1031 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 jniThrowException(env, "java/lang/IllegalStateException",
1033 "Unable to retrieve AudioTrack pointer for reload()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001034 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001036 return nativeToJavaStatus( lpTrack->reload() );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037}
1038
1039
1040// ----------------------------------------------------------------------------
1041static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
1042 jint javaStreamType) {
Glenn Kasten85fbc872012-11-14 13:21:09 -08001043 uint32_t afSamplingRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 // convert the stream type from Java to native value
Jean-Michel Trivieac84382014-02-04 14:50:40 -08001045 // FIXME: code duplication with android_media_AudioTrack_setup()
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001046 audio_stream_type_t nativeStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -08001047 switch (javaStreamType) {
1048 case AUDIO_STREAM_VOICE_CALL:
1049 case AUDIO_STREAM_SYSTEM:
1050 case AUDIO_STREAM_RING:
1051 case AUDIO_STREAM_MUSIC:
1052 case AUDIO_STREAM_ALARM:
1053 case AUDIO_STREAM_NOTIFICATION:
1054 case AUDIO_STREAM_BLUETOOTH_SCO:
1055 case AUDIO_STREAM_DTMF:
1056 nativeStreamType = (audio_stream_type_t) javaStreamType;
1057 break;
1058 default:
Dima Zavin24fc2fb2011-04-19 22:30:36 -07001059 nativeStreamType = AUDIO_STREAM_DEFAULT;
Glenn Kasten29a09092012-01-16 14:37:12 -08001060 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 }
1062
Glenn Kasten8f81d082012-11-28 14:37:48 -08001063 status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
1064 if (status != NO_ERROR) {
1065 ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
1066 "in AudioTrack JNI", status, nativeStreamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 return DEFAULT_OUTPUT_SAMPLE_RATE;
1068 } else {
1069 return afSamplingRate;
1070 }
1071}
1072
1073
1074// ----------------------------------------------------------------------------
1075// returns the minimum required size for the successful creation of a streaming AudioTrack
1076// returns -1 if there was an error querying the hardware.
1077static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
Glenn Kasten5b8fd442013-11-14 09:44:14 -08001078 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +08001079
Glenn Kasten659a9712014-01-08 11:38:33 -08001080 size_t frameCount;
1081 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
1082 sampleRateInHertz);
1083 if (status != NO_ERROR) {
1084 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
1085 sampleRateInHertz, status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 return -1;
1087 }
Glenn Kastenfe834d32014-01-08 14:49:08 -08001088 const audio_format_t format = audioFormatToNative(audioFormat);
Phil Burk43f4b272016-01-27 15:35:20 -08001089 if (audio_has_proportional_frames(format)) {
Eric Laurentff0d9f02014-06-09 17:23:02 -07001090 const size_t bytesPerSample = audio_bytes_per_sample(format);
1091 return frameCount * channelCount * bytesPerSample;
1092 } else {
1093 return frameCount;
1094 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095}
1096
Eric Laurent7070b362010-07-16 07:43:46 -07001097// ----------------------------------------------------------------------------
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001098static jint
Eric Laurent7070b362010-07-16 07:43:46 -07001099android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
1100{
Eric Laurent532bc1c2012-04-20 12:45:03 -07001101 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Eric Laurent7070b362010-07-16 07:43:46 -07001102 if (lpTrack == NULL ) {
1103 jniThrowException(env, "java/lang/IllegalStateException",
1104 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001105 return -1;
Eric Laurent7070b362010-07-16 07:43:46 -07001106 }
1107
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001108 status_t status = lpTrack->setAuxEffectSendLevel(level);
1109 if (status != NO_ERROR) {
1110 ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
1111 level, status);
1112 }
1113 return (jint) status;
Eric Laurent7070b362010-07-16 07:43:46 -07001114}
1115
1116// ----------------------------------------------------------------------------
1117static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
1118 jint effectId) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001119 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1120 if (lpTrack == NULL) {
Eric Laurent7070b362010-07-16 07:43:46 -07001121 jniThrowException(env, "java/lang/IllegalStateException",
1122 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001123 return (jint)AUDIO_JAVA_ERROR;
Eric Laurent7070b362010-07-16 07:43:46 -07001124 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001125 return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
Eric Laurent7070b362010-07-16 07:43:46 -07001126}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127
Paul McLean88e1d862015-04-06 16:36:51 -07001128static jboolean android_media_AudioTrack_setOutputDevice(
1129 JNIEnv *env, jobject thiz, jint device_id) {
1130
1131 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Paul McLeancef696e2015-05-21 08:51:18 -07001132 if (lpTrack == 0) {
1133 return false;
1134 }
Paul McLean88e1d862015-04-06 16:36:51 -07001135 return lpTrack->setOutputDevice(device_id) == NO_ERROR;
1136}
1137
Eric Laurent4bcdba82015-05-01 11:37:49 -07001138static jint android_media_AudioTrack_getRoutedDeviceId(
1139 JNIEnv *env, jobject thiz) {
1140
1141 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1142 if (lpTrack == NULL) {
1143 return 0;
1144 }
1145 return (jint)lpTrack->getRoutedDeviceId();
1146}
1147
1148static void android_media_AudioTrack_enableDeviceCallback(
1149 JNIEnv *env, jobject thiz) {
1150
1151 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1152 if (lpTrack == NULL) {
1153 return;
1154 }
1155 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1156 thiz, javaAudioTrackFields.jniData);
1157 if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
1158 return;
1159 }
1160 pJniStorage->mDeviceCallback =
1161 new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
1162 javaAudioTrackFields.postNativeEventInJava);
1163 lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
1164}
1165
1166static void android_media_AudioTrack_disableDeviceCallback(
1167 JNIEnv *env, jobject thiz) {
1168
1169 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1170 if (lpTrack == NULL) {
1171 return;
1172 }
1173 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1174 thiz, javaAudioTrackFields.jniData);
1175 if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
1176 return;
1177 }
1178 lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
1179 pJniStorage->mDeviceCallback.clear();
1180}
1181
Glenn Kastenbd2c3d62015-12-14 12:21:03 -08001182static jint android_media_AudioTrack_get_FCC_8(JNIEnv *env, jobject thiz) {
1183 return FCC_8;
1184}
1185
Andy Hung035d4ec2017-01-24 13:45:02 -08001186// Pass through the arguments to the AudioFlinger track implementation.
1187static jint android_media_AudioTrack_apply_volume_shaper(JNIEnv *env, jobject thiz,
1188 jobject jconfig, jobject joperation) {
1189 // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
1190 const int VOLUME_SHAPER_INVALID_OPERATION = -38;
1191
1192 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1193 if (lpTrack == nullptr) {
1194 return (jint)VOLUME_SHAPER_INVALID_OPERATION;
1195 }
1196
1197 sp<VolumeShaper::Configuration> configuration;
1198 sp<VolumeShaper::Operation> operation;
1199 if (jconfig != nullptr) {
1200 configuration = VolumeShaperHelper::convertJobjectToConfiguration(
1201 env, gVolumeShaperFields, jconfig);
1202 ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
1203 }
1204 if (joperation != nullptr) {
1205 operation = VolumeShaperHelper::convertJobjectToOperation(
1206 env, gVolumeShaperFields, joperation);
1207 ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
1208 }
1209 VolumeShaper::Status status = lpTrack->applyVolumeShaper(configuration, operation);
1210 if (status == INVALID_OPERATION) {
1211 status = VOLUME_SHAPER_INVALID_OPERATION;
1212 }
1213 return (jint)status; // if status < 0 an error, else a VolumeShaper id
1214}
1215
1216// Pass through the arguments to the AudioFlinger track implementation.
1217static jobject android_media_AudioTrack_get_volume_shaper_state(JNIEnv *env, jobject thiz,
1218 jint id) {
1219 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1220 if (lpTrack == nullptr) {
1221 return (jobject)nullptr;
1222 }
1223
1224 sp<VolumeShaper::State> state = lpTrack->getVolumeShaperState((int)id);
1225 if (state.get() == nullptr) {
1226 return (jobject)nullptr;
1227 }
1228 return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
1229}
Eric Laurent4bcdba82015-05-01 11:37:49 -07001230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231// ----------------------------------------------------------------------------
1232// ----------------------------------------------------------------------------
Daniel Micay76f6a862015-09-19 17:31:01 -04001233static const JNINativeMethod gMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 // name, signature, funcPtr
1235 {"native_start", "()V", (void *)android_media_AudioTrack_start},
1236 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
1237 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
1238 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08001239 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZ)I",
Jean-Michel Trivieac84382014-02-04 14:50:40 -08001240 (void *)android_media_AudioTrack_setup},
1241 {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
1242 {"native_release", "()V", (void *)android_media_AudioTrack_release},
Andy Hung4aacc902015-04-14 15:01:29 -07001243 {"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -08001244 {"native_write_native_bytes",
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -07001245 "(Ljava/lang/Object;IIIZ)I",
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -08001246 (void *)android_media_AudioTrack_write_native_bytes},
Andy Hung4aacc902015-04-14 15:01:29 -07001247 {"native_write_short", "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
1248 {"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
Phil Burk10a33e42016-01-08 12:40:41 -08001250 {"native_get_buffer_size_frames",
1251 "()I", (void *)android_media_AudioTrack_get_buffer_size_frames},
1252 {"native_set_buffer_size_frames",
1253 "(I)I", (void *)android_media_AudioTrack_set_buffer_size_frames},
1254 {"native_get_buffer_capacity_frames",
1255 "()I", (void *)android_media_AudioTrack_get_buffer_capacity_frames},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 {"native_set_playback_rate",
Eric Laurent88e209d2009-07-07 07:10:45 -07001257 "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 {"native_get_playback_rate",
1259 "()I", (void *)android_media_AudioTrack_get_playback_rate},
Wei Jia2d61e2b2015-05-08 15:23:28 -07001260 {"native_set_playback_params",
1261 "(Landroid/media/PlaybackParams;)V",
1262 (void *)android_media_AudioTrack_set_playback_params},
1263 {"native_get_playback_params",
1264 "()Landroid/media/PlaybackParams;",
1265 (void *)android_media_AudioTrack_get_playback_params},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
1267 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
1268 {"native_set_pos_update_period",
1269 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
1270 {"native_get_pos_update_period",
1271 "()I", (void *)android_media_AudioTrack_get_pos_update_period},
1272 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
1273 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001274 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
Phil Burk03f61bb2016-01-17 21:49:58 +00001275 {"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
Andy Hungebc2c142017-01-12 19:20:29 -08001276 {"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
Glenn Kasten948c2e62013-09-04 13:51:29 -07001277 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
1279 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
1280 {"native_get_output_sample_rate",
1281 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
1282 {"native_get_min_buff_size",
1283 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
Eric Laurent7070b362010-07-16 07:43:46 -07001284 {"native_setAuxEffectSendLevel",
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001285 "(F)I", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
Eric Laurent7070b362010-07-16 07:43:46 -07001286 {"native_attachAuxEffect",
1287 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
Paul McLean88e1d862015-04-06 16:36:51 -07001288 {"native_setOutputDevice", "(I)Z",
1289 (void *)android_media_AudioTrack_setOutputDevice},
Eric Laurent4bcdba82015-05-01 11:37:49 -07001290 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
1291 {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
1292 {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
Glenn Kasten25d3c7c2016-01-07 10:59:35 -08001293 {"native_get_FCC_8", "()I", (void *)android_media_AudioTrack_get_FCC_8},
Andy Hung035d4ec2017-01-24 13:45:02 -08001294 {"native_applyVolumeShaper",
1295 "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
1296 (void *)android_media_AudioTrack_apply_volume_shaper},
1297 {"native_getVolumeShaperState",
1298 "(I)Landroid/media/VolumeShaper$State;",
1299 (void *)android_media_AudioTrack_get_volume_shaper_state},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001300};
1301
1302
1303// field names found in android/media/AudioTrack.java
1304#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
1306#define JAVA_JNIDATA_FIELD_NAME "mJniData"
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001307#define JAVA_STREAMTYPE_FIELD_NAME "mStreamType"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309// ----------------------------------------------------------------------------
1310// preconditions:
1311// theClass is valid
1312bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1313 const char* constName, int* constVal) {
1314 jfieldID javaConst = NULL;
1315 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1316 if (javaConst != NULL) {
1317 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1318 return true;
1319 } else {
Steve Block3762c312012-01-06 19:20:56 +00001320 ALOGE("Can't find %s.%s", className, constName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 return false;
1322 }
1323}
1324
1325
1326// ----------------------------------------------------------------------------
1327int register_android_media_AudioTrack(JNIEnv *env)
1328{
Glenn Kasten931fde42016-01-07 15:59:38 -08001329 // must be first
1330 int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1333 javaAudioTrackFields.postNativeEventInJava = NULL;
1334
1335 // Get the AudioTrack class
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001336 jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337
1338 // Get the postEvent method
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001339 javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1340 audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1341 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342
1343 // Get the variables fields
1344 // nativeTrackInJavaObj
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001345 javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1346 audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001347 // jniData
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001348 javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1349 audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001350 // fieldStreamType
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001351 javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1352 audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001353
Andy Hungfe48e0d2015-04-27 18:14:02 -07001354 env->DeleteLocalRef(audioTrackClass);
1355
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001356 // Get the AudioAttributes class and fields
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001357 jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
1358 javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
1359 javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
1360 audioAttrClass, "mContentType", "I");
1361 javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
1362 javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
1363 audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364
Andy Hungfe48e0d2015-04-27 18:14:02 -07001365 env->DeleteLocalRef(audioAttrClass);
1366
Wei Jia2d61e2b2015-05-08 15:23:28 -07001367 // initialize PlaybackParams field info
1368 gPlaybackParamsFields.init(env);
Andy Hungfe48e0d2015-04-27 18:14:02 -07001369
Andy Hung035d4ec2017-01-24 13:45:02 -08001370 gVolumeShaperFields.init(env);
Glenn Kasten931fde42016-01-07 15:59:38 -08001371 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372}
1373
1374
1375// ----------------------------------------------------------------------------