blob: 27f05dfd94dd8aa9fe01e6771fac64dc3ad8983a [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
Glenn Kastenfe834d32014-01-08 14:49:08 -080031#include "android_media_AudioFormat.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
58
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059// ----------------------------------------------------------------------------
60class AudioTrackJniStorage {
61 public:
62 sp<MemoryHeapBase> mMemHeap;
63 sp<MemoryBase> mMemBase;
64 audiotrack_callback_cookie mCallbackData;
Glenn Kastenbc1d77b2012-01-12 16:38:12 -080065 audio_stream_type_t mStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066
67 AudioTrackJniStorage() {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -070068 mCallbackData.audioTrack_class = 0;
69 mCallbackData.audioTrack_ref = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -070070 mStreamType = AUDIO_STREAM_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 }
72
73 ~AudioTrackJniStorage() {
74 mMemBase.clear();
75 mMemHeap.clear();
76 }
77
78 bool allocSharedMem(int sizeInBytes) {
79 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
80 if (mMemHeap->getHeapID() < 0) {
81 return false;
82 }
83 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
84 return true;
85 }
86};
87
Eric Laurent532bc1c2012-04-20 12:45:03 -070088static Mutex sLock;
89static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
90
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091// ----------------------------------------------------------------------------
92#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
93
94#define AUDIOTRACK_SUCCESS 0
95#define AUDIOTRACK_ERROR -1
96#define AUDIOTRACK_ERROR_BAD_VALUE -2
97#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
98#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -080099#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
101#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
102#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
103
104
105jint android_media_translateErrorCode(int code) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700106 switch (code) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 case NO_ERROR:
108 return AUDIOTRACK_SUCCESS;
109 case BAD_VALUE:
110 return AUDIOTRACK_ERROR_BAD_VALUE;
111 case INVALID_OPERATION:
112 return AUDIOTRACK_ERROR_INVALID_OPERATION;
113 default:
114 return AUDIOTRACK_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116}
117
118
119// ----------------------------------------------------------------------------
Glenn Kastene46a86f2011-06-01 15:20:35 -0700120static void audioCallback(int event, void* user, void *info) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700121
122 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
123 {
124 Mutex::Autolock l(sLock);
125 if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
126 return;
127 }
128 callbackInfo->busy = true;
129 }
130
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700131 switch (event) {
132 case AudioTrack::EVENT_MARKER: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700134 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700136 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 javaAudioTrackFields.postNativeEventInJava,
138 callbackInfo->audioTrack_ref, event, 0,0, NULL);
139 if (env->ExceptionCheck()) {
140 env->ExceptionDescribe();
141 env->ExceptionClear();
142 }
143 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700144 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700146 case AudioTrack::EVENT_NEW_POS: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 JNIEnv *env = AndroidRuntime::getJNIEnv();
Glenn Kastena667ff32013-07-22 07:36:34 -0700148 if (user != NULL && env != NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700150 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 javaAudioTrackFields.postNativeEventInJava,
152 callbackInfo->audioTrack_ref, event, 0,0, NULL);
153 if (env->ExceptionCheck()) {
154 env->ExceptionDescribe();
155 env->ExceptionClear();
156 }
157 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700158 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 }
Glenn Kasten5b1576c2013-07-18 16:58:19 -0700160
Eric Laurent532bc1c2012-04-20 12:45:03 -0700161 {
162 Mutex::Autolock l(sLock);
163 callbackInfo->busy = false;
164 callbackInfo->cond.broadcast();
165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166}
167
168
169// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700170static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
171{
172 Mutex::Autolock l(sLock);
173 AudioTrack* const at =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000174 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700175 return sp<AudioTrack>(at);
176}
177
178static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
179{
180 Mutex::Autolock l(sLock);
181 sp<AudioTrack> old =
Ashok Bhat075e9a12014-01-06 13:45:09 +0000182 (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700183 if (at.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800184 at->incStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700185 }
186 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800187 old->decStrong((void*)setAudioTrack);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700188 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000189 env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
Eric Laurent532bc1c2012-04-20 12:45:03 -0700190 return old;
191}
192
193// ----------------------------------------------------------------------------
Ashok Bhat075e9a12014-01-06 13:45:09 +0000194static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700196 jint streamType, jint sampleRateInHertz, jint javaChannelMask,
Eric Laurent619346f2010-06-21 09:27:30 -0700197 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198{
Steve Block71f2cf12011-10-20 11:56:00 +0100199 ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700200 sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);
Glenn Kasten85fbc872012-11-14 13:21:09 -0800201 uint32_t afSampleRate;
Glenn Kastenfd1e3df2012-11-13 15:21:06 -0800202 size_t afFrameCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800204 if (AudioSystem::getOutputFrameCount(&afFrameCount, (audio_stream_type_t) streamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000205 ALOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000206 return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 }
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800208 if (AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000209 ALOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000210 return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 }
212
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700213 // Java channel masks don't map directly to the native definition, but it's a simple shift
214 // to skip the two deprecated channel configurations "default" and "mono".
215 uint32_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
216
217 if (!audio_is_output_channel(nativeChannelMask)) {
Glenn Kasten33c437d2013-07-18 17:04:21 -0700218 ALOGE("Error creating AudioTrack: invalid channel mask %#x.", javaChannelMask);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000219 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 }
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700221
222 int nbChannels = popcount(nativeChannelMask);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 // check the stream type
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700225 audio_stream_type_t atStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -0800226 switch (streamType) {
227 case AUDIO_STREAM_VOICE_CALL:
228 case AUDIO_STREAM_SYSTEM:
229 case AUDIO_STREAM_RING:
230 case AUDIO_STREAM_MUSIC:
231 case AUDIO_STREAM_ALARM:
232 case AUDIO_STREAM_NOTIFICATION:
233 case AUDIO_STREAM_BLUETOOTH_SCO:
234 case AUDIO_STREAM_DTMF:
235 atStreamType = (audio_stream_type_t) streamType;
236 break;
237 default:
Steve Block3762c312012-01-06 19:20:56 +0000238 ALOGE("Error creating AudioTrack: unknown stream type.");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000239 return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 }
241
242 // check the format.
243 // This function was called from Java, so we compare the format against the Java constants
Glenn Kastenfe834d32014-01-08 14:49:08 -0800244 audio_format_t format = audioFormatToNative(audioFormat);
245 if (format == AUDIO_FORMAT_INVALID) {
Glenn Kasten9d2bc862012-01-16 14:38:37 -0800246
Steve Block3762c312012-01-06 19:20:56 +0000247 ALOGE("Error creating AudioTrack: unsupported audio format.");
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
251 // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class
252 // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled
Glenn Kasten00db1f52012-01-16 14:41:30 -0800253 // in android_media_AudioTrack_native_write_byte()
Glenn Kastenfe834d32014-01-08 14:49:08 -0800254 if ((format == AUDIO_FORMAT_PCM_8_BIT)
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800255 && (memoryMode == MODE_STATIC)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100256 ALOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 buff size of %dbytes, switching to 16bit, buff size of %dbytes",
258 buffSizeInBytes, 2*buffSizeInBytes);
Glenn Kastenfe834d32014-01-08 14:49:08 -0800259 format = AUDIO_FORMAT_PCM_16_BIT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 // we will need twice the memory to store the data
261 buffSizeInBytes *= 2;
262 }
263
264 // compute the frame count
Glenn Kastenfe834d32014-01-08 14:49:08 -0800265 const size_t bytesPerSample = audio_bytes_per_sample(format);
Eric Laurenta553c252009-07-17 12:17:14 -0700266 int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 jclass clazz = env->GetObjectClass(thiz);
269 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000270 ALOGE("Can't find %s when setting up callback.", kClassPathName);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000271 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 }
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700273
274 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000275 ALOGE("Error creating AudioTrack: invalid session ID pointer");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000276 return (jint) AUDIOTRACK_ERROR;
Eric Laurent619346f2010-06-21 09:27:30 -0700277 }
278
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700279 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
280 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000281 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000282 return (jint) AUDIOTRACK_ERROR;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700283 }
284 int sessionId = nSession[0];
285 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
286 nSession = NULL;
287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 // create the native AudioTrack object
Eric Laurent532bc1c2012-04-20 12:45:03 -0700289 sp<AudioTrack> lpTrack = new AudioTrack();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700290
Eric Laurent532bc1c2012-04-20 12:45:03 -0700291 // initialize the callback information:
292 // this data will be passed with every AudioTrack callback
293 AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
294 lpJniStorage->mStreamType = atStreamType;
295 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
296 // we use a weak reference so the AudioTrack object can be garbage collected.
297 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
298 lpJniStorage->mCallbackData.busy = false;
299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 // initialize the native AudioTrack object
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800301 switch (memoryMode) {
302 case MODE_STREAM:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303
304 lpTrack->set(
305 atStreamType,// stream type
306 sampleRateInHertz,
307 format,// word length, PCM
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700308 nativeChannelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 frameCount,
Eric Laurent10536b62012-04-18 09:27:14 -0700310 AUDIO_OUTPUT_FLAG_NONE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
312 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
313 0,// shared mem
Eric Laurent619346f2010-06-21 09:27:30 -0700314 true,// thread can call Java
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700315 sessionId);// audio session ID
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800316 break;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700317
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800318 case MODE_STATIC:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 // AudioTrack is using shared memory
Glenn Kasten18db49a2012-03-12 16:29:55 -0700320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
Steve Block3762c312012-01-06 19:20:56 +0000322 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 goto native_init_failure;
324 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 lpTrack->set(
327 atStreamType,// stream type
328 sampleRateInHertz,
329 format,// word length, PCM
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700330 nativeChannelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 frameCount,
Eric Laurent10536b62012-04-18 09:27:14 -0700332 AUDIO_OUTPUT_FLAG_NONE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
Glenn Kasten18db49a2012-03-12 16:29:55 -0700334 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 lpJniStorage->mMemBase,// shared mem
Eric Laurent619346f2010-06-21 09:27:30 -0700336 true,// thread can call Java
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700337 sessionId);// audio session ID
Glenn Kasten3d301cb2012-01-16 14:46:54 -0800338 break;
339
340 default:
341 ALOGE("Unknown mode %d", memoryMode);
342 goto native_init_failure;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 }
344
345 if (lpTrack->initCheck() != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000346 ALOGE("Error initializing AudioTrack");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 goto native_init_failure;
348 }
349
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700350 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
351 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000352 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700353 goto native_init_failure;
354 }
Eric Laurent619346f2010-06-21 09:27:30 -0700355 // read the audio session ID back from AudioTrack in case we create a new session
356 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700357 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
358 nSession = NULL;
359
Eric Laurent532bc1c2012-04-20 12:45:03 -0700360 { // scope for the lock
361 Mutex::Autolock l(sLock);
362 sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
363 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700364 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 // of the Java object (in mNativeTrackInJavaObj)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700366 setAudioTrack(env, thiz, lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 // save the JNI resources so we can free them later
Ashok Bhat075e9a12014-01-06 13:45:09 +0000369 //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
370 env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371
Ashok Bhat075e9a12014-01-06 13:45:09 +0000372 return (jint) AUDIOTRACK_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 // failures:
375native_init_failure:
Eric Laurent619346f2010-06-21 09:27:30 -0700376 if (nSession != NULL) {
377 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
378 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700379 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
380 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 delete lpJniStorage;
Ashok Bhat075e9a12014-01-06 13:45:09 +0000382 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700383
Ashok Bhat075e9a12014-01-06 13:45:09 +0000384 return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385}
386
387
388// ----------------------------------------------------------------------------
389static void
390android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
391{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700392 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
393 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 jniThrowException(env, "java/lang/IllegalStateException",
395 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700396 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 lpTrack->start();
400}
401
402
403// ----------------------------------------------------------------------------
404static void
405android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
406{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700407 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
408 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 jniThrowException(env, "java/lang/IllegalStateException",
410 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700411 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 }
413
414 lpTrack->stop();
415}
416
417
418// ----------------------------------------------------------------------------
419static void
420android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
421{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700422 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
423 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 jniThrowException(env, "java/lang/IllegalStateException",
425 "Unable to retrieve AudioTrack pointer for pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700426 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 }
428
429 lpTrack->pause();
430}
431
432
433// ----------------------------------------------------------------------------
434static void
435android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
436{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700437 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
438 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 jniThrowException(env, "java/lang/IllegalStateException",
440 "Unable to retrieve AudioTrack pointer for flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700441 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 }
443
444 lpTrack->flush();
445}
446
447// ----------------------------------------------------------------------------
448static void
449android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
450{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700451 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
452 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 jniThrowException(env, "java/lang/IllegalStateException",
454 "Unable to retrieve AudioTrack pointer for setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700455 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 }
457
458 lpTrack->setVolume(leftVol, rightVol);
459}
460
461// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700462
Eric Laurent532bc1c2012-04-20 12:45:03 -0700463#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
464static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) {
465 sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
466 if (lpTrack == NULL) {
467 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700469 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
470 lpTrack->stop();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 // delete the JNI data
Ashok Bhat075e9a12014-01-06 13:45:09 +0000473 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 thiz, javaAudioTrackFields.jniData);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700475 // reset the native resources in the Java object so any attempt to access
476 // them after a call to release fails.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000477 env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 if (pJniStorage) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700480 Mutex::Autolock l(sLock);
481 audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
Steve Block71f2cf12011-10-20 11:56:00 +0100482 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700483 while (lpCookie->busy) {
484 if (lpCookie->cond.waitRelative(sLock,
485 milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
486 NO_ERROR) {
487 break;
488 }
489 }
490 sAudioTrackCallBackCookies.remove(lpCookie);
491 // delete global refs created in native_setup
492 env->DeleteGlobalRef(lpCookie->audioTrack_class);
493 env->DeleteGlobalRef(lpCookie->audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 delete pJniStorage;
495 }
496}
497
Glenn Kasten18db49a2012-03-12 16:29:55 -0700498
Eric Laurent532bc1c2012-04-20 12:45:03 -0700499// ----------------------------------------------------------------------------
500static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) {
501 //ALOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
502 android_media_AudioTrack_native_release(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503}
504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505// ----------------------------------------------------------------------------
Eric Laurent532bc1c2012-04-20 12:45:03 -0700506jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, jbyte* data,
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700507 jint offsetInBytes, jint sizeInBytes) {
508 // give the data to the native AudioTrack object (the data starts at the offset)
509 ssize_t written = 0;
510 // regular write() or copy the data to the AudioTrack's shared memory?
Eric Laurent532bc1c2012-04-20 12:45:03 -0700511 if (track->sharedBuffer() == 0) {
512 written = track->write(data + offsetInBytes, sizeInBytes);
Glenn Kasten9b53db32013-07-10 14:13:39 -0700513 // for compatibility with earlier behavior of write(), return 0 in this case
514 if (written == (ssize_t) WOULD_BLOCK) {
515 written = 0;
516 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700517 } else {
Glenn Kastenfe834d32014-01-08 14:49:08 -0800518 const audio_format_t format = audioFormatToNative(audioFormat);
519 switch (format) {
520
521 default:
522 // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT
523 // and AUDIO_FORMAT_PCM_8_BIT, due to the limited set of values for audioFormat.
524 // The next section of the switch will probably work for more formats, but it has only
525 // been tested for AUDIO_FORMAT_PCM_16_BIT, so that's why the "default" case fails.
526 break;
527
528 case AUDIO_FORMAT_PCM_16_BIT: {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700529 // writing to shared memory, check for capacity
Eric Laurent532bc1c2012-04-20 12:45:03 -0700530 if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
531 sizeInBytes = track->sharedBuffer()->size();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700532 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700533 memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700534 written = sizeInBytes;
Glenn Kastenfe834d32014-01-08 14:49:08 -0800535 } break;
536
537 case AUDIO_FORMAT_PCM_8_BIT: {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700538 // data contains 8bit data we need to expand to 16bit before copying
539 // to the shared memory
540 // writing to shared memory, check for capacity,
541 // note that input data will occupy 2X the input space due to 8 to 16bit conversion
Eric Laurent532bc1c2012-04-20 12:45:03 -0700542 if (((size_t)sizeInBytes)*2 > track->sharedBuffer()->size()) {
543 sizeInBytes = track->sharedBuffer()->size() / 2;
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700544 }
545 int count = sizeInBytes;
Eric Laurent532bc1c2012-04-20 12:45:03 -0700546 int16_t *dst = (int16_t *)track->sharedBuffer()->pointer();
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700547 const int8_t *src = (const int8_t *)(data + offsetInBytes);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700548 while (count--) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700549 *dst++ = (int16_t)(*src++^0x80) << 8;
550 }
551 // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
552 // the 8bit mixer restriction from the user of this function
553 written = sizeInBytes;
Glenn Kastenfe834d32014-01-08 14:49:08 -0800554 } break;
555
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700556 }
557 }
558 return written;
559
560}
561
562// ----------------------------------------------------------------------------
Glenn Kasten00db1f52012-01-16 14:41:30 -0800563static jint android_media_AudioTrack_native_write_byte(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 jbyteArray javaAudioData,
565 jint offsetInBytes, jint sizeInBytes,
566 jint javaAudioFormat) {
Glenn Kasten00db1f52012-01-16 14:41:30 -0800567 //ALOGV("android_media_AudioTrack_native_write_byte(offset=%d, sizeInBytes=%d) called",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 // offsetInBytes, sizeInBytes);
Eric Laurent532bc1c2012-04-20 12:45:03 -0700569 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 if (lpTrack == NULL) {
571 jniThrowException(env, "java/lang/IllegalStateException",
572 "Unable to retrieve AudioTrack pointer for write()");
Eric Laurent7070b362010-07-16 07:43:46 -0700573 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 }
575
576 // get the pointer for the audio data from the java array
Eric Laurent421ddc02011-03-07 14:52:59 -0800577 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
578 // a way that it becomes much more efficient. When doing so, we will have to prevent the
579 // AudioSystem callback to be called while in critical section (in case of media server
580 // process crash for instance)
Eric Laurent532bc1c2012-04-20 12:45:03 -0700581 jbyte* cAudioData = NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 if (javaAudioData) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800583 cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 if (cAudioData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000585 ALOGE("Error retrieving source of audio data to play, can't play");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 return 0; // out of memory or no data to load
587 }
588 } else {
Steve Block3762c312012-01-06 19:20:56 +0000589 ALOGE("NULL java array of audio data to play, can't play");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 return 0;
591 }
592
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700593 jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594
Eric Laurent421ddc02011-03-07 14:52:59 -0800595 env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596
Steve Block71f2cf12011-10-20 11:56:00 +0100597 //ALOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 // (int)written, (int)(sizeInBytes), (int)offsetInBytes);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700599 return written;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600}
601
602
603// ----------------------------------------------------------------------------
604static jint android_media_AudioTrack_native_write_short(JNIEnv *env, jobject thiz,
605 jshortArray javaAudioData,
606 jint offsetInShorts, jint sizeInShorts,
607 jint javaAudioFormat) {
Glenn Kastenf7e0a3702013-07-10 14:03:03 -0700608 jint written = android_media_AudioTrack_native_write_byte(env, thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 (jbyteArray) javaAudioData,
610 offsetInShorts*2, sizeInShorts*2,
Glenn Kastenf7e0a3702013-07-10 14:03:03 -0700611 javaAudioFormat);
612 if (written > 0) {
613 written /= 2;
614 }
615 return written;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616}
617
618
619// ----------------------------------------------------------------------------
620static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700621 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
622 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 jniThrowException(env, "java/lang/IllegalStateException",
624 "Unable to retrieve AudioTrack pointer for frameCount()");
625 return AUDIOTRACK_ERROR;
626 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700627
628 return lpTrack->frameCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629}
630
631
632// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700633static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 jint sampleRateInHz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700635 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
636 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 jniThrowException(env, "java/lang/IllegalStateException",
638 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurent88e209d2009-07-07 07:10:45 -0700639 return AUDIOTRACK_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700641 return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642}
643
644
645// ----------------------------------------------------------------------------
646static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700647 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
648 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 jniThrowException(env, "java/lang/IllegalStateException",
650 "Unable to retrieve AudioTrack pointer for getSampleRate()");
651 return AUDIOTRACK_ERROR;
652 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700653 return (jint) lpTrack->getSampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654}
655
656
657// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700658static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 jint markerPos) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700660 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
661 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 jniThrowException(env, "java/lang/IllegalStateException",
663 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
664 return AUDIOTRACK_ERROR;
665 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700666 return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667}
668
669
670// ----------------------------------------------------------------------------
671static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700672 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700674
Eric Laurent532bc1c2012-04-20 12:45:03 -0700675 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 jniThrowException(env, "java/lang/IllegalStateException",
677 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
678 return AUDIOTRACK_ERROR;
679 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700680 lpTrack->getMarkerPosition(&markerPos);
681 return (jint)markerPos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682}
683
684
685// ----------------------------------------------------------------------------
686static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
687 jint period) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700688 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
689 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 jniThrowException(env, "java/lang/IllegalStateException",
691 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
692 return AUDIOTRACK_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700693 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700694 return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695}
696
697
698// ----------------------------------------------------------------------------
699static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700700 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700702
Eric Laurent532bc1c2012-04-20 12:45:03 -0700703 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 jniThrowException(env, "java/lang/IllegalStateException",
705 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
706 return AUDIOTRACK_ERROR;
707 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700708 lpTrack->getPositionUpdatePeriod(&period);
709 return (jint)period;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710}
711
712
713// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700714static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 jint position) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700716 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
717 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 jniThrowException(env, "java/lang/IllegalStateException",
719 "Unable to retrieve AudioTrack pointer for setPosition()");
720 return AUDIOTRACK_ERROR;
721 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700722 return android_media_translateErrorCode( lpTrack->setPosition(position) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723}
724
725
726// ----------------------------------------------------------------------------
727static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700728 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 uint32_t position = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700730
Eric Laurent532bc1c2012-04-20 12:45:03 -0700731 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 jniThrowException(env, "java/lang/IllegalStateException",
733 "Unable to retrieve AudioTrack pointer for getPosition()");
734 return AUDIOTRACK_ERROR;
735 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700736 lpTrack->getPosition(&position);
737 return (jint)position;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738}
739
740
741// ----------------------------------------------------------------------------
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100742static jint android_media_AudioTrack_get_latency(JNIEnv *env, jobject thiz) {
743 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
744
745 if (lpTrack == NULL) {
746 jniThrowException(env, "java/lang/IllegalStateException",
747 "Unable to retrieve AudioTrack pointer for latency()");
748 return AUDIOTRACK_ERROR;
749 }
750 return (jint)lpTrack->latency();
751}
752
753
754// ----------------------------------------------------------------------------
Glenn Kasten948c2e62013-09-04 13:51:29 -0700755static jint android_media_AudioTrack_get_timestamp(JNIEnv *env, jobject thiz, jlongArray jTimestamp) {
756 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
757
758 if (lpTrack == NULL) {
759 ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
760 return AUDIOTRACK_ERROR;
761 }
762 AudioTimestamp timestamp;
763 status_t status = lpTrack->getTimestamp(timestamp);
764 if (status == OK) {
765 jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
766 if (nTimestamp == NULL) {
767 ALOGE("Unable to get array for getTimestamp()");
768 return AUDIOTRACK_ERROR;
769 }
770 nTimestamp[0] = (jlong) timestamp.mPosition;
771 nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
772 env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
773 }
774 return (jint) android_media_translateErrorCode(status);
775}
776
777
778// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
780 jint loopStart, jint loopEnd, jint loopCount) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700781 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
782 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 jniThrowException(env, "java/lang/IllegalStateException",
784 "Unable to retrieve AudioTrack pointer for setLoop()");
785 return AUDIOTRACK_ERROR;
786 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700787 return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788}
789
790
791// ----------------------------------------------------------------------------
792static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700793 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
794 if (lpTrack == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 jniThrowException(env, "java/lang/IllegalStateException",
796 "Unable to retrieve AudioTrack pointer for reload()");
797 return AUDIOTRACK_ERROR;
798 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700799 return android_media_translateErrorCode( lpTrack->reload() );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800}
801
802
803// ----------------------------------------------------------------------------
804static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
805 jint javaStreamType) {
Glenn Kasten85fbc872012-11-14 13:21:09 -0800806 uint32_t afSamplingRate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 // convert the stream type from Java to native value
808 // FIXME: code duplication with android_media_AudioTrack_native_setup()
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700809 audio_stream_type_t nativeStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -0800810 switch (javaStreamType) {
811 case AUDIO_STREAM_VOICE_CALL:
812 case AUDIO_STREAM_SYSTEM:
813 case AUDIO_STREAM_RING:
814 case AUDIO_STREAM_MUSIC:
815 case AUDIO_STREAM_ALARM:
816 case AUDIO_STREAM_NOTIFICATION:
817 case AUDIO_STREAM_BLUETOOTH_SCO:
818 case AUDIO_STREAM_DTMF:
819 nativeStreamType = (audio_stream_type_t) javaStreamType;
820 break;
821 default:
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700822 nativeStreamType = AUDIO_STREAM_DEFAULT;
Glenn Kasten29a09092012-01-16 14:37:12 -0800823 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 }
825
826 if (AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000827 ALOGE("AudioSystem::getOutputSamplingRate() for stream type %d failed in AudioTrack JNI",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 nativeStreamType);
829 return DEFAULT_OUTPUT_SAMPLE_RATE;
830 } else {
831 return afSamplingRate;
832 }
833}
834
835
836// ----------------------------------------------------------------------------
837// returns the minimum required size for the successful creation of a streaming AudioTrack
838// returns -1 if there was an error querying the hardware.
839static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
840 jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +0800841
Glenn Kasten659a9712014-01-08 11:38:33 -0800842 size_t frameCount;
843 const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
844 sampleRateInHertz);
845 if (status != NO_ERROR) {
846 ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
847 sampleRateInHertz, status);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 return -1;
849 }
Glenn Kastenfe834d32014-01-08 14:49:08 -0800850 const audio_format_t format = audioFormatToNative(audioFormat);
851 const size_t bytesPerSample = audio_bytes_per_sample(format);
852 return frameCount * nbChannels * bytesPerSample;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853}
854
Eric Laurent7070b362010-07-16 07:43:46 -0700855// ----------------------------------------------------------------------------
856static void
857android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
858{
Eric Laurent532bc1c2012-04-20 12:45:03 -0700859 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
Eric Laurent7070b362010-07-16 07:43:46 -0700860 if (lpTrack == NULL ) {
861 jniThrowException(env, "java/lang/IllegalStateException",
862 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
863 return;
864 }
865
866 lpTrack->setAuxEffectSendLevel(level);
867}
868
869// ----------------------------------------------------------------------------
870static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
871 jint effectId) {
Eric Laurent532bc1c2012-04-20 12:45:03 -0700872 sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
873 if (lpTrack == NULL) {
Eric Laurent7070b362010-07-16 07:43:46 -0700874 jniThrowException(env, "java/lang/IllegalStateException",
875 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
876 return AUDIOTRACK_ERROR;
877 }
Eric Laurent532bc1c2012-04-20 12:45:03 -0700878 return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
Eric Laurent7070b362010-07-16 07:43:46 -0700879}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880
881// ----------------------------------------------------------------------------
882// ----------------------------------------------------------------------------
883static JNINativeMethod gMethods[] = {
884 // name, signature, funcPtr
885 {"native_start", "()V", (void *)android_media_AudioTrack_start},
886 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
887 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
888 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
Eric Laurent619346f2010-06-21 09:27:30 -0700889 {"native_setup", "(Ljava/lang/Object;IIIIII[I)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 (void *)android_media_AudioTrack_native_setup},
891 {"native_finalize", "()V", (void *)android_media_AudioTrack_native_finalize},
892 {"native_release", "()V", (void *)android_media_AudioTrack_native_release},
Glenn Kasten00db1f52012-01-16 14:41:30 -0800893 {"native_write_byte", "([BIII)I", (void *)android_media_AudioTrack_native_write_byte},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 {"native_write_short", "([SIII)I", (void *)android_media_AudioTrack_native_write_short},
895 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
896 {"native_get_native_frame_count",
897 "()I", (void *)android_media_AudioTrack_get_native_frame_count},
898 {"native_set_playback_rate",
Eric Laurent88e209d2009-07-07 07:10:45 -0700899 "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 {"native_get_playback_rate",
901 "()I", (void *)android_media_AudioTrack_get_playback_rate},
902 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
903 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
904 {"native_set_pos_update_period",
905 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
906 {"native_get_pos_update_period",
907 "()I", (void *)android_media_AudioTrack_get_pos_update_period},
908 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
909 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100910 {"native_get_latency", "()I", (void *)android_media_AudioTrack_get_latency},
Glenn Kasten948c2e62013-09-04 13:51:29 -0700911 {"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
913 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
914 {"native_get_output_sample_rate",
915 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
916 {"native_get_min_buff_size",
917 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
Eric Laurent7070b362010-07-16 07:43:46 -0700918 {"native_setAuxEffectSendLevel",
919 "(F)V", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
920 {"native_attachAuxEffect",
921 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922};
923
924
925// field names found in android/media/AudioTrack.java
926#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
928#define JAVA_JNIDATA_FIELD_NAME "mJniData"
929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930// ----------------------------------------------------------------------------
931// preconditions:
932// theClass is valid
933bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
934 const char* constName, int* constVal) {
935 jfieldID javaConst = NULL;
936 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
937 if (javaConst != NULL) {
938 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
939 return true;
940 } else {
Steve Block3762c312012-01-06 19:20:56 +0000941 ALOGE("Can't find %s.%s", className, constName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 return false;
943 }
944}
945
946
947// ----------------------------------------------------------------------------
948int register_android_media_AudioTrack(JNIEnv *env)
949{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
951 javaAudioTrackFields.postNativeEventInJava = NULL;
952
953 // Get the AudioTrack class
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700954 jclass audioTrackClass = env->FindClass(kClassPathName);
955 if (audioTrackClass == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000956 ALOGE("Can't find %s", kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 return -1;
958 }
959
960 // Get the postEvent method
961 javaAudioTrackFields.postNativeEventInJava = env->GetStaticMethodID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700962 audioTrackClass,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
964 if (javaAudioTrackFields.postNativeEventInJava == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000965 ALOGE("Can't find AudioTrack.%s", JAVA_POSTEVENT_CALLBACK_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 return -1;
967 }
968
969 // Get the variables fields
970 // nativeTrackInJavaObj
971 javaAudioTrackFields.nativeTrackInJavaObj = env->GetFieldID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700972 audioTrackClass,
Ashok Bhat075e9a12014-01-06 13:45:09 +0000973 JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 if (javaAudioTrackFields.nativeTrackInJavaObj == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000975 ALOGE("Can't find AudioTrack.%s", JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 return -1;
977 }
978 // jniData;
979 javaAudioTrackFields.jniData = env->GetFieldID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700980 audioTrackClass,
Ashok Bhat075e9a12014-01-06 13:45:09 +0000981 JAVA_JNIDATA_FIELD_NAME, "J");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 if (javaAudioTrackFields.jniData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000983 ALOGE("Can't find AudioTrack.%s", JAVA_JNIDATA_FIELD_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 return -1;
985 }
986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
988}
989
990
991// ----------------------------------------------------------------------------