blob: 9fbc477a86fedac25039a45bb30b082a279fb79d [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
20#include <stdio.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <math.h>
24
Glenn Kastenc81d31c2012-03-13 14:46:23 -070025#include <jni.h>
26#include <JNIHelp.h>
27#include <android_runtime/AndroidRuntime.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
Glenn Kastenc81d31c2012-03-13 14:46:23 -070029#include <utils/Log.h>
30#include <media/AudioSystem.h>
31#include <media/AudioTrack.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Mathias Agopian07952722009-05-19 19:08:10 -070033#include <binder/MemoryHeapBase.h>
34#include <binder/MemoryBase.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035
Dima Zavin24fc2fb2011-04-19 22:30:36 -070036#include <cutils/bitops.h>
37
Dima Zavin34bb4192011-05-11 14:15:23 -070038#include <system/audio.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
40// ----------------------------------------------------------------------------
41
42using namespace android;
43
44// ----------------------------------------------------------------------------
45static const char* const kClassPathName = "android/media/AudioTrack";
46
47struct fields_t {
48 // these fields provide access from C++ to the...
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 jmethodID postNativeEventInJava; //... event post callback method
50 int PCM16; //... format constants
51 int PCM8; //... format constants
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 int MODE_STREAM; //... memory mode
53 int MODE_STATIC; //... memory mode
Eric Laurent83b36852009-07-28 07:49:22 -070054 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
56};
57static fields_t javaAudioTrackFields;
58
59struct audiotrack_callback_cookie {
60 jclass audioTrack_class;
61 jobject audioTrack_ref;
62 };
63
64// ----------------------------------------------------------------------------
65class AudioTrackJniStorage {
66 public:
67 sp<MemoryHeapBase> mMemHeap;
68 sp<MemoryBase> mMemBase;
69 audiotrack_callback_cookie mCallbackData;
Glenn Kastenbc1d77b2012-01-12 16:38:12 -080070 audio_stream_type_t mStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
72 AudioTrackJniStorage() {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -070073 mCallbackData.audioTrack_class = 0;
74 mCallbackData.audioTrack_ref = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -070075 mStreamType = AUDIO_STREAM_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 }
77
78 ~AudioTrackJniStorage() {
79 mMemBase.clear();
80 mMemHeap.clear();
81 }
82
83 bool allocSharedMem(int sizeInBytes) {
84 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
85 if (mMemHeap->getHeapID() < 0) {
86 return false;
87 }
88 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
89 return true;
90 }
91};
92
93// ----------------------------------------------------------------------------
94#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
95
96#define AUDIOTRACK_SUCCESS 0
97#define AUDIOTRACK_ERROR -1
98#define AUDIOTRACK_ERROR_BAD_VALUE -2
99#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
100#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
Glenn Kastenfb2ab9e2011-12-12 09:05:55 -0800101#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
103#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
104#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
105
106
107jint android_media_translateErrorCode(int code) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700108 switch (code) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 case NO_ERROR:
110 return AUDIOTRACK_SUCCESS;
111 case BAD_VALUE:
112 return AUDIOTRACK_ERROR_BAD_VALUE;
113 case INVALID_OPERATION:
114 return AUDIOTRACK_ERROR_INVALID_OPERATION;
115 default:
116 return AUDIOTRACK_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700117 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118}
119
120
121// ----------------------------------------------------------------------------
Glenn Kastene46a86f2011-06-01 15:20:35 -0700122static void audioCallback(int event, void* user, void *info) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 if (event == AudioTrack::EVENT_MORE_DATA) {
124 // set size to 0 to signal we're not using the callback to write more data
125 AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700126 pBuff->size = 0;
127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 } else if (event == AudioTrack::EVENT_MARKER) {
129 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
130 JNIEnv *env = AndroidRuntime::getJNIEnv();
131 if (user && env) {
132 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700133 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 javaAudioTrackFields.postNativeEventInJava,
135 callbackInfo->audioTrack_ref, event, 0,0, NULL);
136 if (env->ExceptionCheck()) {
137 env->ExceptionDescribe();
138 env->ExceptionClear();
139 }
140 }
141
142 } else if (event == AudioTrack::EVENT_NEW_POS) {
143 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
144 JNIEnv *env = AndroidRuntime::getJNIEnv();
145 if (user && env) {
146 env->CallStaticVoidMethod(
Glenn Kasten18db49a2012-03-12 16:29:55 -0700147 callbackInfo->audioTrack_class,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 javaAudioTrackFields.postNativeEventInJava,
149 callbackInfo->audioTrack_ref, event, 0,0, NULL);
150 if (env->ExceptionCheck()) {
151 env->ExceptionDescribe();
152 env->ExceptionClear();
153 }
154 }
155 }
156}
157
158
159// ----------------------------------------------------------------------------
160static int
161android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700162 jint streamType, jint sampleRateInHertz, jint javaChannelMask,
Eric Laurent619346f2010-06-21 09:27:30 -0700163 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164{
Steve Block71f2cf12011-10-20 11:56:00 +0100165 ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700166 sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 int afSampleRate;
168 int afFrameCount;
169
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800170 if (AudioSystem::getOutputFrameCount(&afFrameCount, (audio_stream_type_t) streamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000171 ALOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
173 }
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800174 if (AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000175 ALOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
177 }
178
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700179 // Java channel masks don't map directly to the native definition, but it's a simple shift
180 // to skip the two deprecated channel configurations "default" and "mono".
181 uint32_t nativeChannelMask = ((uint32_t)javaChannelMask) >> 2;
182
183 if (!audio_is_output_channel(nativeChannelMask)) {
Steve Block3762c312012-01-06 19:20:56 +0000184 ALOGE("Error creating AudioTrack: invalid channel mask.");
Eric Laurenta553c252009-07-17 12:17:14 -0700185 return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 }
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700187
188 int nbChannels = popcount(nativeChannelMask);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 // check the stream type
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700191 audio_stream_type_t atStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -0800192 switch (streamType) {
193 case AUDIO_STREAM_VOICE_CALL:
194 case AUDIO_STREAM_SYSTEM:
195 case AUDIO_STREAM_RING:
196 case AUDIO_STREAM_MUSIC:
197 case AUDIO_STREAM_ALARM:
198 case AUDIO_STREAM_NOTIFICATION:
199 case AUDIO_STREAM_BLUETOOTH_SCO:
200 case AUDIO_STREAM_DTMF:
201 atStreamType = (audio_stream_type_t) streamType;
202 break;
203 default:
Steve Block3762c312012-01-06 19:20:56 +0000204 ALOGE("Error creating AudioTrack: unknown stream type.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
206 }
207
208 // check the format.
209 // This function was called from Java, so we compare the format against the Java constants
210 if ((audioFormat != javaAudioTrackFields.PCM16) && (audioFormat != javaAudioTrackFields.PCM8)) {
Steve Block3762c312012-01-06 19:20:56 +0000211 ALOGE("Error creating AudioTrack: unsupported audio format.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
213 }
214
215 // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class
216 // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled
Glenn Kasten00db1f52012-01-16 14:41:30 -0800217 // in android_media_AudioTrack_native_write_byte()
Glenn Kasten18db49a2012-03-12 16:29:55 -0700218 if ((audioFormat == javaAudioTrackFields.PCM8)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 && (memoryMode == javaAudioTrackFields.MODE_STATIC)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100220 ALOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 buff size of %dbytes, switching to 16bit, buff size of %dbytes",
222 buffSizeInBytes, 2*buffSizeInBytes);
223 audioFormat = javaAudioTrackFields.PCM16;
224 // we will need twice the memory to store the data
225 buffSizeInBytes *= 2;
226 }
227
228 // compute the frame count
229 int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
Glenn Kasten1c5a89d2012-01-04 09:36:37 -0800230 audio_format_t format = audioFormat == javaAudioTrackFields.PCM16 ?
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700231 AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT;
Eric Laurenta553c252009-07-17 12:17:14 -0700232 int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
Glenn Kasten18db49a2012-03-12 16:29:55 -0700235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 // initialize the callback information:
237 // this data will be passed with every AudioTrack callback
238 jclass clazz = env->GetObjectClass(thiz);
239 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000240 ALOGE("Can't find %s when setting up callback.", kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 delete lpJniStorage;
242 return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
243 }
244 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
245 // we use a weak reference so the AudioTrack object can be garbage collected.
246 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 lpJniStorage->mStreamType = atStreamType;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700249
250 if (jSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000251 ALOGE("Error creating AudioTrack: invalid session ID pointer");
Eric Laurent619346f2010-06-21 09:27:30 -0700252 delete lpJniStorage;
253 return AUDIOTRACK_ERROR;
254 }
255
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700256 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
257 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000258 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700259 delete lpJniStorage;
260 return AUDIOTRACK_ERROR;
261 }
262 int sessionId = nSession[0];
263 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
264 nSession = NULL;
265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 // create the native AudioTrack object
267 AudioTrack* lpTrack = new AudioTrack();
268 if (lpTrack == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000269 ALOGE("Error creating uninitialized AudioTrack");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 goto native_track_failure;
271 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 // initialize the native AudioTrack object
274 if (memoryMode == javaAudioTrackFields.MODE_STREAM) {
275
276 lpTrack->set(
277 atStreamType,// stream type
278 sampleRateInHertz,
279 format,// word length, PCM
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700280 nativeChannelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 frameCount,
Glenn Kasten28b269f2012-03-07 09:15:37 -0800282 AUDIO_POLICY_OUTPUT_FLAG_NONE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
284 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
285 0,// shared mem
Eric Laurent619346f2010-06-21 09:27:30 -0700286 true,// thread can call Java
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700287 sessionId);// audio session ID
Glenn Kasten18db49a2012-03-12 16:29:55 -0700288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 } else if (memoryMode == javaAudioTrackFields.MODE_STATIC) {
290 // AudioTrack is using shared memory
Glenn Kasten18db49a2012-03-12 16:29:55 -0700291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
Steve Block3762c312012-01-06 19:20:56 +0000293 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 goto native_init_failure;
295 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 lpTrack->set(
298 atStreamType,// stream type
299 sampleRateInHertz,
300 format,// word length, PCM
Jean-Michel Trivid9ae1c52011-07-25 12:58:14 -0700301 nativeChannelMask,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 frameCount,
Glenn Kasten28b269f2012-03-07 09:15:37 -0800303 AUDIO_POLICY_OUTPUT_FLAG_NONE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
Glenn Kasten18db49a2012-03-12 16:29:55 -0700305 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 lpJniStorage->mMemBase,// shared mem
Eric Laurent619346f2010-06-21 09:27:30 -0700307 true,// thread can call Java
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700308 sessionId);// audio session ID
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 }
310
311 if (lpTrack->initCheck() != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000312 ALOGE("Error initializing AudioTrack");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 goto native_init_failure;
314 }
315
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700316 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
317 if (nSession == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000318 ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700319 goto native_init_failure;
320 }
Eric Laurent619346f2010-06-21 09:27:30 -0700321 // read the audio session ID back from AudioTrack in case we create a new session
322 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700323 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
324 nSession = NULL;
325
Glenn Kasten18db49a2012-03-12 16:29:55 -0700326 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 // of the Java object (in mNativeTrackInJavaObj)
328 env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)lpTrack);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 // save the JNI resources so we can free them later
Steve Block71f2cf12011-10-20 11:56:00 +0100331 //ALOGV("storing lpJniStorage: %x\n", (int)lpJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 env->SetIntField(thiz, javaAudioTrackFields.jniData, (int)lpJniStorage);
333
334 return AUDIOTRACK_SUCCESS;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 // failures:
337native_init_failure:
338 delete lpTrack;
339 env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341native_track_failure:
Eric Laurent619346f2010-06-21 09:27:30 -0700342 if (nSession != NULL) {
343 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
344 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700345 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
346 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 delete lpJniStorage;
348 env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
349 return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351}
352
353
354// ----------------------------------------------------------------------------
355static void
356android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
357{
358 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
359 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
360 if (lpTrack == NULL ) {
361 jniThrowException(env, "java/lang/IllegalStateException",
362 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700363 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 lpTrack->start();
367}
368
369
370// ----------------------------------------------------------------------------
371static void
372android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
373{
374 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
375 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
376 if (lpTrack == NULL ) {
377 jniThrowException(env, "java/lang/IllegalStateException",
378 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700379 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 }
381
382 lpTrack->stop();
383}
384
385
386// ----------------------------------------------------------------------------
387static void
388android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
389{
390 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
391 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
392 if (lpTrack == NULL ) {
393 jniThrowException(env, "java/lang/IllegalStateException",
394 "Unable to retrieve AudioTrack pointer for pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700395 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 }
397
398 lpTrack->pause();
399}
400
401
402// ----------------------------------------------------------------------------
403static void
404android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
405{
406 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
407 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
408 if (lpTrack == NULL ) {
409 jniThrowException(env, "java/lang/IllegalStateException",
410 "Unable to retrieve AudioTrack pointer for flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700411 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 }
413
414 lpTrack->flush();
415}
416
417// ----------------------------------------------------------------------------
418static void
419android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
420{
421 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
422 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
423 if (lpTrack == NULL ) {
424 jniThrowException(env, "java/lang/IllegalStateException",
425 "Unable to retrieve AudioTrack pointer for setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700426 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 }
428
429 lpTrack->setVolume(leftVol, rightVol);
430}
431
432// ----------------------------------------------------------------------------
433static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) {
Steve Block71f2cf12011-10-20 11:56:00 +0100434 //ALOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 // delete the AudioTrack object
437 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
438 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
439 if (lpTrack) {
Steve Block71f2cf12011-10-20 11:56:00 +0100440 //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 lpTrack->stop();
442 delete lpTrack;
443 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 // delete the JNI data
446 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetIntField(
447 thiz, javaAudioTrackFields.jniData);
448 if (pJniStorage) {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700449 // delete global refs created in native_setup
450 env->DeleteGlobalRef(pJniStorage->mCallbackData.audioTrack_class);
451 env->DeleteGlobalRef(pJniStorage->mCallbackData.audioTrack_ref);
Steve Block71f2cf12011-10-20 11:56:00 +0100452 //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 delete pJniStorage;
454 }
455}
456
457// ----------------------------------------------------------------------------
458static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 // do everything a call to finalize would
461 android_media_AudioTrack_native_finalize(env, thiz);
462 // + reset the native resources in the Java object so any attempt to access
463 // them after a call to release fails.
464 env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
465 env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
466}
467
468
469// ----------------------------------------------------------------------------
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700470jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data,
471 jint offsetInBytes, jint sizeInBytes) {
472 // give the data to the native AudioTrack object (the data starts at the offset)
473 ssize_t written = 0;
474 // regular write() or copy the data to the AudioTrack's shared memory?
475 if (pTrack->sharedBuffer() == 0) {
476 written = pTrack->write(data + offsetInBytes, sizeInBytes);
477 } else {
478 if (audioFormat == javaAudioTrackFields.PCM16) {
479 // writing to shared memory, check for capacity
480 if ((size_t)sizeInBytes > pTrack->sharedBuffer()->size()) {
481 sizeInBytes = pTrack->sharedBuffer()->size();
482 }
483 memcpy(pTrack->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
484 written = sizeInBytes;
485 } else if (audioFormat == javaAudioTrackFields.PCM8) {
486 // data contains 8bit data we need to expand to 16bit before copying
487 // to the shared memory
488 // writing to shared memory, check for capacity,
489 // note that input data will occupy 2X the input space due to 8 to 16bit conversion
490 if (((size_t)sizeInBytes)*2 > pTrack->sharedBuffer()->size()) {
491 sizeInBytes = pTrack->sharedBuffer()->size() / 2;
492 }
493 int count = sizeInBytes;
494 int16_t *dst = (int16_t *)pTrack->sharedBuffer()->pointer();
495 const int8_t *src = (const int8_t *)(data + offsetInBytes);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700496 while (count--) {
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700497 *dst++ = (int16_t)(*src++^0x80) << 8;
498 }
499 // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
500 // the 8bit mixer restriction from the user of this function
501 written = sizeInBytes;
502 }
503 }
504 return written;
505
506}
507
508// ----------------------------------------------------------------------------
Glenn Kasten00db1f52012-01-16 14:41:30 -0800509static jint android_media_AudioTrack_native_write_byte(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 jbyteArray javaAudioData,
511 jint offsetInBytes, jint sizeInBytes,
512 jint javaAudioFormat) {
513 jbyte* cAudioData = NULL;
514 AudioTrack *lpTrack = NULL;
Glenn Kasten00db1f52012-01-16 14:41:30 -0800515 //ALOGV("android_media_AudioTrack_native_write_byte(offset=%d, sizeInBytes=%d) called",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 // offsetInBytes, sizeInBytes);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 // get the audio track to load with samples
519 lpTrack = (AudioTrack *)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
520 if (lpTrack == NULL) {
521 jniThrowException(env, "java/lang/IllegalStateException",
522 "Unable to retrieve AudioTrack pointer for write()");
Eric Laurent7070b362010-07-16 07:43:46 -0700523 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 }
525
526 // get the pointer for the audio data from the java array
Eric Laurent421ddc02011-03-07 14:52:59 -0800527 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
528 // a way that it becomes much more efficient. When doing so, we will have to prevent the
529 // AudioSystem callback to be called while in critical section (in case of media server
530 // process crash for instance)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 if (javaAudioData) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800532 cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 if (cAudioData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000534 ALOGE("Error retrieving source of audio data to play, can't play");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 return 0; // out of memory or no data to load
536 }
537 } else {
Steve Block3762c312012-01-06 19:20:56 +0000538 ALOGE("NULL java array of audio data to play, can't play");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 return 0;
540 }
541
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700542 jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543
Eric Laurent421ddc02011-03-07 14:52:59 -0800544 env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545
Steve Block71f2cf12011-10-20 11:56:00 +0100546 //ALOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 // (int)written, (int)(sizeInBytes), (int)offsetInBytes);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700548 return written;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549}
550
551
552// ----------------------------------------------------------------------------
553static jint android_media_AudioTrack_native_write_short(JNIEnv *env, jobject thiz,
554 jshortArray javaAudioData,
555 jint offsetInShorts, jint sizeInShorts,
556 jint javaAudioFormat) {
Glenn Kasten00db1f52012-01-16 14:41:30 -0800557 return (android_media_AudioTrack_native_write_byte(env, thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 (jbyteArray) javaAudioData,
559 offsetInShorts*2, sizeInShorts*2,
560 javaAudioFormat)
561 / 2);
562}
563
564
565// ----------------------------------------------------------------------------
566static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
567 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
568 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
569
570 if (lpTrack) {
571 return lpTrack->frameCount();
572 } else {
573 jniThrowException(env, "java/lang/IllegalStateException",
574 "Unable to retrieve AudioTrack pointer for frameCount()");
575 return AUDIOTRACK_ERROR;
576 }
577}
578
579
580// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700581static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 jint sampleRateInHz) {
583 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
584 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
585
586 if (lpTrack) {
Eric Laurent88e209d2009-07-07 07:10:45 -0700587 return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 } else {
589 jniThrowException(env, "java/lang/IllegalStateException",
590 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurent88e209d2009-07-07 07:10:45 -0700591 return AUDIOTRACK_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 }
593}
594
595
596// ----------------------------------------------------------------------------
597static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
598 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
599 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
600
601 if (lpTrack) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700602 return (jint) lpTrack->getSampleRate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 } else {
604 jniThrowException(env, "java/lang/IllegalStateException",
605 "Unable to retrieve AudioTrack pointer for getSampleRate()");
606 return AUDIOTRACK_ERROR;
607 }
608}
609
610
611// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700612static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 jint markerPos) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
616 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 if (lpTrack) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700619 return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 } else {
621 jniThrowException(env, "java/lang/IllegalStateException",
622 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
623 return AUDIOTRACK_ERROR;
624 }
625}
626
627
628// ----------------------------------------------------------------------------
629static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
632 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
633 uint32_t markerPos = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 if (lpTrack) {
636 lpTrack->getMarkerPosition(&markerPos);
637 return (jint)markerPos;
638 } else {
639 jniThrowException(env, "java/lang/IllegalStateException",
640 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
641 return AUDIOTRACK_ERROR;
642 }
643}
644
645
646// ----------------------------------------------------------------------------
647static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
648 jint period) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
651 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 if (lpTrack) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700654 return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 } else {
656 jniThrowException(env, "java/lang/IllegalStateException",
657 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
658 return AUDIOTRACK_ERROR;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660}
661
662
663// ----------------------------------------------------------------------------
664static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
667 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
668 uint32_t period = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 if (lpTrack) {
671 lpTrack->getPositionUpdatePeriod(&period);
672 return (jint)period;
673 } else {
674 jniThrowException(env, "java/lang/IllegalStateException",
675 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
676 return AUDIOTRACK_ERROR;
677 }
678}
679
680
681// ----------------------------------------------------------------------------
Glenn Kasten18db49a2012-03-12 16:29:55 -0700682static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 jint position) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
686 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 if (lpTrack) {
689 return android_media_translateErrorCode( lpTrack->setPosition(position) );
690 } else {
691 jniThrowException(env, "java/lang/IllegalStateException",
692 "Unable to retrieve AudioTrack pointer for setPosition()");
693 return AUDIOTRACK_ERROR;
694 }
695}
696
697
698// ----------------------------------------------------------------------------
699static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
702 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
703 uint32_t position = 0;
Glenn Kasten18db49a2012-03-12 16:29:55 -0700704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 if (lpTrack) {
706 lpTrack->getPosition(&position);
707 return (jint)position;
708 } else {
709 jniThrowException(env, "java/lang/IllegalStateException",
710 "Unable to retrieve AudioTrack pointer for getPosition()");
711 return AUDIOTRACK_ERROR;
712 }
713}
714
715
716// ----------------------------------------------------------------------------
717static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
718 jint loopStart, jint loopEnd, jint loopCount) {
719
720 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
721 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
722 if (lpTrack) {
723 return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
724 } else {
725 jniThrowException(env, "java/lang/IllegalStateException",
726 "Unable to retrieve AudioTrack pointer for setLoop()");
727 return AUDIOTRACK_ERROR;
728 }
729}
730
731
732// ----------------------------------------------------------------------------
733static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
734
735 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
736 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
737 if (lpTrack) {
738 return android_media_translateErrorCode( lpTrack->reload() );
739 } else {
740 jniThrowException(env, "java/lang/IllegalStateException",
741 "Unable to retrieve AudioTrack pointer for reload()");
742 return AUDIOTRACK_ERROR;
743 }
744}
745
746
747// ----------------------------------------------------------------------------
748static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
749 jint javaStreamType) {
750 int afSamplingRate;
751 // convert the stream type from Java to native value
752 // FIXME: code duplication with android_media_AudioTrack_native_setup()
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700753 audio_stream_type_t nativeStreamType;
Glenn Kasten29a09092012-01-16 14:37:12 -0800754 switch (javaStreamType) {
755 case AUDIO_STREAM_VOICE_CALL:
756 case AUDIO_STREAM_SYSTEM:
757 case AUDIO_STREAM_RING:
758 case AUDIO_STREAM_MUSIC:
759 case AUDIO_STREAM_ALARM:
760 case AUDIO_STREAM_NOTIFICATION:
761 case AUDIO_STREAM_BLUETOOTH_SCO:
762 case AUDIO_STREAM_DTMF:
763 nativeStreamType = (audio_stream_type_t) javaStreamType;
764 break;
765 default:
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700766 nativeStreamType = AUDIO_STREAM_DEFAULT;
Glenn Kasten29a09092012-01-16 14:37:12 -0800767 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 }
769
770 if (AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType) != NO_ERROR) {
Steve Block3762c312012-01-06 19:20:56 +0000771 ALOGE("AudioSystem::getOutputSamplingRate() for stream type %d failed in AudioTrack JNI",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 nativeStreamType);
773 return DEFAULT_OUTPUT_SAMPLE_RATE;
774 } else {
775 return afSamplingRate;
776 }
777}
778
779
780// ----------------------------------------------------------------------------
781// returns the minimum required size for the successful creation of a streaming AudioTrack
782// returns -1 if there was an error querying the hardware.
783static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
784 jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +0800785
786 int frameCount = 0;
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700787 if (AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
Chia-chi Yehc3308072010-08-19 17:14:36 +0800788 sampleRateInHertz) != NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 return -1;
790 }
Chia-chi Yehc3308072010-08-19 17:14:36 +0800791 return frameCount * nbChannels * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792}
793
Eric Laurent7070b362010-07-16 07:43:46 -0700794// ----------------------------------------------------------------------------
795static void
796android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
797{
798 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
799 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
800 if (lpTrack == NULL ) {
801 jniThrowException(env, "java/lang/IllegalStateException",
802 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
803 return;
804 }
805
806 lpTrack->setAuxEffectSendLevel(level);
807}
808
809// ----------------------------------------------------------------------------
810static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
811 jint effectId) {
812
813 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
814 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
815
816 if (lpTrack) {
817 return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
818 } else {
819 jniThrowException(env, "java/lang/IllegalStateException",
820 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
821 return AUDIOTRACK_ERROR;
822 }
823}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824
825// ----------------------------------------------------------------------------
826// ----------------------------------------------------------------------------
827static JNINativeMethod gMethods[] = {
828 // name, signature, funcPtr
829 {"native_start", "()V", (void *)android_media_AudioTrack_start},
830 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
831 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
832 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
Eric Laurent619346f2010-06-21 09:27:30 -0700833 {"native_setup", "(Ljava/lang/Object;IIIIII[I)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 (void *)android_media_AudioTrack_native_setup},
835 {"native_finalize", "()V", (void *)android_media_AudioTrack_native_finalize},
836 {"native_release", "()V", (void *)android_media_AudioTrack_native_release},
Glenn Kasten00db1f52012-01-16 14:41:30 -0800837 {"native_write_byte", "([BIII)I", (void *)android_media_AudioTrack_native_write_byte},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 {"native_write_short", "([SIII)I", (void *)android_media_AudioTrack_native_write_short},
839 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
840 {"native_get_native_frame_count",
841 "()I", (void *)android_media_AudioTrack_get_native_frame_count},
842 {"native_set_playback_rate",
Eric Laurent88e209d2009-07-07 07:10:45 -0700843 "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 {"native_get_playback_rate",
845 "()I", (void *)android_media_AudioTrack_get_playback_rate},
846 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
847 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
848 {"native_set_pos_update_period",
849 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
850 {"native_get_pos_update_period",
851 "()I", (void *)android_media_AudioTrack_get_pos_update_period},
852 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
853 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
854 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
855 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
856 {"native_get_output_sample_rate",
857 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
858 {"native_get_min_buff_size",
859 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
Eric Laurent7070b362010-07-16 07:43:46 -0700860 {"native_setAuxEffectSendLevel",
861 "(F)V", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
862 {"native_attachAuxEffect",
863 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864};
865
866
867// field names found in android/media/AudioTrack.java
868#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
869#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT"
870#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT"
871#define JAVA_CONST_BUFFER_COUNT_NAME "BUFFER_COUNT"
872#define JAVA_CONST_STREAM_VOICE_CALL_NAME "STREAM_VOICE_CALL"
873#define JAVA_CONST_STREAM_SYSTEM_NAME "STREAM_SYSTEM"
874#define JAVA_CONST_STREAM_RING_NAME "STREAM_RING"
875#define JAVA_CONST_STREAM_MUSIC_NAME "STREAM_MUSIC"
876#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
877#define JAVA_CONST_STREAM_NOTIFICATION_NAME "STREAM_NOTIFICATION"
878#define JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME "STREAM_BLUETOOTH_SCO"
Eric Laurent83b36852009-07-28 07:49:22 -0700879#define JAVA_CONST_STREAM_DTMF_NAME "STREAM_DTMF"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
881#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
882#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
883#define JAVA_JNIDATA_FIELD_NAME "mJniData"
884
885#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat"
886#define JAVA_AUDIOMANAGER_CLASS_NAME "android/media/AudioManager"
887
888// ----------------------------------------------------------------------------
889// preconditions:
890// theClass is valid
891bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
892 const char* constName, int* constVal) {
893 jfieldID javaConst = NULL;
894 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
895 if (javaConst != NULL) {
896 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
897 return true;
898 } else {
Steve Block3762c312012-01-06 19:20:56 +0000899 ALOGE("Can't find %s.%s", className, constName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 return false;
901 }
902}
903
904
905// ----------------------------------------------------------------------------
906int register_android_media_AudioTrack(JNIEnv *env)
907{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
909 javaAudioTrackFields.postNativeEventInJava = NULL;
910
911 // Get the AudioTrack class
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700912 jclass audioTrackClass = env->FindClass(kClassPathName);
913 if (audioTrackClass == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000914 ALOGE("Can't find %s", kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 return -1;
916 }
917
918 // Get the postEvent method
919 javaAudioTrackFields.postNativeEventInJava = env->GetStaticMethodID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700920 audioTrackClass,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
922 if (javaAudioTrackFields.postNativeEventInJava == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000923 ALOGE("Can't find AudioTrack.%s", JAVA_POSTEVENT_CALLBACK_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 return -1;
925 }
926
927 // Get the variables fields
928 // nativeTrackInJavaObj
929 javaAudioTrackFields.nativeTrackInJavaObj = env->GetFieldID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700930 audioTrackClass,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "I");
932 if (javaAudioTrackFields.nativeTrackInJavaObj == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000933 ALOGE("Can't find AudioTrack.%s", JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 return -1;
935 }
936 // jniData;
937 javaAudioTrackFields.jniData = env->GetFieldID(
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700938 audioTrackClass,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 JAVA_JNIDATA_FIELD_NAME, "I");
940 if (javaAudioTrackFields.jniData == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000941 ALOGE("Can't find AudioTrack.%s", JAVA_JNIDATA_FIELD_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 return -1;
943 }
944
945 // Get the memory mode constants
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700946 if ( !android_media_getIntConstantFromClass(env, audioTrackClass,
Glenn Kasten18db49a2012-03-12 16:29:55 -0700947 kClassPathName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 JAVA_CONST_MODE_STATIC_NAME, &(javaAudioTrackFields.MODE_STATIC))
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700949 || !android_media_getIntConstantFromClass(env, audioTrackClass,
Glenn Kasten18db49a2012-03-12 16:29:55 -0700950 kClassPathName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 JAVA_CONST_MODE_STREAM_NAME, &(javaAudioTrackFields.MODE_STREAM)) ) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700952 // error log performed in android_media_getIntConstantFromClass()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 return -1;
954 }
955
956 // Get the format constants from the AudioFormat class
957 jclass audioFormatClass = NULL;
958 audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
959 if (audioFormatClass == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000960 ALOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 return -1;
962 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700963 if ( !android_media_getIntConstantFromClass(env, audioFormatClass,
964 JAVA_AUDIOFORMAT_CLASS_NAME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 JAVA_CONST_PCM16_NAME, &(javaAudioTrackFields.PCM16))
Glenn Kasten18db49a2012-03-12 16:29:55 -0700966 || !android_media_getIntConstantFromClass(env, audioFormatClass,
967 JAVA_AUDIOFORMAT_CLASS_NAME,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 JAVA_CONST_PCM8_NAME, &(javaAudioTrackFields.PCM8)) ) {
Glenn Kasten18db49a2012-03-12 16:29:55 -0700969 // error log performed in android_media_getIntConstantFromClass()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 return -1;
971 }
Glenn Kasten18db49a2012-03-12 16:29:55 -0700972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
974}
975
976
977// ----------------------------------------------------------------------------