blob: 1bf42e92e45cfd2e73a58c93a008ffdebf914756 [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
Glenn Kastenc81d31c2012-03-13 14:46:23 -070020#include <jni.h>
21#include <JNIHelp.h>
22#include <android_runtime/AndroidRuntime.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023
Glenn Kastenc81d31c2012-03-13 14:46:23 -070024#include <utils/Log.h>
25#include <media/AudioSystem.h>
26#include <media/AudioTrack.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027
Mathias Agopian07952722009-05-19 19:08:10 -070028#include <binder/MemoryHeapBase.h>
29#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
Dima Zavin34bb4192011-05-11 14:15:23 -070031#include <system/audio.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
33// ----------------------------------------------------------------------------
34
35using namespace android;
36
37// ----------------------------------------------------------------------------
38static const char* const kClassPathName = "android/media/AudioTrack";
39
40struct fields_t {
41 // these fields provide access from C++ to the...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042 jmethodID postNativeEventInJava; //... event post callback method
Eric Laurent83b36852009-07-28 07:49:22 -070043 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
45};
46static fields_t javaAudioTrackFields;
47
48struct audiotrack_callback_cookie {
49 jclass audioTrack_class;
50 jobject audioTrack_ref;
Eric Laurent532bc1c2012-04-20 12:45:03 -070051 bool busy;
52 Condition cond;
53};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054
Glenn Kasten3d301cb2012-01-16 14:46:54 -080055// keep these values in sync with AudioTrack.java
56#define MODE_STATIC 0
57#define MODE_STREAM 1
Glenn Kasten9d2bc862012-01-16 14:38:37 -080058// keep these values in sync with AudioFormat.java
59#define ENCODING_PCM_16BIT 2
60#define ENCODING_PCM_8BIT 3
Glenn Kasten3d301cb2012-01-16 14:46:54 -080061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062// ----------------------------------------------------------------------------
63class AudioTrackJniStorage {
64 public:
65 sp<MemoryHeapBase> mMemHeap;
66 sp<MemoryBase> mMemBase;
67 audiotrack_callback_cookie mCallbackData;
Glenn Kastenbc1d77b2012-01-12 16:38:12 -080068 audio_stream_type_t mStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
70 AudioTrackJniStorage() {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -070071 mCallbackData.audioTrack_class = 0;
72 mCallbackData.audioTrack_ref = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -070073 mStreamType = AUDIO_STREAM_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 }
75
76 ~AudioTrackJniStorage() {
77 mMemBase.clear();
78 mMemHeap.clear();
79 }
80
81 bool allocSharedMem(int sizeInBytes) {
82 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
83 if (mMemHeap->getHeapID() < 0) {
84 return false;
85 }
86 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
87 return true;
88 }
89};
90
Eric Laurent532bc1c2012-04-20 12:45:03 -070091static Mutex sLock;
92static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
93
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094// ----------------------------------------------------------------------------
95#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
96
97#define AUDIOTRACK_SUCCESS 0
98#define AUDIOTRACK_ERROR -1
99#define AUDIOTRACK_ERROR_BAD_VALUE -2
100#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
101#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800102#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
104#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
105#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
106
107
108jint android_media_translateErrorCode(int code) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700109 switch (code) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 case NO_ERROR:
111 return AUDIOTRACK_SUCCESS;
112 case BAD_VALUE:
113 return AUDIOTRACK_ERROR_BAD_VALUE;
114 case INVALID_OPERATION:
115 return AUDIOTRACK_ERROR_INVALID_OPERATION;
116 default:
117 return AUDIOTRACK_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119}
120
121
122// ----------------------------------------------------------------------------
Glenn Kastene46a86f2011-06-01 15:20:35 -0700123static void audioCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700124
125 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
126 {
127 Mutex::Autolock l(sLock);
128 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
129 return;
130 }
131 callbackInfo->busy = true;
132 }
133
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700134 switch (event) {
135 case AudioTrack::EVENT_MARKER: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700137 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700139 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 javaAudioTrackFields.postNativeEventInJava,
141 callbackInfo->audioTrack_ref, event, 0,0, NULL);
142 if (env->ExceptionCheck()) {
143 env->ExceptionDescribe();
144 env->ExceptionClear();
145 }
146 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700147 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700149 case AudioTrack::EVENT_NEW_POS: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700151 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700153 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 javaAudioTrackFields.postNativeEventInJava,
155 callbackInfo->audioTrack_ref, event, 0,0, NULL);
156 if (env->ExceptionCheck()) {
157 env->ExceptionDescribe();
158 env->ExceptionClear();
159 }
160 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700161 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700163
Eric Laurent532bc1c2012-04-20 12:45:03 -0700164 {
165 Mutex::Autolock l(sLock);
166 callbackInfo->busy = false;
167 callbackInfo->cond.broadcast();
168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169}
170
171
172// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700173static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
174{
175 Mutex::Autolock l(sLock);
176 AudioTrack* const at =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000177 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700178 return sp<AudioTrack>(at);
179}
180
181static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
182{
183 Mutex::Autolock l(sLock);
184 sp<AudioTrack> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000185 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700186 if (at.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800187 at->incStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700188 }
189 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800190 old->decStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700191 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000192 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700193 return old;
194}
195
196// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000197static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700199 jint streamType, jint sampleRateInHertz, jint javaChannelMask,
Eric Laurent619346f2010-06-21 09:27:30 -0700200 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201{
Steve Block71f2cf12011-10-20 11:56:00 +0100202 ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700203 sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);
Glenn Kasten85fbc872012-11-14 13:21:09 -0800204 uint32_t afSampleRate;
Glenn Kastenfd1e3df2012-11-13 15:21:06 -0800205 size_t afFrameCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800207 if (AudioSystem::getOutputFrameCount(&afFrameCount, (audio_stream_type_t) streamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000208 ALOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000209 return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 }
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800211 if (AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000212 ALOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000213 return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 }
215
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700216 // Java channel masks don't map directly to the native definition, but it's a simple shift
217 // to skip the two deprecated channel configurations "default" and "mono".
218 uint32_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
219
220 if (!audio_is_output_channel(nativeChannelMask)) {
Glenn Kasten33c437d2013-07-18 17:04:21 -0700221 ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000222 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 }
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700224
225 int nbChannels = popcount(nativeChannelMask);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 // check the stream type
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700228 audio_stream_type_t atStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -0800229 switch (streamType) {
230 case AUDIO_STREAM_VOICE_CALL:
231 case AUDIO_STREAM_SYSTEM:
232 case AUDIO_STREAM_RING:
233 case AUDIO_STREAM_MUSIC:
234 case AUDIO_STREAM_ALARM:
235 case AUDIO_STREAM_NOTIFICATION:
236 case AUDIO_STREAM_BLUETOOTH_SCO:
237 case AUDIO_STREAM_DTMF:
238 atStreamType = (audio_stream_type_t) streamType;
239 break;
240 default:
Steve Block3762c312012-01-06 19:20:56 +0000241 ALOGE("Error creating AudioTrack: unknown stream type.");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000242 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 }
244
245 // check the format.
246 // This function was called from Java, so we compare the format against the Java constants
Glenn Kasten9d2bc862012-01-16 14:38:37 -0800247 if ((audioFormat != ENCODING_PCM_16BIT) && (audioFormat != ENCODING_PCM_8BIT)) {
248
Steve Block3762c312012-01-06 19:20:56 +0000249 ALOGE("Error creating AudioTrack: unsupported audio format.");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000250 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 }
252
253 // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class
254 // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled
Glenn Kasten00db1f52012-01-16 14:41:30 -0800255 // in android_media_AudioTrack_native_write_byte()
Glenn Kasten9d2bc862012-01-16 14:38:37 -0800256 if ((audioFormat == ENCODING_PCM_8BIT)
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800257 && (memoryMode == MODE_STATIC)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100258 ALOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 buff size of %dbytes, switching to 16bit, buff size of %dbytes",
260 buffSizeInBytes, 2*buffSizeInBytes);
Glenn Kasten9d2bc862012-01-16 14:38:37 -0800261 audioFormat = ENCODING_PCM_16BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 // we will need twice the memory to store the data
263 buffSizeInBytes *= 2;
264 }
265
266 // compute the frame count
Glenn Kasten9d2bc862012-01-16 14:38:37 -0800267 int bytesPerSample = audioFormat == ENCODING_PCM_16BIT ? 2 : 1;
268 audio_format_t format = audioFormat == ENCODING_PCM_16BIT ?
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700269 AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT;
Eric Laurenta553c252009-07-17 12:17:14 -0700270 int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 jclass clazz = env->GetObjectClass(thiz);
273 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000274 ALOGE("Can't find %s when setting up callback.", kClassPathName);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000275 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 }
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700277
278 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000279 ALOGE("Error creating AudioTrack: invalid session ID pointer");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000280 return (jint) AUDIOTRACK_ERROR;
Eric Laurent619346f2010-06-21 09:27:30 -0700281 }
282
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700283 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
284 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000285 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000286 return (jint) AUDIOTRACK_ERROR;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700287 }
288 int sessionId = nSession[0];
289 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
290 nSession = NULL;
291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 // create the native AudioTrack object
Eric Laurent532bc1c2012-04-20 12:45:03 -0700293 sp<AudioTrack> lpTrack = new AudioTrack();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700294
Eric Laurent532bc1c2012-04-20 12:45:03 -0700295 // initialize the callback information:
296 // this data will be passed with every AudioTrack callback
297 AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
298 lpJniStorage->mStreamType = atStreamType;
299 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
300 // we use a weak reference so the AudioTrack object can be garbage collected.
301 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
302 lpJniStorage->mCallbackData.busy = false;
303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 // initialize the native AudioTrack object
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800305 switch (memoryMode) {
306 case MODE_STREAM:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307
308 lpTrack->set(
309 atStreamType,// stream type
310 sampleRateInHertz,
311 format,// word length, PCM
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700312 nativeChannelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 frameCount,
Eric Laurent10536b62012-04-18 09:27:14 -0700314 AUDIO_OUTPUT_FLAG_NONE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
316 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
317 0,// shared mem
Eric Laurent619346f2010-06-21 09:27:30 -0700318 true,// thread can call Java
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700319 sessionId);// audio session ID
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800320 break;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700321
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800322 case MODE_STATIC:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 // AudioTrack is using shared memory
Glenn Kasten18db49a2012-03-12 16:29:55 -0700324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
Steve Block3762c312012-01-06 19:20:56 +0000326 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 goto native_init_failure;
328 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 lpTrack->set(
331 atStreamType,// stream type
332 sampleRateInHertz,
333 format,// word length, PCM
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700334 nativeChannelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 frameCount,
Eric Laurent10536b62012-04-18 09:27:14 -0700336 AUDIO_OUTPUT_FLAG_NONE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
Glenn Kasten18db49a2012-03-12 16:29:55 -0700338 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 lpJniStorage->mMemBase,// shared mem
Eric Laurent619346f2010-06-21 09:27:30 -0700340 true,// thread can call Java
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700341 sessionId);// audio session ID
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800342 break;
343
344 default:
345 ALOGE("Unknown mode %d", memoryMode);
346 goto native_init_failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 }
348
349 if (lpTrack->initCheck() != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000350 ALOGE("Error initializing AudioTrack");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 goto native_init_failure;
352 }
353
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700354 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
355 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000356 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700357 goto native_init_failure;
358 }
Eric Laurent619346f2010-06-21 09:27:30 -0700359 // read the audio session ID back from AudioTrack in case we create a new session
360 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700361 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
362 nSession = NULL;
363
Eric Laurent532bc1c2012-04-20 12:45:03 -0700364 { // scope for the lock
365 Mutex::Autolock l(sLock);
366 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
367 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700368 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 // of the Java object (in mNativeTrackInJavaObj)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700370 setAudioTrack(env, thiz, lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 // save the JNI resources so we can free them later
Ashok Bhat075e9a12014-01-06 13:45:09 +0000373 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
374 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375
Ashok Bhat075e9a12014-01-06 13:45:09 +0000376 return (jint) AUDIOTRACK_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 // failures:
379native_init_failure:
Eric Laurent619346f2010-06-21 09:27:30 -0700380 if (nSession != NULL) {
381 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
382 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700383 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
384 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 delete lpJniStorage;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000386 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700387
Ashok Bhat075e9a12014-01-06 13:45:09 +0000388 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389}
390
391
392// ----------------------------------------------------------------------------
393static void
394android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
395{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700396 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
397 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 jniThrowException(env, "java/lang/IllegalStateException",
399 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700400 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 lpTrack->start();
404}
405
406
407// ----------------------------------------------------------------------------
408static void
409android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
410{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700411 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
412 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 jniThrowException(env, "java/lang/IllegalStateException",
414 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700415 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 }
417
418 lpTrack->stop();
419}
420
421
422// ----------------------------------------------------------------------------
423static void
424android_media_AudioTrack_pause(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 pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700430 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 }
432
433 lpTrack->pause();
434}
435
436
437// ----------------------------------------------------------------------------
438static void
439android_media_AudioTrack_flush(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 flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700445 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 }
447
448 lpTrack->flush();
449}
450
451// ----------------------------------------------------------------------------
452static void
453android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
454{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700455 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
456 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 jniThrowException(env, "java/lang/IllegalStateException",
458 "Unable to retrieve AudioTrack pointer for setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700459 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 }
461
462 lpTrack->setVolume(leftVol, rightVol);
463}
464
465// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700466
Eric Laurent532bc1c2012-04-20 12:45:03 -0700467#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
468static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) {
469 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
470 if (lpTrack == NULL) {
471 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700473 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
474 lpTrack->stop();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 // delete the JNI data
Ashok Bhat075e9a12014-01-06 13:45:09 +0000477 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 thiz, javaAudioTrackFields.jniData);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700479 // reset the native resources in the Java object so any attempt to access
480 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000481 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 if (pJniStorage) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700484 Mutex::Autolock l(sLock);
485 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
Steve Block71f2cf12011-10-20 11:56:00 +0100486 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700487 while (lpCookie->busy) {
488 if (lpCookie->cond.waitRelative(sLock,
489 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
490 NO_ERROR) {
491 break;
492 }
493 }
494 sAudioTrackCallBackCookies.remove(lpCookie);
495 // delete global refs created in native_setup
496 env->DeleteGlobalRef(lpCookie->audioTrack_class);
497 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 delete pJniStorage;
499 }
500}
501
Glenn Kasten18db49a2012-03-12 16:29:55 -0700502
Eric Laurent532bc1c2012-04-20 12:45:03 -0700503// ----------------------------------------------------------------------------
504static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) {
505 //ALOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
506 android_media_AudioTrack_native_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507}
508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700510jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte* data,
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700511 jint offsetInBytes, jint sizeInBytes) {
512 // give the data to the native AudioTrack object (the data starts at the offset)
513 ssize_t written = 0;
514 // regular write() or copy the data to the AudioTrack's shared memory?
Eric Laurent532bc1c2012-04-20 12:45:03 -0700515 if (track->sharedBuffer() == 0) {
516 written = track->write(data + offsetInBytes, sizeInBytes);
Glenn Kasten9b53db32013-07-10 14:13:39 -0700517 // for compatibility with earlier behavior of write(), return 0 in this case
518 if (written == (ssize_t) WOULD_BLOCK) {
519 written = 0;
520 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700521 } else {
Glenn Kasten9d2bc862012-01-16 14:38:37 -0800522 if (audioFormat == ENCODING_PCM_16BIT) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700523 // writing to shared memory, check for capacity
Eric Laurent532bc1c2012-04-20 12:45:03 -0700524 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
525 sizeInBytes = track->sharedBuffer()->size();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700526 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700527 memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700528 written = sizeInBytes;
Glenn Kasten9d2bc862012-01-16 14:38:37 -0800529 } else if (audioFormat == ENCODING_PCM_8BIT) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700530 // data contains 8bit data we need to expand to 16bit before copying
531 // to the shared memory
532 // writing to shared memory, check for capacity,
533 // note that input data will occupy 2X the input space due to 8 to 16bit conversion
Eric Laurent532bc1c2012-04-20 12:45:03 -0700534 if (((size_t)sizeInBytes)*2 > track->sharedBuffer()->size()) {
535 sizeInBytes = track->sharedBuffer()->size() / 2;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700536 }
537 int count = sizeInBytes;
Eric Laurent532bc1c2012-04-20 12:45:03 -0700538 int16_t *dst = (int16_t *)track->sharedBuffer()->pointer();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700539 const int8_t *src = (const int8_t *)(data + offsetInBytes);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700540 while (count--) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700541 *dst++ = (int16_t)(*src++^0x80) << 8;
542 }
543 // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
544 // the 8bit mixer restriction from the user of this function
545 written = sizeInBytes;
546 }
547 }
548 return written;
549
550}
551
552// ----------------------------------------------------------------------------
Glenn Kasten00db1f52012-01-16 14:41:30 -0800553static jint android_media_AudioTrack_native_write_byte(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 jbyteArray javaAudioData,
555 jint offsetInBytes, jint sizeInBytes,
556 jint javaAudioFormat) {
Glenn Kasten00db1f52012-01-16 14:41:30 -0800557 //ALOGV("android_media_AudioTrack_native_write_byte(offset=%d, sizeInBytes=%d) called",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 // offsetInBytes, sizeInBytes);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700559 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 if (lpTrack == NULL) {
561 jniThrowException(env, "java/lang/IllegalStateException",
562 "Unable to retrieve AudioTrack pointer for write()");
Eric Laurent7070b362010-07-16 07:43:46 -0700563 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 }
565
566 // get the pointer for the audio data from the java array
Eric Laurent421ddc02011-03-07 14:52:59 -0800567 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
568 // a way that it becomes much more efficient. When doing so, we will have to prevent the
569 // AudioSystem callback to be called while in critical section (in case of media server
570 // process crash for instance)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700571 jbyte* cAudioData = NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 if (javaAudioData) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800573 cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 if (cAudioData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000575 ALOGE("Error retrieving source of audio data to play, can't play");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 return 0; // out of memory or no data to load
577 }
578 } else {
Steve Block3762c312012-01-06 19:20:56 +0000579 ALOGE("NULL java array of audio data to play, can't play");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 return 0;
581 }
582
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700583 jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584
Eric Laurent421ddc02011-03-07 14:52:59 -0800585 env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586
Steve Block71f2cf12011-10-20 11:56:00 +0100587 //ALOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 // (int)written, (int)(sizeInBytes), (int)offsetInBytes);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700589 return written;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590}
591
592
593// ----------------------------------------------------------------------------
594static jint android_media_AudioTrack_native_write_short(JNIEnv *env, jobject thiz,
595 jshortArray javaAudioData,
596 jint offsetInShorts, jint sizeInShorts,
597 jint javaAudioFormat) {
Eric Laurent90d0b9e2014-04-30 11:59:21 -0700598 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
599 if (lpTrack == NULL) {
600 jniThrowException(env, "java/lang/IllegalStateException",
601 "Unable to retrieve AudioTrack pointer for write()");
602 return 0;
Glenn Kastenf7e0a3702013-07-10 14:03:03 -0700603 }
Eric Laurent90d0b9e2014-04-30 11:59:21 -0700604
605 // get the pointer for the audio data from the java array
606 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
607 // a way that it becomes much more efficient. When doing so, we will have to prevent the
608 // AudioSystem callback to be called while in critical section (in case of media server
609 // process crash for instance)
610 jshort* cAudioData = NULL;
611 if (javaAudioData) {
612 cAudioData = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
613 if (cAudioData == NULL) {
614 ALOGE("Error retrieving source of audio data to play, can't play");
615 return 0; // out of memory or no data to load
616 }
617 } else {
618 ALOGE("NULL java array of audio data to play, can't play");
619 return 0;
620 }
621 jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
622 offsetInShorts * sizeof(short), sizeInShorts * sizeof(short));
623 env->ReleaseShortArrayElements(javaAudioData, cAudioData, 0);
624
625 if (written > 0) {
626 written /= sizeof(short);
627 }
628 //ALOGV("write wrote %d (tried %d) shorts in the native AudioTrack with offset %d",
629 // (int)written, (int)(sizeInShorts), (int)offsetInShorts);
630
Glenn Kastenf7e0a3702013-07-10 14:03:03 -0700631 return written;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632}
633
634
635// ----------------------------------------------------------------------------
636static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700637 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
638 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 jniThrowException(env, "java/lang/IllegalStateException",
640 "Unable to retrieve AudioTrack pointer for frameCount()");
641 return AUDIOTRACK_ERROR;
642 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700643
644 return lpTrack->frameCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645}
646
647
648// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700649static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 jint sampleRateInHz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700651 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
652 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 jniThrowException(env, "java/lang/IllegalStateException",
654 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurent88e209d2009-07-07 07:10:45 -0700655 return AUDIOTRACK_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700657 return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658}
659
660
661// ----------------------------------------------------------------------------
662static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700663 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
664 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 jniThrowException(env, "java/lang/IllegalStateException",
666 "Unable to retrieve AudioTrack pointer for getSampleRate()");
667 return AUDIOTRACK_ERROR;
668 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700669 return (jint) lpTrack->getSampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670}
671
672
673// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700674static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 jint markerPos) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700676 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
677 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 jniThrowException(env, "java/lang/IllegalStateException",
679 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
680 return AUDIOTRACK_ERROR;
681 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700682 return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683}
684
685
686// ----------------------------------------------------------------------------
687static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700688 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700690
Eric Laurent532bc1c2012-04-20 12:45:03 -0700691 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 jniThrowException(env, "java/lang/IllegalStateException",
693 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
694 return AUDIOTRACK_ERROR;
695 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700696 lpTrack->getMarkerPosition(&markerPos);
697 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698}
699
700
701// ----------------------------------------------------------------------------
702static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
703 jint period) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700704 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
705 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 jniThrowException(env, "java/lang/IllegalStateException",
707 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
708 return AUDIOTRACK_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700709 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700710 return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711}
712
713
714// ----------------------------------------------------------------------------
715static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700716 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700718
Eric Laurent532bc1c2012-04-20 12:45:03 -0700719 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 jniThrowException(env, "java/lang/IllegalStateException",
721 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
722 return AUDIOTRACK_ERROR;
723 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700724 lpTrack->getPositionUpdatePeriod(&period);
725 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726}
727
728
729// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700730static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 jint position) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700732 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
733 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 jniThrowException(env, "java/lang/IllegalStateException",
735 "Unable to retrieve AudioTrack pointer for setPosition()");
736 return AUDIOTRACK_ERROR;
737 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700738 return android_media_translateErrorCode( lpTrack->setPosition(position) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739}
740
741
742// ----------------------------------------------------------------------------
743static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700744 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 uint32_t position = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700746
Eric Laurent532bc1c2012-04-20 12:45:03 -0700747 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 jniThrowException(env, "java/lang/IllegalStateException",
749 "Unable to retrieve AudioTrack pointer for getPosition()");
750 return AUDIOTRACK_ERROR;
751 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700752 lpTrack->getPosition(&position);
753 return (jint)position;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754}
755
756
757// ----------------------------------------------------------------------------
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100758static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
759 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
760
761 if (lpTrack == NULL) {
762 jniThrowException(env, "java/lang/IllegalStateException",
763 "Unable to retrieve AudioTrack pointer for latency()");
764 return AUDIOTRACK_ERROR;
765 }
766 return (jint)lpTrack->latency();
767}
768
769
770// ----------------------------------------------------------------------------
Glenn Kasten948c2e62013-09-04 13:51:29 -0700771static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
772 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
773
774 if (lpTrack == NULL) {
775 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
776 return AUDIOTRACK_ERROR;
777 }
778 AudioTimestamp timestamp;
779 status_t status = lpTrack->getTimestamp(timestamp);
780 if (status == OK) {
781 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
782 if (nTimestamp == NULL) {
783 ALOGE("Unable to get array for getTimestamp()");
784 return AUDIOTRACK_ERROR;
785 }
786 nTimestamp[0] = (jlong) timestamp.mPosition;
787 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
788 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
789 }
790 return (jint) android_media_translateErrorCode(status);
791}
792
793
794// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
796 jint loopStart, jint loopEnd, jint loopCount) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700797 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
798 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 jniThrowException(env, "java/lang/IllegalStateException",
800 "Unable to retrieve AudioTrack pointer for setLoop()");
801 return AUDIOTRACK_ERROR;
802 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700803 return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804}
805
806
807// ----------------------------------------------------------------------------
808static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700809 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
810 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 jniThrowException(env, "java/lang/IllegalStateException",
812 "Unable to retrieve AudioTrack pointer for reload()");
813 return AUDIOTRACK_ERROR;
814 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700815 return android_media_translateErrorCode( lpTrack->reload() );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816}
817
818
819// ----------------------------------------------------------------------------
820static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
821 jint javaStreamType) {
Glenn Kasten85fbc872012-11-14 13:21:09 -0800822 uint32_t afSamplingRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 // convert the stream type from Java to native value
824 // FIXME: code duplication with android_media_AudioTrack_native_setup()
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700825 audio_stream_type_t nativeStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -0800826 switch (javaStreamType) {
827 case AUDIO_STREAM_VOICE_CALL:
828 case AUDIO_STREAM_SYSTEM:
829 case AUDIO_STREAM_RING:
830 case AUDIO_STREAM_MUSIC:
831 case AUDIO_STREAM_ALARM:
832 case AUDIO_STREAM_NOTIFICATION:
833 case AUDIO_STREAM_BLUETOOTH_SCO:
834 case AUDIO_STREAM_DTMF:
835 nativeStreamType = (audio_stream_type_t) javaStreamType;
836 break;
837 default:
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700838 nativeStreamType = AUDIO_STREAM_DEFAULT;
Glenn Kasten29a09092012-01-16 14:37:12 -0800839 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840 }
841
842 if (AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000843 ALOGE("AudioSystem::getOutputSamplingRate() for stream type %d failed in AudioTrack JNI",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 nativeStreamType);
845 return DEFAULT_OUTPUT_SAMPLE_RATE;
846 } else {
847 return afSamplingRate;
848 }
849}
850
851
852// ----------------------------------------------------------------------------
853// returns the minimum required size for the successful creation of a streaming AudioTrack
854// returns -1 if there was an error querying the hardware.
855static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
856 jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +0800857
Glenn Kastenfd1e3df2012-11-13 15:21:06 -0800858 size_t frameCount = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700859 if (AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
Chia-chi Yehc3308072010-08-19 17:14:36 +0800860 sampleRateInHertz) != NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 return -1;
862 }
Glenn Kasten9d2bc862012-01-16 14:38:37 -0800863 return frameCount * nbChannels * (audioFormat == ENCODING_PCM_16BIT ? 2 : 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864}
865
Eric Laurent7070b362010-07-16 07:43:46 -0700866// ----------------------------------------------------------------------------
867static void
868android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
869{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700870 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Eric Laurent7070b362010-07-16 07:43:46 -0700871 if (lpTrack == NULL ) {
872 jniThrowException(env, "java/lang/IllegalStateException",
873 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
874 return;
875 }
876
877 lpTrack->setAuxEffectSendLevel(level);
878}
879
880// ----------------------------------------------------------------------------
881static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
882 jint effectId) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700883 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
884 if (lpTrack == NULL) {
Eric Laurent7070b362010-07-16 07:43:46 -0700885 jniThrowException(env, "java/lang/IllegalStateException",
886 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
887 return AUDIOTRACK_ERROR;
888 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700889 return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
Eric Laurent7070b362010-07-16 07:43:46 -0700890}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891
892// ----------------------------------------------------------------------------
893// ----------------------------------------------------------------------------
894static JNINativeMethod gMethods[] = {
895 // name, signature, funcPtr
896 {"native_start", "()V", (void *)android_media_AudioTrack_start},
897 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
898 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
899 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
Eric Laurent619346f2010-06-21 09:27:30 -0700900 {"native_setup", "(Ljava/lang/Object;IIIIII[I)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 (void *)android_media_AudioTrack_native_setup},
902 {"native_finalize", "()V", (void *)android_media_AudioTrack_native_finalize},
903 {"native_release", "()V", (void *)android_media_AudioTrack_native_release},
Glenn Kasten00db1f52012-01-16 14:41:30 -0800904 {"native_write_byte", "([BIII)I", (void *)android_media_AudioTrack_native_write_byte},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 {"native_write_short", "([SIII)I", (void *)android_media_AudioTrack_native_write_short},
906 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
907 {"native_get_native_frame_count",
908 "()I", (void *)android_media_AudioTrack_get_native_frame_count},
909 {"native_set_playback_rate",
Eric Laurent88e209d2009-07-07 07:10:45 -0700910 "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 {"native_get_playback_rate",
912 "()I", (void *)android_media_AudioTrack_get_playback_rate},
913 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
914 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
915 {"native_set_pos_update_period",
916 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
917 {"native_get_pos_update_period",
918 "()I", (void *)android_media_AudioTrack_get_pos_update_period},
919 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
920 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100921 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
Glenn Kasten948c2e62013-09-04 13:51:29 -0700922 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
924 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
925 {"native_get_output_sample_rate",
926 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
927 {"native_get_min_buff_size",
928 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
Eric Laurent7070b362010-07-16 07:43:46 -0700929 {"native_setAuxEffectSendLevel",
930 "(F)V", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
931 {"native_attachAuxEffect",
932 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933};
934
935
936// field names found in android/media/AudioTrack.java
937#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
939#define JAVA_JNIDATA_FIELD_NAME "mJniData"
940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941// ----------------------------------------------------------------------------
942// preconditions:
943// theClass is valid
944bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
945 const char* constName, int* constVal) {
946 jfieldID javaConst = NULL;
947 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
948 if (javaConst != NULL) {
949 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
950 return true;
951 } else {
Steve Block3762c312012-01-06 19:20:56 +0000952 ALOGE("Can't find %s.%s", className, constName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 return false;
954 }
955}
956
957
958// ----------------------------------------------------------------------------
959int register_android_media_AudioTrack(JNIEnv *env)
960{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
962 javaAudioTrackFields.postNativeEventInJava = NULL;
963
964 // Get the AudioTrack class
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700965 jclass audioTrackClass = env->FindClass(kClassPathName);
966 if (audioTrackClass == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000967 ALOGE("Can't find %s", kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 return -1;
969 }
970
971 // Get the postEvent method
972 javaAudioTrackFields.postNativeEventInJava = env->GetStaticMethodID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700973 audioTrackClass,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
975 if (javaAudioTrackFields.postNativeEventInJava == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000976 ALOGE("Can't find AudioTrack.%s", JAVA_POSTEVENT_CALLBACK_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 return -1;
978 }
979
980 // Get the variables fields
981 // nativeTrackInJavaObj
982 javaAudioTrackFields.nativeTrackInJavaObj = env->GetFieldID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700983 audioTrackClass,
Ashok Bhat075e9a12014-01-06 13:45:09 +0000984 JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 if (javaAudioTrackFields.nativeTrackInJavaObj == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000986 ALOGE("Can't find AudioTrack.%s", JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 return -1;
988 }
989 // jniData;
990 javaAudioTrackFields.jniData = env->GetFieldID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700991 audioTrackClass,
Ashok Bhat075e9a12014-01-06 13:45:09 +0000992 JAVA_JNIDATA_FIELD_NAME, "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 if (javaAudioTrackFields.jniData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000994 ALOGE("Can't find AudioTrack.%s", JAVA_JNIDATA_FIELD_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 return -1;
996 }
997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
999}
1000
1001
1002// ----------------------------------------------------------------------------