blob: 44d2a52e67ac2615b5090ba24f3bf1679ffa6abd [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
25#include "jni.h"
26#include "JNIHelp.h"
27#include "android_runtime/AndroidRuntime.h"
28
29#include "utils/Log.h"
30#include "media/AudioSystem.h"
31#include "media/AudioTrack.h"
32
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
36
37// ----------------------------------------------------------------------------
38
39using namespace android;
40
41// ----------------------------------------------------------------------------
42static const char* const kClassPathName = "android/media/AudioTrack";
43
44struct fields_t {
45 // these fields provide access from C++ to the...
46 jclass audioTrackClass; //... AudioTrack class
47 jmethodID postNativeEventInJava; //... event post callback method
48 int PCM16; //... format constants
49 int PCM8; //... format constants
50 int STREAM_VOICE_CALL; //... stream type constants
51 int STREAM_SYSTEM; //... stream type constants
52 int STREAM_RING; //... stream type constants
53 int STREAM_MUSIC; //... stream type constants
54 int STREAM_ALARM; //... stream type constants
55 int STREAM_NOTIFICATION; //... stream type constants
Eric Laurent83b36852009-07-28 07:49:22 -070056 int STREAM_BLUETOOTH_SCO; //... stream type constants
57 int STREAM_DTMF; //... stream type constants
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 int MODE_STREAM; //... memory mode
59 int MODE_STATIC; //... memory mode
Eric Laurent83b36852009-07-28 07:49:22 -070060 jfieldID nativeTrackInJavaObj; // stores in Java the native AudioTrack object
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 jfieldID jniData; // stores in Java additional resources used by the native AudioTrack
62};
63static fields_t javaAudioTrackFields;
64
65struct audiotrack_callback_cookie {
66 jclass audioTrack_class;
67 jobject audioTrack_ref;
68 };
69
70// ----------------------------------------------------------------------------
71class AudioTrackJniStorage {
72 public:
73 sp<MemoryHeapBase> mMemHeap;
74 sp<MemoryBase> mMemBase;
75 audiotrack_callback_cookie mCallbackData;
76 int mStreamType;
77
78 AudioTrackJniStorage() {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -070079 mCallbackData.audioTrack_class = 0;
80 mCallbackData.audioTrack_ref = 0;
81 mStreamType = AudioSystem::DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 }
83
84 ~AudioTrackJniStorage() {
85 mMemBase.clear();
86 mMemHeap.clear();
87 }
88
89 bool allocSharedMem(int sizeInBytes) {
90 mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
91 if (mMemHeap->getHeapID() < 0) {
92 return false;
93 }
94 mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
95 return true;
96 }
97};
98
99// ----------------------------------------------------------------------------
100#define DEFAULT_OUTPUT_SAMPLE_RATE 44100
101
102#define AUDIOTRACK_SUCCESS 0
103#define AUDIOTRACK_ERROR -1
104#define AUDIOTRACK_ERROR_BAD_VALUE -2
105#define AUDIOTRACK_ERROR_INVALID_OPERATION -3
106#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM -16
Eric Laurenta553c252009-07-17 12:17:14 -0700107#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK -17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT -18
109#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE -19
110#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED -20
111
112
113jint android_media_translateErrorCode(int code) {
114 switch(code) {
115 case NO_ERROR:
116 return AUDIOTRACK_SUCCESS;
117 case BAD_VALUE:
118 return AUDIOTRACK_ERROR_BAD_VALUE;
119 case INVALID_OPERATION:
120 return AUDIOTRACK_ERROR_INVALID_OPERATION;
121 default:
122 return AUDIOTRACK_ERROR;
123 }
124}
125
126
127// ----------------------------------------------------------------------------
128static void audioCallback(int event, void* user, void *info) {
129 if (event == AudioTrack::EVENT_MORE_DATA) {
130 // set size to 0 to signal we're not using the callback to write more data
131 AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;
132 pBuff->size = 0;
133
134 } else if (event == AudioTrack::EVENT_MARKER) {
135 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
136 JNIEnv *env = AndroidRuntime::getJNIEnv();
137 if (user && env) {
138 env->CallStaticVoidMethod(
139 callbackInfo->audioTrack_class,
140 javaAudioTrackFields.postNativeEventInJava,
141 callbackInfo->audioTrack_ref, event, 0,0, NULL);
142 if (env->ExceptionCheck()) {
143 env->ExceptionDescribe();
144 env->ExceptionClear();
145 }
146 }
147
148 } else if (event == AudioTrack::EVENT_NEW_POS) {
149 audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
150 JNIEnv *env = AndroidRuntime::getJNIEnv();
151 if (user && env) {
152 env->CallStaticVoidMethod(
153 callbackInfo->audioTrack_class,
154 javaAudioTrackFields.postNativeEventInJava,
155 callbackInfo->audioTrack_ref, event, 0,0, NULL);
156 if (env->ExceptionCheck()) {
157 env->ExceptionDescribe();
158 env->ExceptionClear();
159 }
160 }
161 }
162}
163
164
165// ----------------------------------------------------------------------------
166static int
167android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Eric Laurenta553c252009-07-17 12:17:14 -0700168 jint streamType, jint sampleRateInHertz, jint channels,
Eric Laurent619346f2010-06-21 09:27:30 -0700169 jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170{
Eric Laurenta553c252009-07-17 12:17:14 -0700171 LOGV("sampleRate=%d, audioFormat(from Java)=%d, channels=%x, buffSize=%d",
172 sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 int afSampleRate;
174 int afFrameCount;
175
176 if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
177 LOGE("Error creating AudioTrack: Could not get AudioSystem frame count.");
178 return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
179 }
180 if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
181 LOGE("Error creating AudioTrack: Could not get AudioSystem sampling rate.");
182 return AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
183 }
184
Eric Laurenta553c252009-07-17 12:17:14 -0700185 if (!AudioSystem::isOutputChannel(channels)) {
186 LOGE("Error creating AudioTrack: invalid channel mask.");
187 return AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 }
Eric Laurenta553c252009-07-17 12:17:14 -0700189 int nbChannels = AudioSystem::popCount(channels);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
191 // check the stream type
192 AudioSystem::stream_type atStreamType;
193 if (streamType == javaAudioTrackFields.STREAM_VOICE_CALL) {
194 atStreamType = AudioSystem::VOICE_CALL;
195 } else if (streamType == javaAudioTrackFields.STREAM_SYSTEM) {
196 atStreamType = AudioSystem::SYSTEM;
197 } else if (streamType == javaAudioTrackFields.STREAM_RING) {
198 atStreamType = AudioSystem::RING;
199 } else if (streamType == javaAudioTrackFields.STREAM_MUSIC) {
200 atStreamType = AudioSystem::MUSIC;
201 } else if (streamType == javaAudioTrackFields.STREAM_ALARM) {
202 atStreamType = AudioSystem::ALARM;
203 } else if (streamType == javaAudioTrackFields.STREAM_NOTIFICATION) {
204 atStreamType = AudioSystem::NOTIFICATION;
205 } else if (streamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
206 atStreamType = AudioSystem::BLUETOOTH_SCO;
Eric Laurent83b36852009-07-28 07:49:22 -0700207 } else if (streamType == javaAudioTrackFields.STREAM_DTMF) {
208 atStreamType = AudioSystem::DTMF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 } else {
210 LOGE("Error creating AudioTrack: unknown stream type.");
211 return AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
212 }
213
214 // check the format.
215 // This function was called from Java, so we compare the format against the Java constants
216 if ((audioFormat != javaAudioTrackFields.PCM16) && (audioFormat != javaAudioTrackFields.PCM8)) {
217 LOGE("Error creating AudioTrack: unsupported audio format.");
218 return AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
219 }
220
221 // for the moment 8bitPCM in MODE_STATIC is not supported natively in the AudioTrack C++ class
222 // so we declare everything as 16bitPCM, the 8->16bit conversion for MODE_STATIC will be handled
223 // in android_media_AudioTrack_native_write()
224 if ((audioFormat == javaAudioTrackFields.PCM8)
225 && (memoryMode == javaAudioTrackFields.MODE_STATIC)) {
226 LOGV("android_media_AudioTrack_native_setup(): requesting MODE_STATIC for 8bit \
227 buff size of %dbytes, switching to 16bit, buff size of %dbytes",
228 buffSizeInBytes, 2*buffSizeInBytes);
229 audioFormat = javaAudioTrackFields.PCM16;
230 // we will need twice the memory to store the data
231 buffSizeInBytes *= 2;
232 }
233
234 // compute the frame count
235 int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;
236 int format = audioFormat == javaAudioTrackFields.PCM16 ?
237 AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;
Eric Laurenta553c252009-07-17 12:17:14 -0700238 int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239
240 AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
241
242 // initialize the callback information:
243 // this data will be passed with every AudioTrack callback
244 jclass clazz = env->GetObjectClass(thiz);
245 if (clazz == NULL) {
246 LOGE("Can't find %s when setting up callback.", kClassPathName);
247 delete lpJniStorage;
248 return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
249 }
250 lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
251 // we use a weak reference so the AudioTrack object can be garbage collected.
252 lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
253
254 lpJniStorage->mStreamType = atStreamType;
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700255
256 if (jSession == NULL) {
Eric Laurent619346f2010-06-21 09:27:30 -0700257 LOGE("Error creating AudioTrack: invalid session ID pointer");
258 delete lpJniStorage;
259 return AUDIOTRACK_ERROR;
260 }
261
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700262 jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
263 if (nSession == NULL) {
264 LOGE("Error creating AudioTrack: Error retrieving session id pointer");
265 delete lpJniStorage;
266 return AUDIOTRACK_ERROR;
267 }
268 int sessionId = nSession[0];
269 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
270 nSession = NULL;
271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 // create the native AudioTrack object
273 AudioTrack* lpTrack = new AudioTrack();
274 if (lpTrack == NULL) {
275 LOGE("Error creating uninitialized AudioTrack");
276 goto native_track_failure;
277 }
278
279 // initialize the native AudioTrack object
280 if (memoryMode == javaAudioTrackFields.MODE_STREAM) {
281
282 lpTrack->set(
283 atStreamType,// stream type
284 sampleRateInHertz,
285 format,// word length, PCM
Eric Laurenta553c252009-07-17 12:17:14 -0700286 channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 frameCount,
288 0,// flags
289 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
290 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
291 0,// shared mem
Eric Laurent619346f2010-06-21 09:27:30 -0700292 true,// thread can call Java
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700293 sessionId);// audio session ID
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294
295 } else if (memoryMode == javaAudioTrackFields.MODE_STATIC) {
296 // AudioTrack is using shared memory
297
298 if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
299 LOGE("Error creating AudioTrack in static mode: error creating mem heap base");
300 goto native_init_failure;
301 }
302
303 lpTrack->set(
304 atStreamType,// stream type
305 sampleRateInHertz,
306 format,// word length, PCM
Eric Laurenta553c252009-07-17 12:17:14 -0700307 channels,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 frameCount,
309 0,// flags
310 audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
311 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
312 lpJniStorage->mMemBase,// shared mem
Eric Laurent619346f2010-06-21 09:27:30 -0700313 true,// thread can call Java
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700314 sessionId);// audio session ID
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316
317 if (lpTrack->initCheck() != NO_ERROR) {
318 LOGE("Error initializing AudioTrack");
319 goto native_init_failure;
320 }
321
Eric Laurent2fb43ef2010-09-24 12:03:36 -0700322 nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
323 if (nSession == NULL) {
324 LOGE("Error creating AudioTrack: Error retrieving session id pointer");
325 goto native_init_failure;
326 }
Eric Laurent619346f2010-06-21 09:27:30 -0700327 // read the audio session ID back from AudioTrack in case we create a new session
328 nSession[0] = lpTrack->getSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -0700329 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
330 nSession = NULL;
331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
333 // of the Java object (in mNativeTrackInJavaObj)
334 env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)lpTrack);
335
336 // save the JNI resources so we can free them later
337 //LOGV("storing lpJniStorage: %x\n", (int)lpJniStorage);
338 env->SetIntField(thiz, javaAudioTrackFields.jniData, (int)lpJniStorage);
339
340 return AUDIOTRACK_SUCCESS;
341
342 // failures:
343native_init_failure:
344 delete lpTrack;
345 env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
346
347native_track_failure:
Eric Laurent619346f2010-06-21 09:27:30 -0700348 if (nSession != NULL) {
349 env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
350 }
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700351 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
352 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 delete lpJniStorage;
354 env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
355 return AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
356
357}
358
359
360// ----------------------------------------------------------------------------
361static void
362android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
363{
364 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
365 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
366 if (lpTrack == NULL ) {
367 jniThrowException(env, "java/lang/IllegalStateException",
368 "Unable to retrieve AudioTrack pointer for start()");
Eric Laurent7070b362010-07-16 07:43:46 -0700369 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 }
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 lpTrack->start();
373}
374
375
376// ----------------------------------------------------------------------------
377static void
378android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
379{
380 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
381 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
382 if (lpTrack == NULL ) {
383 jniThrowException(env, "java/lang/IllegalStateException",
384 "Unable to retrieve AudioTrack pointer for stop()");
Eric Laurent7070b362010-07-16 07:43:46 -0700385 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 }
387
388 lpTrack->stop();
389}
390
391
392// ----------------------------------------------------------------------------
393static void
394android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
395{
396 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
397 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
398 if (lpTrack == NULL ) {
399 jniThrowException(env, "java/lang/IllegalStateException",
400 "Unable to retrieve AudioTrack pointer for pause()");
Eric Laurent7070b362010-07-16 07:43:46 -0700401 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 }
403
404 lpTrack->pause();
405}
406
407
408// ----------------------------------------------------------------------------
409static void
410android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
411{
412 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
413 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
414 if (lpTrack == NULL ) {
415 jniThrowException(env, "java/lang/IllegalStateException",
416 "Unable to retrieve AudioTrack pointer for flush()");
Eric Laurent7070b362010-07-16 07:43:46 -0700417 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 }
419
420 lpTrack->flush();
421}
422
423// ----------------------------------------------------------------------------
424static void
425android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
426{
427 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
428 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
429 if (lpTrack == NULL ) {
430 jniThrowException(env, "java/lang/IllegalStateException",
431 "Unable to retrieve AudioTrack pointer for setVolume()");
Eric Laurent7070b362010-07-16 07:43:46 -0700432 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 }
434
435 lpTrack->setVolume(leftVol, rightVol);
436}
437
438// ----------------------------------------------------------------------------
439static void android_media_AudioTrack_native_finalize(JNIEnv *env, jobject thiz) {
440 //LOGV("android_media_AudioTrack_native_finalize jobject: %x\n", (int)thiz);
441
442 // delete the AudioTrack object
443 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
444 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
445 if (lpTrack) {
446 //LOGV("deleting lpTrack: %x\n", (int)lpTrack);
447 lpTrack->stop();
448 delete lpTrack;
449 }
450
451 // delete the JNI data
452 AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetIntField(
453 thiz, javaAudioTrackFields.jniData);
454 if (pJniStorage) {
Jean-Michel Trivi8a149682009-07-15 18:31:11 -0700455 // delete global refs created in native_setup
456 env->DeleteGlobalRef(pJniStorage->mCallbackData.audioTrack_class);
457 env->DeleteGlobalRef(pJniStorage->mCallbackData.audioTrack_ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 //LOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
459 delete pJniStorage;
460 }
461}
462
463// ----------------------------------------------------------------------------
464static void android_media_AudioTrack_native_release(JNIEnv *env, jobject thiz) {
465
466 // do everything a call to finalize would
467 android_media_AudioTrack_native_finalize(env, thiz);
468 // + reset the native resources in the Java object so any attempt to access
469 // them after a call to release fails.
470 env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
471 env->SetIntField(thiz, javaAudioTrackFields.jniData, 0);
472}
473
474
475// ----------------------------------------------------------------------------
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700476jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data,
477 jint offsetInBytes, jint sizeInBytes) {
478 // give the data to the native AudioTrack object (the data starts at the offset)
479 ssize_t written = 0;
480 // regular write() or copy the data to the AudioTrack's shared memory?
481 if (pTrack->sharedBuffer() == 0) {
482 written = pTrack->write(data + offsetInBytes, sizeInBytes);
483 } else {
484 if (audioFormat == javaAudioTrackFields.PCM16) {
485 // writing to shared memory, check for capacity
486 if ((size_t)sizeInBytes > pTrack->sharedBuffer()->size()) {
487 sizeInBytes = pTrack->sharedBuffer()->size();
488 }
489 memcpy(pTrack->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
490 written = sizeInBytes;
491 } else if (audioFormat == javaAudioTrackFields.PCM8) {
492 // data contains 8bit data we need to expand to 16bit before copying
493 // to the shared memory
494 // writing to shared memory, check for capacity,
495 // note that input data will occupy 2X the input space due to 8 to 16bit conversion
496 if (((size_t)sizeInBytes)*2 > pTrack->sharedBuffer()->size()) {
497 sizeInBytes = pTrack->sharedBuffer()->size() / 2;
498 }
499 int count = sizeInBytes;
500 int16_t *dst = (int16_t *)pTrack->sharedBuffer()->pointer();
501 const int8_t *src = (const int8_t *)(data + offsetInBytes);
502 while(count--) {
503 *dst++ = (int16_t)(*src++^0x80) << 8;
504 }
505 // even though we wrote 2*sizeInBytes, we only report sizeInBytes as written to hide
506 // the 8bit mixer restriction from the user of this function
507 written = sizeInBytes;
508 }
509 }
510 return written;
511
512}
513
514// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515static jint android_media_AudioTrack_native_write(JNIEnv *env, jobject thiz,
516 jbyteArray javaAudioData,
517 jint offsetInBytes, jint sizeInBytes,
518 jint javaAudioFormat) {
519 jbyte* cAudioData = NULL;
520 AudioTrack *lpTrack = NULL;
521 //LOGV("android_media_AudioTrack_native_write(offset=%d, sizeInBytes=%d) called",
522 // offsetInBytes, sizeInBytes);
523
524 // get the audio track to load with samples
525 lpTrack = (AudioTrack *)env->GetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
526 if (lpTrack == NULL) {
527 jniThrowException(env, "java/lang/IllegalStateException",
528 "Unable to retrieve AudioTrack pointer for write()");
Eric Laurent7070b362010-07-16 07:43:46 -0700529 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 }
531
532 // get the pointer for the audio data from the java array
Eric Laurent421ddc02011-03-07 14:52:59 -0800533 // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
534 // a way that it becomes much more efficient. When doing so, we will have to prevent the
535 // AudioSystem callback to be called while in critical section (in case of media server
536 // process crash for instance)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 if (javaAudioData) {
Eric Laurent421ddc02011-03-07 14:52:59 -0800538 cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 if (cAudioData == NULL) {
540 LOGE("Error retrieving source of audio data to play, can't play");
541 return 0; // out of memory or no data to load
542 }
543 } else {
544 LOGE("NULL java array of audio data to play, can't play");
545 return 0;
546 }
547
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700548 jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549
Eric Laurent421ddc02011-03-07 14:52:59 -0800550 env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551
552 //LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
553 // (int)written, (int)(sizeInBytes), (int)offsetInBytes);
Jean-Michel Trivi21dc0372009-05-08 16:06:34 -0700554 return written;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555}
556
557
558// ----------------------------------------------------------------------------
559static jint android_media_AudioTrack_native_write_short(JNIEnv *env, jobject thiz,
560 jshortArray javaAudioData,
561 jint offsetInShorts, jint sizeInShorts,
562 jint javaAudioFormat) {
563 return (android_media_AudioTrack_native_write(env, thiz,
564 (jbyteArray) javaAudioData,
565 offsetInShorts*2, sizeInShorts*2,
566 javaAudioFormat)
567 / 2);
568}
569
570
571// ----------------------------------------------------------------------------
572static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
573 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
574 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
575
576 if (lpTrack) {
577 return lpTrack->frameCount();
578 } else {
579 jniThrowException(env, "java/lang/IllegalStateException",
580 "Unable to retrieve AudioTrack pointer for frameCount()");
581 return AUDIOTRACK_ERROR;
582 }
583}
584
585
586// ----------------------------------------------------------------------------
Eric Laurent88e209d2009-07-07 07:10:45 -0700587static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 jint sampleRateInHz) {
589 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
590 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
591
592 if (lpTrack) {
Eric Laurent88e209d2009-07-07 07:10:45 -0700593 return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 } else {
595 jniThrowException(env, "java/lang/IllegalStateException",
596 "Unable to retrieve AudioTrack pointer for setSampleRate()");
Eric Laurent88e209d2009-07-07 07:10:45 -0700597 return AUDIOTRACK_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 }
599}
600
601
602// ----------------------------------------------------------------------------
603static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thiz) {
604 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
605 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
606
607 if (lpTrack) {
608 return (jint) lpTrack->getSampleRate();
609 } else {
610 jniThrowException(env, "java/lang/IllegalStateException",
611 "Unable to retrieve AudioTrack pointer for getSampleRate()");
612 return AUDIOTRACK_ERROR;
613 }
614}
615
616
617// ----------------------------------------------------------------------------
618static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env, jobject thiz,
619 jint markerPos) {
620
621 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
622 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
623
624 if (lpTrack) {
625 return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
626 } else {
627 jniThrowException(env, "java/lang/IllegalStateException",
628 "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
629 return AUDIOTRACK_ERROR;
630 }
631}
632
633
634// ----------------------------------------------------------------------------
635static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env, jobject thiz) {
636
637 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
638 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
639 uint32_t markerPos = 0;
640
641 if (lpTrack) {
642 lpTrack->getMarkerPosition(&markerPos);
643 return (jint)markerPos;
644 } else {
645 jniThrowException(env, "java/lang/IllegalStateException",
646 "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
647 return AUDIOTRACK_ERROR;
648 }
649}
650
651
652// ----------------------------------------------------------------------------
653static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env, jobject thiz,
654 jint period) {
655
656 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
657 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
658
659 if (lpTrack) {
660 return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
661 } else {
662 jniThrowException(env, "java/lang/IllegalStateException",
663 "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
664 return AUDIOTRACK_ERROR;
665 }
666}
667
668
669// ----------------------------------------------------------------------------
670static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env, jobject thiz) {
671
672 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
673 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
674 uint32_t period = 0;
675
676 if (lpTrack) {
677 lpTrack->getPositionUpdatePeriod(&period);
678 return (jint)period;
679 } else {
680 jniThrowException(env, "java/lang/IllegalStateException",
681 "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
682 return AUDIOTRACK_ERROR;
683 }
684}
685
686
687// ----------------------------------------------------------------------------
688static jint android_media_AudioTrack_set_position(JNIEnv *env, jobject thiz,
689 jint position) {
690
691 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
692 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
693
694 if (lpTrack) {
695 return android_media_translateErrorCode( lpTrack->setPosition(position) );
696 } else {
697 jniThrowException(env, "java/lang/IllegalStateException",
698 "Unable to retrieve AudioTrack pointer for setPosition()");
699 return AUDIOTRACK_ERROR;
700 }
701}
702
703
704// ----------------------------------------------------------------------------
705static jint android_media_AudioTrack_get_position(JNIEnv *env, jobject thiz) {
706
707 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
708 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
709 uint32_t position = 0;
710
711 if (lpTrack) {
712 lpTrack->getPosition(&position);
713 return (jint)position;
714 } else {
715 jniThrowException(env, "java/lang/IllegalStateException",
716 "Unable to retrieve AudioTrack pointer for getPosition()");
717 return AUDIOTRACK_ERROR;
718 }
719}
720
721
722// ----------------------------------------------------------------------------
723static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
724 jint loopStart, jint loopEnd, jint loopCount) {
725
726 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
727 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
728 if (lpTrack) {
729 return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
730 } else {
731 jniThrowException(env, "java/lang/IllegalStateException",
732 "Unable to retrieve AudioTrack pointer for setLoop()");
733 return AUDIOTRACK_ERROR;
734 }
735}
736
737
738// ----------------------------------------------------------------------------
739static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) {
740
741 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
742 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
743 if (lpTrack) {
744 return android_media_translateErrorCode( lpTrack->reload() );
745 } else {
746 jniThrowException(env, "java/lang/IllegalStateException",
747 "Unable to retrieve AudioTrack pointer for reload()");
748 return AUDIOTRACK_ERROR;
749 }
750}
751
752
753// ----------------------------------------------------------------------------
754static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz,
755 jint javaStreamType) {
756 int afSamplingRate;
757 // convert the stream type from Java to native value
758 // FIXME: code duplication with android_media_AudioTrack_native_setup()
759 AudioSystem::stream_type nativeStreamType;
760 if (javaStreamType == javaAudioTrackFields.STREAM_VOICE_CALL) {
761 nativeStreamType = AudioSystem::VOICE_CALL;
762 } else if (javaStreamType == javaAudioTrackFields.STREAM_SYSTEM) {
763 nativeStreamType = AudioSystem::SYSTEM;
764 } else if (javaStreamType == javaAudioTrackFields.STREAM_RING) {
765 nativeStreamType = AudioSystem::RING;
766 } else if (javaStreamType == javaAudioTrackFields.STREAM_MUSIC) {
767 nativeStreamType = AudioSystem::MUSIC;
768 } else if (javaStreamType == javaAudioTrackFields.STREAM_ALARM) {
769 nativeStreamType = AudioSystem::ALARM;
770 } else if (javaStreamType == javaAudioTrackFields.STREAM_NOTIFICATION) {
771 nativeStreamType = AudioSystem::NOTIFICATION;
772 } else if (javaStreamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) {
773 nativeStreamType = AudioSystem::BLUETOOTH_SCO;
Eric Laurent83b36852009-07-28 07:49:22 -0700774 } else if (javaStreamType == javaAudioTrackFields.STREAM_DTMF) {
775 nativeStreamType = AudioSystem::DTMF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 } else {
777 nativeStreamType = AudioSystem::DEFAULT;
778 }
779
780 if (AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType) != NO_ERROR) {
781 LOGE("AudioSystem::getOutputSamplingRate() for stream type %d failed in AudioTrack JNI",
782 nativeStreamType);
783 return DEFAULT_OUTPUT_SAMPLE_RATE;
784 } else {
785 return afSamplingRate;
786 }
787}
788
789
790// ----------------------------------------------------------------------------
791// returns the minimum required size for the successful creation of a streaming AudioTrack
792// returns -1 if there was an error querying the hardware.
793static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env, jobject thiz,
794 jint sampleRateInHertz, jint nbChannels, jint audioFormat) {
Chia-chi Yehc3308072010-08-19 17:14:36 +0800795
796 int frameCount = 0;
797 if (AudioTrack::getMinFrameCount(&frameCount, AudioSystem::DEFAULT,
798 sampleRateInHertz) != NO_ERROR) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 return -1;
800 }
Chia-chi Yehc3308072010-08-19 17:14:36 +0800801 return frameCount * nbChannels * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802}
803
Eric Laurent7070b362010-07-16 07:43:46 -0700804// ----------------------------------------------------------------------------
805static void
806android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
807{
808 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
809 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
810 if (lpTrack == NULL ) {
811 jniThrowException(env, "java/lang/IllegalStateException",
812 "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
813 return;
814 }
815
816 lpTrack->setAuxEffectSendLevel(level);
817}
818
819// ----------------------------------------------------------------------------
820static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env, jobject thiz,
821 jint effectId) {
822
823 AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
824 thiz, javaAudioTrackFields.nativeTrackInJavaObj);
825
826 if (lpTrack) {
827 return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
828 } else {
829 jniThrowException(env, "java/lang/IllegalStateException",
830 "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
831 return AUDIOTRACK_ERROR;
832 }
833}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834
835// ----------------------------------------------------------------------------
836// ----------------------------------------------------------------------------
837static JNINativeMethod gMethods[] = {
838 // name, signature, funcPtr
839 {"native_start", "()V", (void *)android_media_AudioTrack_start},
840 {"native_stop", "()V", (void *)android_media_AudioTrack_stop},
841 {"native_pause", "()V", (void *)android_media_AudioTrack_pause},
842 {"native_flush", "()V", (void *)android_media_AudioTrack_flush},
Eric Laurent619346f2010-06-21 09:27:30 -0700843 {"native_setup", "(Ljava/lang/Object;IIIIII[I)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 (void *)android_media_AudioTrack_native_setup},
845 {"native_finalize", "()V", (void *)android_media_AudioTrack_native_finalize},
846 {"native_release", "()V", (void *)android_media_AudioTrack_native_release},
847 {"native_write_byte", "([BIII)I", (void *)android_media_AudioTrack_native_write},
848 {"native_write_short", "([SIII)I", (void *)android_media_AudioTrack_native_write_short},
849 {"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
850 {"native_get_native_frame_count",
851 "()I", (void *)android_media_AudioTrack_get_native_frame_count},
852 {"native_set_playback_rate",
Eric Laurent88e209d2009-07-07 07:10:45 -0700853 "(I)I", (void *)android_media_AudioTrack_set_playback_rate},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 {"native_get_playback_rate",
855 "()I", (void *)android_media_AudioTrack_get_playback_rate},
856 {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos},
857 {"native_get_marker_pos","()I", (void *)android_media_AudioTrack_get_marker_pos},
858 {"native_set_pos_update_period",
859 "(I)I", (void *)android_media_AudioTrack_set_pos_update_period},
860 {"native_get_pos_update_period",
861 "()I", (void *)android_media_AudioTrack_get_pos_update_period},
862 {"native_set_position", "(I)I", (void *)android_media_AudioTrack_set_position},
863 {"native_get_position", "()I", (void *)android_media_AudioTrack_get_position},
864 {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
865 {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
866 {"native_get_output_sample_rate",
867 "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate},
868 {"native_get_min_buff_size",
869 "(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
Eric Laurent7070b362010-07-16 07:43:46 -0700870 {"native_setAuxEffectSendLevel",
871 "(F)V", (void *)android_media_AudioTrack_setAuxEffectSendLevel},
872 {"native_attachAuxEffect",
873 "(I)I", (void *)android_media_AudioTrack_attachAuxEffect},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874};
875
876
877// field names found in android/media/AudioTrack.java
878#define JAVA_POSTEVENT_CALLBACK_NAME "postEventFromNative"
879#define JAVA_CONST_PCM16_NAME "ENCODING_PCM_16BIT"
880#define JAVA_CONST_PCM8_NAME "ENCODING_PCM_8BIT"
881#define JAVA_CONST_BUFFER_COUNT_NAME "BUFFER_COUNT"
882#define JAVA_CONST_STREAM_VOICE_CALL_NAME "STREAM_VOICE_CALL"
883#define JAVA_CONST_STREAM_SYSTEM_NAME "STREAM_SYSTEM"
884#define JAVA_CONST_STREAM_RING_NAME "STREAM_RING"
885#define JAVA_CONST_STREAM_MUSIC_NAME "STREAM_MUSIC"
886#define JAVA_CONST_STREAM_ALARM_NAME "STREAM_ALARM"
887#define JAVA_CONST_STREAM_NOTIFICATION_NAME "STREAM_NOTIFICATION"
888#define JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME "STREAM_BLUETOOTH_SCO"
Eric Laurent83b36852009-07-28 07:49:22 -0700889#define JAVA_CONST_STREAM_DTMF_NAME "STREAM_DTMF"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890#define JAVA_CONST_MODE_STREAM_NAME "MODE_STREAM"
891#define JAVA_CONST_MODE_STATIC_NAME "MODE_STATIC"
892#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME "mNativeTrackInJavaObj"
893#define JAVA_JNIDATA_FIELD_NAME "mJniData"
894
895#define JAVA_AUDIOFORMAT_CLASS_NAME "android/media/AudioFormat"
896#define JAVA_AUDIOMANAGER_CLASS_NAME "android/media/AudioManager"
897
898// ----------------------------------------------------------------------------
899// preconditions:
900// theClass is valid
901bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
902 const char* constName, int* constVal) {
903 jfieldID javaConst = NULL;
904 javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
905 if (javaConst != NULL) {
906 *constVal = pEnv->GetStaticIntField(theClass, javaConst);
907 return true;
908 } else {
909 LOGE("Can't find %s.%s", className, constName);
910 return false;
911 }
912}
913
914
915// ----------------------------------------------------------------------------
916int register_android_media_AudioTrack(JNIEnv *env)
917{
918 javaAudioTrackFields.audioTrackClass = NULL;
919 javaAudioTrackFields.nativeTrackInJavaObj = NULL;
920 javaAudioTrackFields.postNativeEventInJava = NULL;
921
922 // Get the AudioTrack class
923 javaAudioTrackFields.audioTrackClass = env->FindClass(kClassPathName);
924 if (javaAudioTrackFields.audioTrackClass == NULL) {
925 LOGE("Can't find %s", kClassPathName);
926 return -1;
927 }
928
929 // Get the postEvent method
930 javaAudioTrackFields.postNativeEventInJava = env->GetStaticMethodID(
931 javaAudioTrackFields.audioTrackClass,
932 JAVA_POSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;IIILjava/lang/Object;)V");
933 if (javaAudioTrackFields.postNativeEventInJava == NULL) {
934 LOGE("Can't find AudioTrack.%s", JAVA_POSTEVENT_CALLBACK_NAME);
935 return -1;
936 }
937
938 // Get the variables fields
939 // nativeTrackInJavaObj
940 javaAudioTrackFields.nativeTrackInJavaObj = env->GetFieldID(
941 javaAudioTrackFields.audioTrackClass,
942 JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "I");
943 if (javaAudioTrackFields.nativeTrackInJavaObj == NULL) {
944 LOGE("Can't find AudioTrack.%s", JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME);
945 return -1;
946 }
947 // jniData;
948 javaAudioTrackFields.jniData = env->GetFieldID(
949 javaAudioTrackFields.audioTrackClass,
950 JAVA_JNIDATA_FIELD_NAME, "I");
951 if (javaAudioTrackFields.jniData == NULL) {
952 LOGE("Can't find AudioTrack.%s", JAVA_JNIDATA_FIELD_NAME);
953 return -1;
954 }
955
956 // Get the memory mode constants
957 if ( !android_media_getIntConstantFromClass(env, javaAudioTrackFields.audioTrackClass,
958 kClassPathName,
959 JAVA_CONST_MODE_STATIC_NAME, &(javaAudioTrackFields.MODE_STATIC))
960 || !android_media_getIntConstantFromClass(env, javaAudioTrackFields.audioTrackClass,
961 kClassPathName,
962 JAVA_CONST_MODE_STREAM_NAME, &(javaAudioTrackFields.MODE_STREAM)) ) {
963 // error log performed in android_media_getIntConstantFromClass()
964 return -1;
965 }
966
967 // Get the format constants from the AudioFormat class
968 jclass audioFormatClass = NULL;
969 audioFormatClass = env->FindClass(JAVA_AUDIOFORMAT_CLASS_NAME);
970 if (audioFormatClass == NULL) {
971 LOGE("Can't find %s", JAVA_AUDIOFORMAT_CLASS_NAME);
972 return -1;
973 }
974 if ( !android_media_getIntConstantFromClass(env, audioFormatClass,
975 JAVA_AUDIOFORMAT_CLASS_NAME,
976 JAVA_CONST_PCM16_NAME, &(javaAudioTrackFields.PCM16))
977 || !android_media_getIntConstantFromClass(env, audioFormatClass,
978 JAVA_AUDIOFORMAT_CLASS_NAME,
979 JAVA_CONST_PCM8_NAME, &(javaAudioTrackFields.PCM8)) ) {
980 // error log performed in android_media_getIntConstantFromClass()
981 return -1;
982 }
983
984 // Get the stream types from the AudioManager class
985 jclass audioManagerClass = NULL;
986 audioManagerClass = env->FindClass(JAVA_AUDIOMANAGER_CLASS_NAME);
987 if (audioManagerClass == NULL) {
988 LOGE("Can't find %s", JAVA_AUDIOMANAGER_CLASS_NAME);
989 return -1;
990 }
991 if ( !android_media_getIntConstantFromClass(env, audioManagerClass,
992 JAVA_AUDIOMANAGER_CLASS_NAME,
993 JAVA_CONST_STREAM_VOICE_CALL_NAME, &(javaAudioTrackFields.STREAM_VOICE_CALL))
994 || !android_media_getIntConstantFromClass(env, audioManagerClass,
995 JAVA_AUDIOMANAGER_CLASS_NAME,
996 JAVA_CONST_STREAM_MUSIC_NAME, &(javaAudioTrackFields.STREAM_MUSIC))
997 || !android_media_getIntConstantFromClass(env, audioManagerClass,
998 JAVA_AUDIOMANAGER_CLASS_NAME,
999 JAVA_CONST_STREAM_SYSTEM_NAME, &(javaAudioTrackFields.STREAM_SYSTEM))
1000 || !android_media_getIntConstantFromClass(env, audioManagerClass,
1001 JAVA_AUDIOMANAGER_CLASS_NAME,
1002 JAVA_CONST_STREAM_RING_NAME, &(javaAudioTrackFields.STREAM_RING))
1003 || !android_media_getIntConstantFromClass(env, audioManagerClass,
1004 JAVA_AUDIOMANAGER_CLASS_NAME,
1005 JAVA_CONST_STREAM_ALARM_NAME, &(javaAudioTrackFields.STREAM_ALARM))
1006 || !android_media_getIntConstantFromClass(env, audioManagerClass,
1007 JAVA_AUDIOMANAGER_CLASS_NAME,
1008 JAVA_CONST_STREAM_NOTIFICATION_NAME, &(javaAudioTrackFields.STREAM_NOTIFICATION))
1009 || !android_media_getIntConstantFromClass(env, audioManagerClass,
1010 JAVA_AUDIOMANAGER_CLASS_NAME,
Eric Laurent83b36852009-07-28 07:49:22 -07001011 JAVA_CONST_STREAM_BLUETOOTH_SCO_NAME, &(javaAudioTrackFields.STREAM_BLUETOOTH_SCO))
1012 || !android_media_getIntConstantFromClass(env, audioManagerClass,
1013 JAVA_AUDIOMANAGER_CLASS_NAME,
1014 JAVA_CONST_STREAM_DTMF_NAME, &(javaAudioTrackFields.STREAM_DTMF))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 // error log performed in android_media_getIntConstantFromClass()
1016 return -1;
1017 }
1018
1019 return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
1020}
1021
1022
1023// ----------------------------------------------------------------------------