blob: 84cc185d13e24c5bb230d08b6a4c6cd51cf5ac35 [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
Glenn Kastenc81d31c2012-03-13 14:46:23 -070022#include <JNIHelp.h>
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -080023#include <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
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -080026#include "ScopedBytes.h"
27
Glenn Kastenc81d31c2012-03-13 14:46:23 -070028#include <utils/Log.h>
29#include <media/AudioSystem.h>
30#include <media/AudioTrack.h>
Glenn Kasten37967d42012-11-28 14:37:36 -080031#include <audio_utils/primitives.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Mathias Agopian07952722009-05-19 19:08:10 -070033#include <binder/MemoryHeapBase.h>
34#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035
Glenn Kastenfe834d32014-01-08 14:49:08 -080036#include "android_media_AudioFormat.h"
Eric Laurentbc11a692014-05-16 12:19:25 -070037#include "android_media_AudioErrors.h"
Wei Jia2d61e2b2015-05-08 15:23:28 -070038#include "android_media_PlaybackParams.h"
Eric Laurent4bcdba82015-05-01 11:37:49 -070039#include "android_media_DeviceCallback.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41// ----------------------------------------------------------------------------
42
43using namespace android;
44
45// ----------------------------------------------------------------------------
46static const char* const kClassPathName = "android/media/AudioTrack";
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070047static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070049struct audio_track_fields_t {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 // these fields provide access from C++ to the...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 jmethodID postNativeEventInJava; //... event post callback method
Eric Laurent83b36852009-07-28 07:49:22 -070052 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070054 jfieldID fieldStreamType; // ... mStreamType field in the AudioTrack Java object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055};
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070056struct audio_attributes_fields_t {
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -070057 jfieldID fieldUsage; // AudioAttributes.mUsage
58 jfieldID fieldContentType; // AudioAttributes.mContentType
59 jfieldID fieldFlags; // AudioAttributes.mFlags
60 jfieldID fieldFormattedTags;// AudioAttributes.mFormattedTags
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -070061};
62static audio_track_fields_t javaAudioTrackFields;
63static audio_attributes_fields_t javaAudioAttrFields;
Wei Jia2d61e2b2015-05-08 15:23:28 -070064static PlaybackParams::fields_t gPlaybackParamsFields;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
66struct audiotrack_callback_cookie {
67 jclass audioTrack_class;
68 jobject audioTrack_ref;
Eric Laurent532bc1c2012-04-20 12:45:03 -070069 bool busy;
70 Condition cond;
71};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072
Glenn Kasten3d301cb2012-01-16 14:46:54 -080073// keep these values in sync with AudioTrack.java
74#define MODE_STATIC 0
75#define MODE_STREAM 1
76
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077// ----------------------------------------------------------------------------
78class AudioTrackJniStorage {
79 public:
80 sp<MemoryHeapBase> mMemHeap;
81 sp<MemoryBase> mMemBase;
82 audiotrack_callback_cookie mCallbackData;
Eric Laurent4bcdba82015-05-01 11:37:49 -070083 sp<JNIDeviceCallback> mDeviceCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85 AudioTrackJniStorage() {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -070086 mCallbackData.audioTrack_class = 0;
87 mCallbackData.audioTrack_ref = 0;
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
Eric Laurent532bc1c2012-04-20 12:45:03 -0700105static Mutex sLock;
106static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108// ----------------------------------------------------------------------------
109#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800112#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
114#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
115#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117// ----------------------------------------------------------------------------
Glenn Kastene46a86f2011-06-01 15:20:35 -0700118static void audioCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700119
120 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
121 {
122 Mutex::Autolock l(sLock);
123 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
124 return;
125 }
126 callbackInfo->busy = true;
127 }
128
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700129 switch (event) {
130 case AudioTrack::EVENT_MARKER: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700132 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700134 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 javaAudioTrackFields.postNativeEventInJava,
136 callbackInfo->audioTrack_ref, event, 0,0, NULL);
137 if (env->ExceptionCheck()) {
138 env->ExceptionDescribe();
139 env->ExceptionClear();
140 }
141 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700142 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700144 case AudioTrack::EVENT_NEW_POS: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700146 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700148 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 javaAudioTrackFields.postNativeEventInJava,
150 callbackInfo->audioTrack_ref, event, 0,0, NULL);
151 if (env->ExceptionCheck()) {
152 env->ExceptionDescribe();
153 env->ExceptionClear();
154 }
155 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700156 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700158
Eric Laurent532bc1c2012-04-20 12:45:03 -0700159 {
160 Mutex::Autolock l(sLock);
161 callbackInfo->busy = false;
162 callbackInfo->cond.broadcast();
163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164}
165
166
167// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700168static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
169{
170 Mutex::Autolock l(sLock);
171 AudioTrack* const at =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000172 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700173 return sp<AudioTrack>(at);
174}
175
176static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
177{
178 Mutex::Autolock l(sLock);
179 sp<AudioTrack> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000180 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700181 if (at.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800182 at->incStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700183 }
184 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800185 old->decStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700186 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000187 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700188 return old;
189}
Wei Jia071a8b72015-03-09 16:38:25 -0700190
191// ----------------------------------------------------------------------------
192sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
193 return getAudioTrack(env, audioTrackObj);
194}
195
Andy Hung30d79432015-04-23 19:28:38 -0700196// This function converts Java channel masks to a native channel mask.
197// validity should be checked with audio_is_output_channel().
198static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
199 jint channelPositionMask, jint channelIndexMask)
200{
201 if (channelIndexMask != 0) { // channel index mask takes priority
202 // To convert to a native channel mask, the Java channel index mask
203 // requires adding the index representation.
204 return audio_channel_mask_from_representation_and_bits(
205 AUDIO_CHANNEL_REPRESENTATION_INDEX,
206 channelIndexMask);
207 }
208 // To convert to a native channel mask, the Java channel position mask
209 // requires a shift by 2 to skip the two deprecated channel
210 // configurations "default" and "mono".
211 return (audio_channel_mask_t)(channelPositionMask >> 2);
212}
213
Eric Laurent532bc1c2012-04-20 12:45:03 -0700214// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000215static jint
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800216android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700217 jobject jaa,
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800218 jintArray jSampleRate, jint channelPositionMask, jint channelIndexMask,
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700219 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {
220
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800221 jint elements[1];
222 env->GetIntArrayRegion(jSampleRate, 0, 1, elements);
223 int sampleRateInHertz = elements[0];
224
Andy Hung30d79432015-04-23 19:28:38 -0700225 ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d",
226 sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700228 if (jaa == 0) {
229 ALOGE("Error creating AudioTrack: invalid audio attributes");
230 return (jint) AUDIO_JAVA_ERROR;
231 }
232
Andy Hunga9470c12015-01-29 17:16:03 -0800233 // Invalid channel representations are caught by !audio_is_output_channel() below.
Andy Hung30d79432015-04-23 19:28:38 -0700234 audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
235 channelPositionMask, channelIndexMask);
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700236 if (!audio_is_output_channel(nativeChannelMask)) {
Andy Hung30d79432015-04-23 19:28:38 -0700237 ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000238 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 }
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700240
Eric Laurentdbf55662014-07-01 18:56:30 -0700241 uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 // check the format.
244 // This function was called from Java, so we compare the format against the Java constants
Glenn Kastenfe834d32014-01-08 14:49:08 -0800245 audio_format_t format = audioFormatToNative(audioFormat);
246 if (format == AUDIO_FORMAT_INVALID) {
Glenn Kasten8f81d082012-11-28 14:37:48 -0800247 ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000248 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 }
250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 // compute the frame count
Eric Laurentff0d9f02014-06-09 17:23:02 -0700252 size_t frameCount;
Phil Burk43f4b272016-01-27 15:35:20 -0800253 if (audio_has_proportional_frames(format)) {
Eric Laurentff0d9f02014-06-09 17:23:02 -0700254 const size_t bytesPerSample = audio_bytes_per_sample(format);
255 frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
256 } else {
257 frameCount = buffSizeInBytes;
258 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 jclass clazz = env->GetObjectClass(thiz);
261 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000262 ALOGE("Can't find %s when setting up callback.", kClassPathName);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000263 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 }
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700265
266 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000267 ALOGE("Error creating AudioTrack: invalid session ID pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700268 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent619346f2010-06-21 09:27:30 -0700269 }
270
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700271 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
272 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000273 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurentbc11a692014-05-16 12:19:25 -0700274 return (jint) AUDIO_JAVA_ERROR;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700275 }
276 int sessionId = nSession[0];
277 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
278 nSession = NULL;
279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 // create the native AudioTrack object
Eric Laurent532bc1c2012-04-20 12:45:03 -0700281 sp<AudioTrack> lpTrack = new AudioTrack();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700282
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700283 audio_attributes_t *paa = NULL;
284 // read the AudioAttributes values
285 paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
Jean-Michel Trivi701d6ff2014-07-16 07:51:22 -0700286 const jstring jtags =
287 (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700288 const char* tags = env->GetStringUTFChars(jtags, NULL);
289 // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
290 strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
291 env->ReleaseStringUTFChars(jtags, tags);
292 paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
293 paa->content_type =
294 (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
295 paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
296
297 ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
298 paa->usage, paa->content_type, paa->flags, paa->tags);
299
Eric Laurent532bc1c2012-04-20 12:45:03 -0700300 // initialize the callback information:
301 // this data will be passed with every AudioTrack callback
302 AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
Eric Laurent532bc1c2012-04-20 12:45:03 -0700303 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
304 // we use a weak reference so the AudioTrack object can be garbage collected.
305 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
306 lpJniStorage->mCallbackData.busy = false;
307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 // initialize the native AudioTrack object
Jean-Michel Trivi2defed92014-05-14 18:15:59 -0700309 status_t status = NO_ERROR;
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800310 switch (memoryMode) {
311 case MODE_STREAM:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312
Glenn Kastenc5d14242014-03-28 16:19:52 -0700313 status = lpTrack->set(
Jean-Michel Trivic8d6b6f2014-07-28 09:52:14 -0700314 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700315 sampleRateInHertz,
316 format,// word length, PCM
317 nativeChannelMask,
318 frameCount,
319 AUDIO_OUTPUT_FLAG_NONE,
320 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
321 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
322 0,// shared mem
323 true,// thread can call Java
324 sessionId,// audio session ID
Jean-Michel Trivic8d6b6f2014-07-28 09:52:14 -0700325 AudioTrack::TRANSFER_SYNC,
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700326 NULL, // default offloadInfo
327 -1, -1, // default uid, pid values
328 paa);
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800329 break;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700330
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800331 case MODE_STATIC:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 // AudioTrack is using shared memory
Glenn Kasten18db49a2012-03-12 16:29:55 -0700333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
Steve Block3762c312012-01-06 19:20:56 +0000335 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 goto native_init_failure;
337 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700338
Glenn Kastenc5d14242014-03-28 16:19:52 -0700339 status = lpTrack->set(
Jean-Michel Trivic8d6b6f2014-07-28 09:52:14 -0700340 AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700341 sampleRateInHertz,
342 format,// word length, PCM
343 nativeChannelMask,
344 frameCount,
345 AUDIO_OUTPUT_FLAG_NONE,
346 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
347 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
348 lpJniStorage->mMemBase,// shared mem
349 true,// thread can call Java
350 sessionId,// audio session ID
Jean-Michel Trivic8d6b6f2014-07-28 09:52:14 -0700351 AudioTrack::TRANSFER_SHARED,
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700352 NULL, // default offloadInfo
353 -1, -1, // default uid, pid values
354 paa);
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800355 break;
356
357 default:
358 ALOGE("Unknown mode %d", memoryMode);
359 goto native_init_failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 }
361
Glenn Kastenc5d14242014-03-28 16:19:52 -0700362 if (status != NO_ERROR) {
363 ALOGE("Error %d initializing AudioTrack", status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 goto native_init_failure;
365 }
366
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700367 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
368 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000369 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700370 goto native_init_failure;
371 }
Eric Laurent619346f2010-06-21 09:27:30 -0700372 // read the audio session ID back from AudioTrack in case we create a new session
373 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700374 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
375 nSession = NULL;
376
Glenn Kasten1cbf9b32016-02-02 12:04:09 -0800377 {
378 const jint elements[1] = { (jint) lpTrack->getSampleRate() };
379 env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
380 }
381
Eric Laurent532bc1c2012-04-20 12:45:03 -0700382 { // scope for the lock
383 Mutex::Autolock l(sLock);
384 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
385 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700386 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 // of the Java object (in mNativeTrackInJavaObj)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700388 setAudioTrack(env, thiz, lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 // save the JNI resources so we can free them later
Ashok Bhat075e9a12014-01-06 13:45:09 +0000391 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
392 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700394 // since we had audio attributes, the stream type was derived from them during the
395 // creation of the native AudioTrack: push the same value to the Java object
396 env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
397 // audio attributes were copied in AudioTrack creation
398 free(paa);
399 paa = NULL;
400
401
Eric Laurentbc11a692014-05-16 12:19:25 -0700402 return (jint) AUDIO_JAVA_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 // failures:
405native_init_failure:
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -0700406 if (paa != NULL) {
407 free(paa);
408 }
Eric Laurent619346f2010-06-21 09:27:30 -0700409 if (nSession != NULL) {
410 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
411 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700412 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
413 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 delete lpJniStorage;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000415 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700416
Glenn Kasten14d226a2015-05-18 13:53:39 -0700417 // lpTrack goes out of scope, so reference count drops to zero
Ashok Bhat075e9a12014-01-06 13:45:09 +0000418 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419}
420
421
422// ----------------------------------------------------------------------------
423static void
424android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
425{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700426 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
427 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 jniThrowException(env, "java/lang/IllegalStateException",
429 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700430 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 lpTrack->start();
434}
435
436
437// ----------------------------------------------------------------------------
438static void
439android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
440{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700441 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
442 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 jniThrowException(env, "java/lang/IllegalStateException",
444 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700445 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 }
447
448 lpTrack->stop();
449}
450
451
452// ----------------------------------------------------------------------------
453static void
454android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
455{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700456 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
457 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 jniThrowException(env, "java/lang/IllegalStateException",
459 "Unable to retrieve AudioTrack pointer for pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700460 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 }
462
463 lpTrack->pause();
464}
465
466
467// ----------------------------------------------------------------------------
468static void
469android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
470{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700471 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
472 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 jniThrowException(env, "java/lang/IllegalStateException",
474 "Unable to retrieve AudioTrack pointer for flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700475 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
477
478 lpTrack->flush();
479}
480
481// ----------------------------------------------------------------------------
482static void
483android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
484{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700485 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
486 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 jniThrowException(env, "java/lang/IllegalStateException",
488 "Unable to retrieve AudioTrack pointer for setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700489 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 }
491
492 lpTrack->setVolume(leftVol, rightVol);
493}
494
495// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700496
Eric Laurent532bc1c2012-04-20 12:45:03 -0700497#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800498static void android_media_AudioTrack_release(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700499 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
500 if (lpTrack == NULL) {
501 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700503 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
504 lpTrack->stop();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 // delete the JNI data
Ashok Bhat075e9a12014-01-06 13:45:09 +0000507 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 thiz, javaAudioTrackFields.jniData);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700509 // reset the native resources in the Java object so any attempt to access
510 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000511 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 if (pJniStorage) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700514 Mutex::Autolock l(sLock);
515 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
Steve Block71f2cf12011-10-20 11:56:00 +0100516 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700517 while (lpCookie->busy) {
518 if (lpCookie->cond.waitRelative(sLock,
519 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
520 NO_ERROR) {
521 break;
522 }
523 }
524 sAudioTrackCallBackCookies.remove(lpCookie);
525 // delete global refs created in native_setup
526 env->DeleteGlobalRef(lpCookie->audioTrack_class);
527 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 delete pJniStorage;
529 }
530}
531
Glenn Kasten18db49a2012-03-12 16:29:55 -0700532
Eric Laurent532bc1c2012-04-20 12:45:03 -0700533// ----------------------------------------------------------------------------
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800534static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
535 //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
536 android_media_AudioTrack_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537}
538
Andy Hung4aacc902015-04-14 15:01:29 -0700539// overloaded JNI array helper functions (same as in android_media_AudioRecord)
540static inline
541jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
542 return env->GetByteArrayElements(array, isCopy);
543}
544
545static inline
546void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
547 env->ReleaseByteArrayElements(array, elems, mode);
548}
549
550static inline
551jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
552 return env->GetShortArrayElements(array, isCopy);
553}
554
555static inline
556void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
557 env->ReleaseShortArrayElements(array, elems, mode);
558}
559
560static inline
561jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
562 return env->GetFloatArrayElements(array, isCopy);
563}
564
565static inline
566void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
567 env->ReleaseFloatArrayElements(array, elems, mode);
568}
569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700571template <typename T>
572static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
573 jint offsetInSamples, jint sizeInSamples, bool blocking) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700574 // give the data to the native AudioTrack object (the data starts at the offset)
575 ssize_t written = 0;
576 // regular write() or copy the data to the AudioTrack's shared memory?
Andy Hung4aacc902015-04-14 15:01:29 -0700577 size_t sizeInBytes = sizeInSamples * sizeof(T);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700578 if (track->sharedBuffer() == 0) {
Andy Hung4aacc902015-04-14 15:01:29 -0700579 written = track->write(data + offsetInSamples, sizeInBytes, blocking);
Glenn Kasten9b53db32013-07-10 14:13:39 -0700580 // for compatibility with earlier behavior of write(), return 0 in this case
581 if (written == (ssize_t) WOULD_BLOCK) {
582 written = 0;
583 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700584 } else {
Andy Hung2c0e17c2015-01-12 15:07:14 -0800585 // writing to shared memory, check for capacity
586 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
587 sizeInBytes = track->sharedBuffer()->size();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700588 }
Andy Hung4aacc902015-04-14 15:01:29 -0700589 memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
Andy Hung2c0e17c2015-01-12 15:07:14 -0800590 written = sizeInBytes;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700591 }
Andy Hung4aacc902015-04-14 15:01:29 -0700592 if (written > 0) {
593 return written / sizeof(T);
594 }
595 // for compatibility, error codes pass through unchanged
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700596 return written;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700597}
598
599// ----------------------------------------------------------------------------
Andy Hung4aacc902015-04-14 15:01:29 -0700600template <typename T>
601static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
602 T javaAudioData,
603 jint offsetInSamples, jint sizeInSamples,
604 jint javaAudioFormat,
605 jboolean isWriteBlocking) {
606 //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
607 // offsetInSamples, sizeInSamples);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700608 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 if (lpTrack == NULL) {
610 jniThrowException(env, "java/lang/IllegalStateException",
611 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700612 return (jint)AUDIO_JAVA_INVALID_OPERATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 }
614
Andy Hung4aacc902015-04-14 15:01:29 -0700615 if (javaAudioData == NULL) {
616 ALOGE("NULL java array of audio data to play");
617 return (jint)AUDIO_JAVA_BAD_VALUE;
618 }
619
Eric Laurent421ddc02011-03-07 14:52:59 -0800620 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
621 // a way that it becomes much more efficient. When doing so, we will have to prevent the
622 // AudioSystem callback to be called while in critical section (in case of media server
623 // process crash for instance)
Andy Hung4aacc902015-04-14 15:01:29 -0700624
625 // get the pointer for the audio data from the java array
626 auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
627 if (cAudioData == NULL) {
628 ALOGE("Error retrieving source of audio data to play");
629 return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 }
631
Andy Hung4aacc902015-04-14 15:01:29 -0700632 jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
633 offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634
Andy Hung4aacc902015-04-14 15:01:29 -0700635 envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636
Andy Hung4aacc902015-04-14 15:01:29 -0700637 //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
638 // (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
639 return samplesWritten;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640}
641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642// ----------------------------------------------------------------------------
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800643static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -0700644 jbyteArray javaBytes, jint byteOffset, jint sizeInBytes,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800645 jint javaAudioFormat, jboolean isWriteBlocking) {
646 //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
647 // offsetInBytes, sizeInBytes);
648 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
649 if (lpTrack == NULL) {
650 jniThrowException(env, "java/lang/IllegalStateException",
651 "Unable to retrieve AudioTrack pointer for write()");
Andy Hung4aacc902015-04-14 15:01:29 -0700652 return (jint)AUDIO_JAVA_INVALID_OPERATION;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800653 }
654
655 ScopedBytesRO bytes(env, javaBytes);
656 if (bytes.get() == NULL) {
657 ALOGE("Error retrieving source of audio data to play, can't play");
Eric Laurentbc11a692014-05-16 12:19:25 -0700658 return (jint)AUDIO_JAVA_BAD_VALUE;
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800659 }
660
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -0700661 jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -0800662 sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
663
664 return written;
665}
666
667// ----------------------------------------------------------------------------
Phil Burk10a33e42016-01-08 12:40:41 -0800668static jint android_media_AudioTrack_get_buffer_size_frames(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700669 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
670 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 jniThrowException(env, "java/lang/IllegalStateException",
Phil Burk10a33e42016-01-08 12:40:41 -0800672 "Unable to retrieve AudioTrack pointer for getBufferSizeInFrames()");
673 return (jint)AUDIO_JAVA_ERROR;
674 }
675
676 ssize_t result = lpTrack->getBufferSizeInFrames();
677 if (result < 0) {
678 jniThrowException(env, "java/lang/IllegalStateException",
679 "Internal error detected in getBufferSizeInFrames() = " + result);
680 return (jint)AUDIO_JAVA_ERROR;
681 }
682 return (jint)result;
683}
684
685// ----------------------------------------------------------------------------
686static jint android_media_AudioTrack_set_buffer_size_frames(JNIEnv *env,
687 jobject thiz, jint bufferSizeInFrames) {
688 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
689 if (lpTrack == NULL) {
690 jniThrowException(env, "java/lang/IllegalStateException",
691 "Unable to retrieve AudioTrack pointer for setBufferSizeInFrames()");
692 return (jint)AUDIO_JAVA_ERROR;
693 }
694 // Value will be coerced into the valid range.
695 // But internal values are unsigned, size_t, so we need to clip
696 // against zero here where it is signed.
697 if (bufferSizeInFrames < 0) {
698 bufferSizeInFrames = 0;
699 }
700 ssize_t result = lpTrack->setBufferSizeInFrames(bufferSizeInFrames);
701 if (result < 0) {
702 jniThrowException(env, "java/lang/IllegalStateException",
703 "Internal error detected in setBufferSizeInFrames() = " + result);
704 return (jint)AUDIO_JAVA_ERROR;
705 }
706 return (jint)result;
707}
708
709// ----------------------------------------------------------------------------
710static jint android_media_AudioTrack_get_buffer_capacity_frames(JNIEnv *env, jobject thiz) {
711 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
712 if (lpTrack == NULL) {
713 jniThrowException(env, "java/lang/IllegalStateException",
714 "Unable to retrieve AudioTrack pointer for getBufferCapacityInFrames()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700715 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700717
718 return lpTrack->frameCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719}
720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700722static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 jint sampleRateInHz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700724 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
725 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 jniThrowException(env, "java/lang/IllegalStateException",
727 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700728 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700730 return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731}
732
733
734// ----------------------------------------------------------------------------
735static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700736 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
737 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 jniThrowException(env, "java/lang/IllegalStateException",
739 "Unable to retrieve AudioTrack pointer for getSampleRate()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700740 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700742 return (jint) lpTrack->getSampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743}
744
745
746// ----------------------------------------------------------------------------
Wei Jia2d61e2b2015-05-08 15:23:28 -0700747static void android_media_AudioTrack_set_playback_params(JNIEnv *env, jobject thiz,
748 jobject params) {
Andy Hung263b4c92015-04-16 11:16:29 -0700749 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
750 if (lpTrack == NULL) {
751 jniThrowException(env, "java/lang/IllegalStateException",
752 "AudioTrack not initialized");
753 return;
754 }
755
Andy Hung973b8852015-05-13 15:15:25 -0700756 PlaybackParams pbp;
757 pbp.fillFromJobject(env, gPlaybackParamsFields, params);
Andy Hungfe48e0d2015-04-27 18:14:02 -0700758
Wei Jia2d61e2b2015-05-08 15:23:28 -0700759 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
Andy Hung973b8852015-05-13 15:15:25 -0700760 pbp.speedSet, pbp.audioRate.mSpeed,
761 pbp.pitchSet, pbp.audioRate.mPitch,
762 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
763 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
Andy Hungfe48e0d2015-04-27 18:14:02 -0700764
Andy Hung973b8852015-05-13 15:15:25 -0700765 // to simulate partially set params, we do a read-modify-write.
766 // TODO: pass in the valid set mask into AudioTrack.
767 AudioPlaybackRate rate = lpTrack->getPlaybackRate();
768 bool updatedRate = false;
769 if (pbp.speedSet) {
770 rate.mSpeed = pbp.audioRate.mSpeed;
771 updatedRate = true;
772 }
773 if (pbp.pitchSet) {
774 rate.mPitch = pbp.audioRate.mPitch;
775 updatedRate = true;
776 }
777 if (pbp.audioFallbackModeSet) {
778 rate.mFallbackMode = pbp.audioRate.mFallbackMode;
779 updatedRate = true;
780 }
781 if (pbp.audioStretchModeSet) {
782 rate.mStretchMode = pbp.audioRate.mStretchMode;
783 updatedRate = true;
784 }
785 if (updatedRate) {
786 if (lpTrack->setPlaybackRate(rate) != OK) {
787 jniThrowException(env, "java/lang/IllegalArgumentException",
788 "arguments out of range");
789 }
Andy Hung263b4c92015-04-16 11:16:29 -0700790 }
791}
792
793
794// ----------------------------------------------------------------------------
Wei Jia2d61e2b2015-05-08 15:23:28 -0700795static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env, jobject thiz,
796 jobject params) {
Andy Hung263b4c92015-04-16 11:16:29 -0700797 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
798 if (lpTrack == NULL) {
799 jniThrowException(env, "java/lang/IllegalStateException",
800 "AudioTrack not initialized");
Andy Hungfe48e0d2015-04-27 18:14:02 -0700801 return NULL;
Andy Hung263b4c92015-04-16 11:16:29 -0700802 }
803
Wei Jia2d61e2b2015-05-08 15:23:28 -0700804 PlaybackParams pbs;
Andy Hungfe48e0d2015-04-27 18:14:02 -0700805 pbs.audioRate = lpTrack->getPlaybackRate();
806 pbs.speedSet = true;
807 pbs.pitchSet = true;
808 pbs.audioFallbackModeSet = true;
809 pbs.audioStretchModeSet = true;
Wei Jia2d61e2b2015-05-08 15:23:28 -0700810 return pbs.asJobject(env, gPlaybackParamsFields);
Andy Hung263b4c92015-04-16 11:16:29 -0700811}
812
813
814// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700815static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 jint markerPos) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700817 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
818 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 jniThrowException(env, "java/lang/IllegalStateException",
820 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700821 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700823 return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824}
825
826
827// ----------------------------------------------------------------------------
828static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700829 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700831
Eric Laurent532bc1c2012-04-20 12:45:03 -0700832 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 jniThrowException(env, "java/lang/IllegalStateException",
834 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700835 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700837 lpTrack->getMarkerPosition(&markerPos);
838 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839}
840
841
842// ----------------------------------------------------------------------------
843static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
844 jint period) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700845 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
846 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 jniThrowException(env, "java/lang/IllegalStateException",
848 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700849 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700850 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700851 return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852}
853
854
855// ----------------------------------------------------------------------------
856static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700857 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700859
Eric Laurent532bc1c2012-04-20 12:45:03 -0700860 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 jniThrowException(env, "java/lang/IllegalStateException",
862 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700863 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700865 lpTrack->getPositionUpdatePeriod(&period);
866 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867}
868
869
870// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700871static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 jint position) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700873 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
874 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 jniThrowException(env, "java/lang/IllegalStateException",
876 "Unable to retrieve AudioTrack pointer for setPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700877 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700879 return nativeToJavaStatus( lpTrack->setPosition(position) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880}
881
882
883// ----------------------------------------------------------------------------
884static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700885 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 uint32_t position = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700887
Eric Laurent532bc1c2012-04-20 12:45:03 -0700888 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 jniThrowException(env, "java/lang/IllegalStateException",
890 "Unable to retrieve AudioTrack pointer for getPosition()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700891 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700893 lpTrack->getPosition(&position);
894 return (jint)position;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895}
896
897
898// ----------------------------------------------------------------------------
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100899static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
900 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
901
902 if (lpTrack == NULL) {
903 jniThrowException(env, "java/lang/IllegalStateException",
904 "Unable to retrieve AudioTrack pointer for latency()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700905 return (jint)AUDIO_JAVA_ERROR;
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100906 }
907 return (jint)lpTrack->latency();
908}
909
Phil Burk03f61bb2016-01-17 21:49:58 +0000910// ----------------------------------------------------------------------------
911static jint android_media_AudioTrack_get_underrun_count(JNIEnv *env, jobject thiz) {
912 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
913
914 if (lpTrack == NULL) {
915 jniThrowException(env, "java/lang/IllegalStateException",
916 "Unable to retrieve AudioTrack pointer for getUnderrunCount()");
917 return (jint)AUDIO_JAVA_ERROR;
918 }
919 return (jint)lpTrack->getUnderrunCount();
920}
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100921
922// ----------------------------------------------------------------------------
Glenn Kasten948c2e62013-09-04 13:51:29 -0700923static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
924 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
925
926 if (lpTrack == NULL) {
927 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700928 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -0700929 }
930 AudioTimestamp timestamp;
931 status_t status = lpTrack->getTimestamp(timestamp);
932 if (status == OK) {
933 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
934 if (nTimestamp == NULL) {
935 ALOGE("Unable to get array for getTimestamp()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700936 return (jint)AUDIO_JAVA_ERROR;
Glenn Kasten948c2e62013-09-04 13:51:29 -0700937 }
938 nTimestamp[0] = (jlong) timestamp.mPosition;
939 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
940 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
941 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700942 return (jint) nativeToJavaStatus(status);
Glenn Kasten948c2e62013-09-04 13:51:29 -0700943}
944
945
946// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
948 jint loopStart, jint loopEnd, jint loopCount) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700949 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
950 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 jniThrowException(env, "java/lang/IllegalStateException",
952 "Unable to retrieve AudioTrack pointer for setLoop()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700953 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700955 return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956}
957
958
959// ----------------------------------------------------------------------------
960static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700961 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
962 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 jniThrowException(env, "java/lang/IllegalStateException",
964 "Unable to retrieve AudioTrack pointer for reload()");
Eric Laurentbc11a692014-05-16 12:19:25 -0700965 return (jint)AUDIO_JAVA_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 }
Eric Laurentbc11a692014-05-16 12:19:25 -0700967 return nativeToJavaStatus( lpTrack->reload() );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968}
969
970
971// ----------------------------------------------------------------------------
972static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
973 jint javaStreamType) {
Glenn Kasten85fbc872012-11-14 13:21:09 -0800974 uint32_t afSamplingRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 // convert the stream type from Java to native value
Jean-Michel Trivieac84382014-02-04 14:50:40 -0800976 // FIXME: code duplication with android_media_AudioTrack_setup()
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700977 audio_stream_type_t nativeStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -0800978 switch (javaStreamType) {
979 case AUDIO_STREAM_VOICE_CALL:
980 case AUDIO_STREAM_SYSTEM:
981 case AUDIO_STREAM_RING:
982 case AUDIO_STREAM_MUSIC:
983 case AUDIO_STREAM_ALARM:
984 case AUDIO_STREAM_NOTIFICATION:
985 case AUDIO_STREAM_BLUETOOTH_SCO:
986 case AUDIO_STREAM_DTMF:
987 nativeStreamType = (audio_stream_type_t) javaStreamType;
988 break;
989 default:
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700990 nativeStreamType = AUDIO_STREAM_DEFAULT;
Glenn Kasten29a09092012-01-16 14:37:12 -0800991 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 }
993
Glenn Kasten8f81d082012-11-28 14:37:48 -0800994 status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
995 if (status != NO_ERROR) {
996 ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
997 "in AudioTrack JNI", status, nativeStreamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 return DEFAULT_OUTPUT_SAMPLE_RATE;
999 } else {
1000 return afSamplingRate;
1001 }
1002}
1003
1004
1005// ----------------------------------------------------------------------------
1006// returns the minimum required size for the successful creation of a streaming AudioTrack
1007// returns -1 if there was an error querying the hardware.
1008static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
Glenn Kasten5b8fd442013-11-14 09:44:14 -08001009 jint sampleRateInHertz, jint channelCount, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +08001010
Glenn Kasten659a9712014-01-08 11:38:33 -08001011 size_t frameCount;
1012 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
1013 sampleRateInHertz);
1014 if (status != NO_ERROR) {
1015 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
1016 sampleRateInHertz, status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 return -1;
1018 }
Glenn Kastenfe834d32014-01-08 14:49:08 -08001019 const audio_format_t format = audioFormatToNative(audioFormat);
Phil Burk43f4b272016-01-27 15:35:20 -08001020 if (audio_has_proportional_frames(format)) {
Eric Laurentff0d9f02014-06-09 17:23:02 -07001021 const size_t bytesPerSample = audio_bytes_per_sample(format);
1022 return frameCount * channelCount * bytesPerSample;
1023 } else {
1024 return frameCount;
1025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026}
1027
Eric Laurent7070b362010-07-16 07:43:46 -07001028// ----------------------------------------------------------------------------
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001029static jint
Eric Laurent7070b362010-07-16 07:43:46 -07001030android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
1031{
Eric Laurent532bc1c2012-04-20 12:45:03 -07001032 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Eric Laurent7070b362010-07-16 07:43:46 -07001033 if (lpTrack == NULL ) {
1034 jniThrowException(env, "java/lang/IllegalStateException",
1035 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001036 return -1;
Eric Laurent7070b362010-07-16 07:43:46 -07001037 }
1038
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001039 status_t status = lpTrack->setAuxEffectSendLevel(level);
1040 if (status != NO_ERROR) {
1041 ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
1042 level, status);
1043 }
1044 return (jint) status;
Eric Laurent7070b362010-07-16 07:43:46 -07001045}
1046
1047// ----------------------------------------------------------------------------
1048static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
1049 jint effectId) {
Eric Laurent532bc1c2012-04-20 12:45:03 -07001050 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1051 if (lpTrack == NULL) {
Eric Laurent7070b362010-07-16 07:43:46 -07001052 jniThrowException(env, "java/lang/IllegalStateException",
1053 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
Eric Laurentbc11a692014-05-16 12:19:25 -07001054 return (jint)AUDIO_JAVA_ERROR;
Eric Laurent7070b362010-07-16 07:43:46 -07001055 }
Eric Laurentbc11a692014-05-16 12:19:25 -07001056 return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
Eric Laurent7070b362010-07-16 07:43:46 -07001057}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058
Paul McLean88e1d862015-04-06 16:36:51 -07001059static jboolean android_media_AudioTrack_setOutputDevice(
1060 JNIEnv *env, jobject thiz, jint device_id) {
1061
1062 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Paul McLeancef696e2015-05-21 08:51:18 -07001063 if (lpTrack == 0) {
1064 return false;
1065 }
Paul McLean88e1d862015-04-06 16:36:51 -07001066 return lpTrack->setOutputDevice(device_id) == NO_ERROR;
1067}
1068
Eric Laurent4bcdba82015-05-01 11:37:49 -07001069static jint android_media_AudioTrack_getRoutedDeviceId(
1070 JNIEnv *env, jobject thiz) {
1071
1072 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1073 if (lpTrack == NULL) {
1074 return 0;
1075 }
1076 return (jint)lpTrack->getRoutedDeviceId();
1077}
1078
1079static void android_media_AudioTrack_enableDeviceCallback(
1080 JNIEnv *env, jobject thiz) {
1081
1082 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1083 if (lpTrack == NULL) {
1084 return;
1085 }
1086 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1087 thiz, javaAudioTrackFields.jniData);
1088 if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
1089 return;
1090 }
1091 pJniStorage->mDeviceCallback =
1092 new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
1093 javaAudioTrackFields.postNativeEventInJava);
1094 lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
1095}
1096
1097static void android_media_AudioTrack_disableDeviceCallback(
1098 JNIEnv *env, jobject thiz) {
1099
1100 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1101 if (lpTrack == NULL) {
1102 return;
1103 }
1104 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1105 thiz, javaAudioTrackFields.jniData);
1106 if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
1107 return;
1108 }
1109 lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
1110 pJniStorage->mDeviceCallback.clear();
1111}
1112
Glenn Kastenbd2c3d62015-12-14 12:21:03 -08001113static jint android_media_AudioTrack_get_FCC_8(JNIEnv *env, jobject thiz) {
1114 return FCC_8;
1115}
1116
Eric Laurent4bcdba82015-05-01 11:37:49 -07001117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118// ----------------------------------------------------------------------------
1119// ----------------------------------------------------------------------------
Daniel Micay76f6a862015-09-19 17:31:01 -04001120static const JNINativeMethod gMethods[] = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 // name, signature, funcPtr
1122 {"native_start", "()V", (void *)android_media_AudioTrack_start},
1123 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
1124 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
1125 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08001126 {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[I)I",
Jean-Michel Trivieac84382014-02-04 14:50:40 -08001127 (void *)android_media_AudioTrack_setup},
1128 {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
1129 {"native_release", "()V", (void *)android_media_AudioTrack_release},
Andy Hung4aacc902015-04-14 15:01:29 -07001130 {"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -08001131 {"native_write_native_bytes",
Jean-Michel Trivi5d21f672014-03-20 17:02:31 -07001132 "(Ljava/lang/Object;IIIZ)I",
Jean-Michel Trivi7ca04522014-02-07 09:39:34 -08001133 (void *)android_media_AudioTrack_write_native_bytes},
Andy Hung4aacc902015-04-14 15:01:29 -07001134 {"native_write_short", "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
1135 {"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
Phil Burk10a33e42016-01-08 12:40:41 -08001137 {"native_get_buffer_size_frames",
1138 "()I", (void *)android_media_AudioTrack_get_buffer_size_frames},
1139 {"native_set_buffer_size_frames",
1140 "(I)I", (void *)android_media_AudioTrack_set_buffer_size_frames},
1141 {"native_get_buffer_capacity_frames",
1142 "()I", (void *)android_media_AudioTrack_get_buffer_capacity_frames},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 {"native_set_playback_rate",
Eric Laurent88e209d2009-07-07 07:10:45 -07001144 "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 {"native_get_playback_rate",
1146 "()I", (void *)android_media_AudioTrack_get_playback_rate},
Wei Jia2d61e2b2015-05-08 15:23:28 -07001147 {"native_set_playback_params",
1148 "(Landroid/media/PlaybackParams;)V",
1149 (void *)android_media_AudioTrack_set_playback_params},
1150 {"native_get_playback_params",
1151 "()Landroid/media/PlaybackParams;",
1152 (void *)android_media_AudioTrack_get_playback_params},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
1154 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
1155 {"native_set_pos_update_period",
1156 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
1157 {"native_get_pos_update_period",
1158 "()I", (void *)android_media_AudioTrack_get_pos_update_period},
1159 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
1160 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
Oliver Woodman61dcdf32013-06-26 12:43:36 +01001161 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
Phil Burk03f61bb2016-01-17 21:49:58 +00001162 {"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
Glenn Kasten948c2e62013-09-04 13:51:29 -07001163 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
1165 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
1166 {"native_get_output_sample_rate",
1167 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
1168 {"native_get_min_buff_size",
1169 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
Eric Laurent7070b362010-07-16 07:43:46 -07001170 {"native_setAuxEffectSendLevel",
Glenn Kasten3009f0b2014-03-28 16:02:26 -07001171 "(F)I", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
Eric Laurent7070b362010-07-16 07:43:46 -07001172 {"native_attachAuxEffect",
1173 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
Paul McLean88e1d862015-04-06 16:36:51 -07001174 {"native_setOutputDevice", "(I)Z",
1175 (void *)android_media_AudioTrack_setOutputDevice},
Eric Laurent4bcdba82015-05-01 11:37:49 -07001176 {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
1177 {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
1178 {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
Glenn Kasten25d3c7c2016-01-07 10:59:35 -08001179 {"native_get_FCC_8", "()I", (void *)android_media_AudioTrack_get_FCC_8},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180};
1181
1182
1183// field names found in android/media/AudioTrack.java
1184#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
1186#define JAVA_JNIDATA_FIELD_NAME "mJniData"
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001187#define JAVA_STREAMTYPE_FIELD_NAME "mStreamType"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189// ----------------------------------------------------------------------------
1190// preconditions:
1191// theClass is valid
1192bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1193 const char* constName, int* constVal) {
1194 jfieldID javaConst = NULL;
1195 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1196 if (javaConst != NULL) {
1197 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1198 return true;
1199 } else {
Steve Block3762c312012-01-06 19:20:56 +00001200 ALOGE("Can't find %s.%s", className, constName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 return false;
1202 }
1203}
1204
1205
1206// ----------------------------------------------------------------------------
1207int register_android_media_AudioTrack(JNIEnv *env)
1208{
Glenn Kasten931fde42016-01-07 15:59:38 -08001209 // must be first
1210 int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1213 javaAudioTrackFields.postNativeEventInJava = NULL;
1214
1215 // Get the AudioTrack class
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001216 jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217
1218 // Get the postEvent method
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001219 javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1220 audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1221 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222
1223 // Get the variables fields
1224 // nativeTrackInJavaObj
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001225 javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1226 audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001227 // jniData
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001228 javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1229 audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001230 // fieldStreamType
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001231 javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1232 audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001233
Andy Hungfe48e0d2015-04-27 18:14:02 -07001234 env->DeleteLocalRef(audioTrackClass);
1235
Jean-Michel Trivia1d80e32014-06-18 08:18:41 -07001236 // Get the AudioAttributes class and fields
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001237 jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
1238 javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
1239 javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
1240 audioAttrClass, "mContentType", "I");
1241 javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
1242 javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
1243 audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244
Andy Hungfe48e0d2015-04-27 18:14:02 -07001245 env->DeleteLocalRef(audioAttrClass);
1246
Wei Jia2d61e2b2015-05-08 15:23:28 -07001247 // initialize PlaybackParams field info
1248 gPlaybackParamsFields.init(env);
Andy Hungfe48e0d2015-04-27 18:14:02 -07001249
Glenn Kasten931fde42016-01-07 15:59:38 -08001250 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251}
1252
1253
1254// ----------------------------------------------------------------------------