1/*
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 "android_media_AudioTrack.h"
21
22#include <JNIHelp.h>
23#include <JniConstants.h>
24#include "core_jni_helpers.h"
25
26#include "ScopedBytes.h"
27
28#include <utils/Log.h>
29#include <media/AudioSystem.h>
30#include <media/AudioTrack.h>
31#include <audio_utils/primitives.h>
32
33#include <binder/MemoryHeapBase.h>
34#include <binder/MemoryBase.h>
35
36#include "android_media_AudioFormat.h"
37#include "android_media_AudioErrors.h"
38#include "android_media_PlaybackParams.h"
39#include "android_media_DeviceCallback.h"
40
41// ----------------------------------------------------------------------------
42
43using namespace android;
44
45// ----------------------------------------------------------------------------
46static const char* const kClassPathName = "android/media/AudioTrack";
47static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
48
49struct audio_track_fields_t {
50    // these fields provide access from C++ to the...
51    jmethodID postNativeEventInJava; //... event post callback method
52    jfieldID  nativeTrackInJavaObj;  // stores in Java the native AudioTrack object
53    jfieldID  jniData;      // stores in Java additional resources used by the native AudioTrack
54    jfieldID  fieldStreamType; // ... mStreamType field in the AudioTrack Java object
55};
56struct audio_attributes_fields_t {
57    jfieldID  fieldUsage;        // AudioAttributes.mUsage
58    jfieldID  fieldContentType;  // AudioAttributes.mContentType
59    jfieldID  fieldFlags;        // AudioAttributes.mFlags
60    jfieldID  fieldFormattedTags;// AudioAttributes.mFormattedTags
61};
62static audio_track_fields_t      javaAudioTrackFields;
63static audio_attributes_fields_t javaAudioAttrFields;
64static PlaybackParams::fields_t gPlaybackParamsFields;
65
66struct audiotrack_callback_cookie {
67    jclass      audioTrack_class;
68    jobject     audioTrack_ref;
69    bool        busy;
70    Condition   cond;
71};
72
73// keep these values in sync with AudioTrack.java
74#define MODE_STATIC 0
75#define MODE_STREAM 1
76
77// ----------------------------------------------------------------------------
78class AudioTrackJniStorage {
79    public:
80        sp<MemoryHeapBase>         mMemHeap;
81        sp<MemoryBase>             mMemBase;
82        audiotrack_callback_cookie mCallbackData;
83        sp<JNIDeviceCallback>      mDeviceCallback;
84
85    AudioTrackJniStorage() {
86        mCallbackData.audioTrack_class = 0;
87        mCallbackData.audioTrack_ref = 0;
88    }
89
90    ~AudioTrackJniStorage() {
91        mMemBase.clear();
92        mMemHeap.clear();
93    }
94
95    bool allocSharedMem(int sizeInBytes) {
96        mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
97        if (mMemHeap->getHeapID() < 0) {
98            return false;
99        }
100        mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
101        return true;
102    }
103};
104
105static Mutex sLock;
106static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
107
108// ----------------------------------------------------------------------------
109#define DEFAULT_OUTPUT_SAMPLE_RATE   44100
110
111#define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM         -16
112#define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK  -17
113#define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT       -18
114#define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE   -19
115#define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED    -20
116
117// ----------------------------------------------------------------------------
118static void audioCallback(int event, void* user, void *info) {
119
120    audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
121    {
122        Mutex::Autolock l(sLock);
123        if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
124            return;
125        }
126        callbackInfo->busy = true;
127    }
128
129    switch (event) {
130    case AudioTrack::EVENT_MARKER: {
131        JNIEnv *env = AndroidRuntime::getJNIEnv();
132        if (user != NULL && env != NULL) {
133            env->CallStaticVoidMethod(
134                callbackInfo->audioTrack_class,
135                javaAudioTrackFields.postNativeEventInJava,
136                callbackInfo->audioTrack_ref, event, 0,0, NULL);
137            if (env->ExceptionCheck()) {
138                env->ExceptionDescribe();
139                env->ExceptionClear();
140            }
141        }
142        } break;
143
144    case AudioTrack::EVENT_NEW_POS: {
145        JNIEnv *env = AndroidRuntime::getJNIEnv();
146        if (user != NULL && env != NULL) {
147            env->CallStaticVoidMethod(
148                callbackInfo->audioTrack_class,
149                javaAudioTrackFields.postNativeEventInJava,
150                callbackInfo->audioTrack_ref, event, 0,0, NULL);
151            if (env->ExceptionCheck()) {
152                env->ExceptionDescribe();
153                env->ExceptionClear();
154            }
155        }
156        } break;
157    }
158
159    {
160        Mutex::Autolock l(sLock);
161        callbackInfo->busy = false;
162        callbackInfo->cond.broadcast();
163    }
164}
165
166
167// ----------------------------------------------------------------------------
168static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
169{
170    Mutex::Autolock l(sLock);
171    AudioTrack* const at =
172            (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
173    return sp<AudioTrack>(at);
174}
175
176static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
177{
178    Mutex::Autolock l(sLock);
179    sp<AudioTrack> old =
180            (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
181    if (at.get()) {
182        at->incStrong((void*)setAudioTrack);
183    }
184    if (old != 0) {
185        old->decStrong((void*)setAudioTrack);
186    }
187    env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
188    return old;
189}
190
191// ----------------------------------------------------------------------------
192sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
193    return getAudioTrack(env, audioTrackObj);
194}
195
196// This function converts Java channel masks to a native channel mask.
197// validity should be checked with audio_is_output_channel().
198static inline audio_channel_mask_t nativeChannelMaskFromJavaChannelMasks(
199        jint channelPositionMask, jint channelIndexMask)
200{
201    if (channelIndexMask != 0) {  // channel index mask takes priority
202        // To convert to a native channel mask, the Java channel index mask
203        // requires adding the index representation.
204        return audio_channel_mask_from_representation_and_bits(
205                        AUDIO_CHANNEL_REPRESENTATION_INDEX,
206                        channelIndexMask);
207    }
208    // To convert to a native channel mask, the Java channel position mask
209    // requires a shift by 2 to skip the two deprecated channel
210    // configurations "default" and "mono".
211    return (audio_channel_mask_t)(channelPositionMask >> 2);
212}
213
214// ----------------------------------------------------------------------------
215static jint
216android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
217        jobject jaa,
218        jint sampleRateInHertz, jint channelPositionMask, jint channelIndexMask,
219        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession) {
220
221    ALOGV("sampleRate=%d, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d",
222        sampleRateInHertz, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes);
223
224    if (jaa == 0) {
225        ALOGE("Error creating AudioTrack: invalid audio attributes");
226        return (jint) AUDIO_JAVA_ERROR;
227    }
228
229    // Invalid channel representations are caught by !audio_is_output_channel() below.
230    audio_channel_mask_t nativeChannelMask = nativeChannelMaskFromJavaChannelMasks(
231            channelPositionMask, channelIndexMask);
232    if (!audio_is_output_channel(nativeChannelMask)) {
233        ALOGE("Error creating AudioTrack: invalid native channel mask %#x.", nativeChannelMask);
234        return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK;
235    }
236
237    uint32_t channelCount = audio_channel_count_from_out_mask(nativeChannelMask);
238
239    // check the format.
240    // This function was called from Java, so we compare the format against the Java constants
241    audio_format_t format = audioFormatToNative(audioFormat);
242    if (format == AUDIO_FORMAT_INVALID) {
243        ALOGE("Error creating AudioTrack: unsupported audio format %d.", audioFormat);
244        return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT;
245    }
246
247    // compute the frame count
248    size_t frameCount;
249    if (audio_is_linear_pcm(format)) {
250        const size_t bytesPerSample = audio_bytes_per_sample(format);
251        frameCount = buffSizeInBytes / (channelCount * bytesPerSample);
252    } else {
253        frameCount = buffSizeInBytes;
254    }
255
256    jclass clazz = env->GetObjectClass(thiz);
257    if (clazz == NULL) {
258        ALOGE("Can't find %s when setting up callback.", kClassPathName);
259        return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
260    }
261
262    if (jSession == NULL) {
263        ALOGE("Error creating AudioTrack: invalid session ID pointer");
264        return (jint) AUDIO_JAVA_ERROR;
265    }
266
267    jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
268    if (nSession == NULL) {
269        ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
270        return (jint) AUDIO_JAVA_ERROR;
271    }
272    int sessionId = nSession[0];
273    env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
274    nSession = NULL;
275
276    // create the native AudioTrack object
277    sp<AudioTrack> lpTrack = new AudioTrack();
278
279    audio_attributes_t *paa = NULL;
280    // read the AudioAttributes values
281    paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
282    const jstring jtags =
283            (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
284    const char* tags = env->GetStringUTFChars(jtags, NULL);
285    // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
286    strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
287    env->ReleaseStringUTFChars(jtags, tags);
288    paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
289    paa->content_type =
290            (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
291    paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
292
293    ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
294            paa->usage, paa->content_type, paa->flags, paa->tags);
295
296    // initialize the callback information:
297    // this data will be passed with every AudioTrack callback
298    AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();
299    lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
300    // we use a weak reference so the AudioTrack object can be garbage collected.
301    lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
302    lpJniStorage->mCallbackData.busy = false;
303
304    // initialize the native AudioTrack object
305    status_t status = NO_ERROR;
306    switch (memoryMode) {
307    case MODE_STREAM:
308
309        status = lpTrack->set(
310                AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
311                sampleRateInHertz,
312                format,// word length, PCM
313                nativeChannelMask,
314                frameCount,
315                AUDIO_OUTPUT_FLAG_NONE,
316                audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
317                0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
318                0,// shared mem
319                true,// thread can call Java
320                sessionId,// audio session ID
321                AudioTrack::TRANSFER_SYNC,
322                NULL,                         // default offloadInfo
323                -1, -1,                       // default uid, pid values
324                paa);
325        break;
326
327    case MODE_STATIC:
328        // AudioTrack is using shared memory
329
330        if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
331            ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
332            goto native_init_failure;
333        }
334
335        status = lpTrack->set(
336                AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument)
337                sampleRateInHertz,
338                format,// word length, PCM
339                nativeChannelMask,
340                frameCount,
341                AUDIO_OUTPUT_FLAG_NONE,
342                audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
343                0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
344                lpJniStorage->mMemBase,// shared mem
345                true,// thread can call Java
346                sessionId,// audio session ID
347                AudioTrack::TRANSFER_SHARED,
348                NULL,                         // default offloadInfo
349                -1, -1,                       // default uid, pid values
350                paa);
351        break;
352
353    default:
354        ALOGE("Unknown mode %d", memoryMode);
355        goto native_init_failure;
356    }
357
358    if (status != NO_ERROR) {
359        ALOGE("Error %d initializing AudioTrack", status);
360        goto native_init_failure;
361    }
362
363    nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
364    if (nSession == NULL) {
365        ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
366        goto native_init_failure;
367    }
368    // read the audio session ID back from AudioTrack in case we create a new session
369    nSession[0] = lpTrack->getSessionId();
370    env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
371    nSession = NULL;
372
373    {   // scope for the lock
374        Mutex::Autolock l(sLock);
375        sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
376    }
377    // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
378    // of the Java object (in mNativeTrackInJavaObj)
379    setAudioTrack(env, thiz, lpTrack);
380
381    // save the JNI resources so we can free them later
382    //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
383    env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
384
385    // since we had audio attributes, the stream type was derived from them during the
386    // creation of the native AudioTrack: push the same value to the Java object
387    env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
388    // audio attributes were copied in AudioTrack creation
389    free(paa);
390    paa = NULL;
391
392
393    return (jint) AUDIO_JAVA_SUCCESS;
394
395    // failures:
396native_init_failure:
397    if (paa != NULL) {
398        free(paa);
399    }
400    if (nSession != NULL) {
401        env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
402    }
403    env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
404    env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
405    delete lpJniStorage;
406    env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
407
408    // lpTrack goes out of scope, so reference count drops to zero
409    return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
410}
411
412
413// ----------------------------------------------------------------------------
414static void
415android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
416{
417    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
418    if (lpTrack == NULL) {
419        jniThrowException(env, "java/lang/IllegalStateException",
420            "Unable to retrieve AudioTrack pointer for start()");
421        return;
422    }
423
424    lpTrack->start();
425}
426
427
428// ----------------------------------------------------------------------------
429static void
430android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
431{
432    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
433    if (lpTrack == NULL) {
434        jniThrowException(env, "java/lang/IllegalStateException",
435            "Unable to retrieve AudioTrack pointer for stop()");
436        return;
437    }
438
439    lpTrack->stop();
440}
441
442
443// ----------------------------------------------------------------------------
444static void
445android_media_AudioTrack_pause(JNIEnv *env, jobject thiz)
446{
447    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
448    if (lpTrack == NULL) {
449        jniThrowException(env, "java/lang/IllegalStateException",
450            "Unable to retrieve AudioTrack pointer for pause()");
451        return;
452    }
453
454    lpTrack->pause();
455}
456
457
458// ----------------------------------------------------------------------------
459static void
460android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
461{
462    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
463    if (lpTrack == NULL) {
464        jniThrowException(env, "java/lang/IllegalStateException",
465            "Unable to retrieve AudioTrack pointer for flush()");
466        return;
467    }
468
469    lpTrack->flush();
470}
471
472// ----------------------------------------------------------------------------
473static void
474android_media_AudioTrack_set_volume(JNIEnv *env, jobject thiz, jfloat leftVol, jfloat rightVol )
475{
476    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
477    if (lpTrack == NULL) {
478        jniThrowException(env, "java/lang/IllegalStateException",
479            "Unable to retrieve AudioTrack pointer for setVolume()");
480        return;
481    }
482
483    lpTrack->setVolume(leftVol, rightVol);
484}
485
486// ----------------------------------------------------------------------------
487
488#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
489static void android_media_AudioTrack_release(JNIEnv *env,  jobject thiz) {
490    sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
491    if (lpTrack == NULL) {
492        return;
493    }
494    //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
495    lpTrack->stop();
496
497    // delete the JNI data
498    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
499        thiz, javaAudioTrackFields.jniData);
500    // reset the native resources in the Java object so any attempt to access
501    // them after a call to release fails.
502    env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
503
504    if (pJniStorage) {
505        Mutex::Autolock l(sLock);
506        audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
507        //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
508        while (lpCookie->busy) {
509            if (lpCookie->cond.waitRelative(sLock,
510                                            milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
511                                                    NO_ERROR) {
512                break;
513            }
514        }
515        sAudioTrackCallBackCookies.remove(lpCookie);
516        // delete global refs created in native_setup
517        env->DeleteGlobalRef(lpCookie->audioTrack_class);
518        env->DeleteGlobalRef(lpCookie->audioTrack_ref);
519        delete pJniStorage;
520    }
521}
522
523
524// ----------------------------------------------------------------------------
525static void android_media_AudioTrack_finalize(JNIEnv *env,  jobject thiz) {
526    //ALOGV("android_media_AudioTrack_finalize jobject: %x\n", (int)thiz);
527    android_media_AudioTrack_release(env, thiz);
528}
529
530// overloaded JNI array helper functions (same as in android_media_AudioRecord)
531static inline
532jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
533    return env->GetByteArrayElements(array, isCopy);
534}
535
536static inline
537void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
538    env->ReleaseByteArrayElements(array, elems, mode);
539}
540
541static inline
542jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
543    return env->GetShortArrayElements(array, isCopy);
544}
545
546static inline
547void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
548    env->ReleaseShortArrayElements(array, elems, mode);
549}
550
551static inline
552jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
553    return env->GetFloatArrayElements(array, isCopy);
554}
555
556static inline
557void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
558    env->ReleaseFloatArrayElements(array, elems, mode);
559}
560
561// ----------------------------------------------------------------------------
562template <typename T>
563static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
564                         jint offsetInSamples, jint sizeInSamples, bool blocking) {
565    // give the data to the native AudioTrack object (the data starts at the offset)
566    ssize_t written = 0;
567    // regular write() or copy the data to the AudioTrack's shared memory?
568    size_t sizeInBytes = sizeInSamples * sizeof(T);
569    if (track->sharedBuffer() == 0) {
570        written = track->write(data + offsetInSamples, sizeInBytes, blocking);
571        // for compatibility with earlier behavior of write(), return 0 in this case
572        if (written == (ssize_t) WOULD_BLOCK) {
573            written = 0;
574        }
575    } else {
576        // writing to shared memory, check for capacity
577        if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
578            sizeInBytes = track->sharedBuffer()->size();
579        }
580        memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
581        written = sizeInBytes;
582    }
583    if (written > 0) {
584        return written / sizeof(T);
585    }
586    // for compatibility, error codes pass through unchanged
587    return written;
588}
589
590// ----------------------------------------------------------------------------
591template <typename T>
592static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
593                                                T javaAudioData,
594                                                jint offsetInSamples, jint sizeInSamples,
595                                                jint javaAudioFormat,
596                                                jboolean isWriteBlocking) {
597    //ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
598    //        offsetInSamples, sizeInSamples);
599    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
600    if (lpTrack == NULL) {
601        jniThrowException(env, "java/lang/IllegalStateException",
602            "Unable to retrieve AudioTrack pointer for write()");
603        return (jint)AUDIO_JAVA_INVALID_OPERATION;
604    }
605
606    if (javaAudioData == NULL) {
607        ALOGE("NULL java array of audio data to play");
608        return (jint)AUDIO_JAVA_BAD_VALUE;
609    }
610
611    // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
612    // a way that it becomes much more efficient. When doing so, we will have to prevent the
613    // AudioSystem callback to be called while in critical section (in case of media server
614    // process crash for instance)
615
616    // get the pointer for the audio data from the java array
617    auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
618    if (cAudioData == NULL) {
619        ALOGE("Error retrieving source of audio data to play");
620        return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
621    }
622
623    jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
624            offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
625
626    envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
627
628    //ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
629    //        (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
630    return samplesWritten;
631}
632
633// ----------------------------------------------------------------------------
634static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env,  jobject thiz,
635        jbyteArray javaBytes, jint byteOffset, jint sizeInBytes,
636        jint javaAudioFormat, jboolean isWriteBlocking) {
637    //ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
638    //    offsetInBytes, sizeInBytes);
639    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
640    if (lpTrack == NULL) {
641        jniThrowException(env, "java/lang/IllegalStateException",
642                "Unable to retrieve AudioTrack pointer for write()");
643        return (jint)AUDIO_JAVA_INVALID_OPERATION;
644    }
645
646    ScopedBytesRO bytes(env, javaBytes);
647    if (bytes.get() == NULL) {
648        ALOGE("Error retrieving source of audio data to play, can't play");
649        return (jint)AUDIO_JAVA_BAD_VALUE;
650    }
651
652    jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
653            sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
654
655    return written;
656}
657
658// ----------------------------------------------------------------------------
659static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env,  jobject thiz) {
660    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
661    if (lpTrack == NULL) {
662        jniThrowException(env, "java/lang/IllegalStateException",
663            "Unable to retrieve AudioTrack pointer for frameCount()");
664        return (jint)AUDIO_JAVA_ERROR;
665    }
666
667    return lpTrack->frameCount();
668}
669
670
671// ----------------------------------------------------------------------------
672static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env,  jobject thiz,
673        jint sampleRateInHz) {
674    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
675    if (lpTrack == NULL) {
676        jniThrowException(env, "java/lang/IllegalStateException",
677            "Unable to retrieve AudioTrack pointer for setSampleRate()");
678        return (jint)AUDIO_JAVA_ERROR;
679    }
680    return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
681}
682
683
684// ----------------------------------------------------------------------------
685static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env,  jobject thiz) {
686    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
687    if (lpTrack == NULL) {
688        jniThrowException(env, "java/lang/IllegalStateException",
689            "Unable to retrieve AudioTrack pointer for getSampleRate()");
690        return (jint)AUDIO_JAVA_ERROR;
691    }
692    return (jint) lpTrack->getSampleRate();
693}
694
695
696// ----------------------------------------------------------------------------
697static void android_media_AudioTrack_set_playback_params(JNIEnv *env,  jobject thiz,
698        jobject params) {
699    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
700    if (lpTrack == NULL) {
701        jniThrowException(env, "java/lang/IllegalStateException",
702            "AudioTrack not initialized");
703        return;
704    }
705
706    PlaybackParams pbp;
707    pbp.fillFromJobject(env, gPlaybackParamsFields, params);
708
709    ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
710            pbp.speedSet, pbp.audioRate.mSpeed,
711            pbp.pitchSet, pbp.audioRate.mPitch,
712            pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
713            pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
714
715    // to simulate partially set params, we do a read-modify-write.
716    // TODO: pass in the valid set mask into AudioTrack.
717    AudioPlaybackRate rate = lpTrack->getPlaybackRate();
718    bool updatedRate = false;
719    if (pbp.speedSet) {
720        rate.mSpeed = pbp.audioRate.mSpeed;
721        updatedRate = true;
722    }
723    if (pbp.pitchSet) {
724        rate.mPitch = pbp.audioRate.mPitch;
725        updatedRate = true;
726    }
727    if (pbp.audioFallbackModeSet) {
728        rate.mFallbackMode = pbp.audioRate.mFallbackMode;
729        updatedRate = true;
730    }
731    if (pbp.audioStretchModeSet) {
732        rate.mStretchMode = pbp.audioRate.mStretchMode;
733        updatedRate = true;
734    }
735    if (updatedRate) {
736        if (lpTrack->setPlaybackRate(rate) != OK) {
737            jniThrowException(env, "java/lang/IllegalArgumentException",
738                    "arguments out of range");
739        }
740    }
741}
742
743
744// ----------------------------------------------------------------------------
745static jobject android_media_AudioTrack_get_playback_params(JNIEnv *env,  jobject thiz,
746        jobject params) {
747    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
748    if (lpTrack == NULL) {
749        jniThrowException(env, "java/lang/IllegalStateException",
750            "AudioTrack not initialized");
751        return NULL;
752    }
753
754    PlaybackParams pbs;
755    pbs.audioRate = lpTrack->getPlaybackRate();
756    pbs.speedSet = true;
757    pbs.pitchSet = true;
758    pbs.audioFallbackModeSet = true;
759    pbs.audioStretchModeSet = true;
760    return pbs.asJobject(env, gPlaybackParamsFields);
761}
762
763
764// ----------------------------------------------------------------------------
765static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env,  jobject thiz,
766        jint markerPos) {
767    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
768    if (lpTrack == NULL) {
769        jniThrowException(env, "java/lang/IllegalStateException",
770            "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
771        return (jint)AUDIO_JAVA_ERROR;
772    }
773    return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
774}
775
776
777// ----------------------------------------------------------------------------
778static jint android_media_AudioTrack_get_marker_pos(JNIEnv *env,  jobject thiz) {
779    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
780    uint32_t markerPos = 0;
781
782    if (lpTrack == NULL) {
783        jniThrowException(env, "java/lang/IllegalStateException",
784            "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
785        return (jint)AUDIO_JAVA_ERROR;
786    }
787    lpTrack->getMarkerPosition(&markerPos);
788    return (jint)markerPos;
789}
790
791
792// ----------------------------------------------------------------------------
793static jint android_media_AudioTrack_set_pos_update_period(JNIEnv *env,  jobject thiz,
794        jint period) {
795    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
796    if (lpTrack == NULL) {
797        jniThrowException(env, "java/lang/IllegalStateException",
798            "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
799        return (jint)AUDIO_JAVA_ERROR;
800    }
801    return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
802}
803
804
805// ----------------------------------------------------------------------------
806static jint android_media_AudioTrack_get_pos_update_period(JNIEnv *env,  jobject thiz) {
807    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
808    uint32_t period = 0;
809
810    if (lpTrack == NULL) {
811        jniThrowException(env, "java/lang/IllegalStateException",
812            "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
813        return (jint)AUDIO_JAVA_ERROR;
814    }
815    lpTrack->getPositionUpdatePeriod(&period);
816    return (jint)period;
817}
818
819
820// ----------------------------------------------------------------------------
821static jint android_media_AudioTrack_set_position(JNIEnv *env,  jobject thiz,
822        jint position) {
823    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
824    if (lpTrack == NULL) {
825        jniThrowException(env, "java/lang/IllegalStateException",
826            "Unable to retrieve AudioTrack pointer for setPosition()");
827        return (jint)AUDIO_JAVA_ERROR;
828    }
829    return nativeToJavaStatus( lpTrack->setPosition(position) );
830}
831
832
833// ----------------------------------------------------------------------------
834static jint android_media_AudioTrack_get_position(JNIEnv *env,  jobject thiz) {
835    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
836    uint32_t position = 0;
837
838    if (lpTrack == NULL) {
839        jniThrowException(env, "java/lang/IllegalStateException",
840            "Unable to retrieve AudioTrack pointer for getPosition()");
841        return (jint)AUDIO_JAVA_ERROR;
842    }
843    lpTrack->getPosition(&position);
844    return (jint)position;
845}
846
847
848// ----------------------------------------------------------------------------
849static jint android_media_AudioTrack_get_latency(JNIEnv *env,  jobject thiz) {
850    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
851
852    if (lpTrack == NULL) {
853        jniThrowException(env, "java/lang/IllegalStateException",
854            "Unable to retrieve AudioTrack pointer for latency()");
855        return (jint)AUDIO_JAVA_ERROR;
856    }
857    return (jint)lpTrack->latency();
858}
859
860
861// ----------------------------------------------------------------------------
862static jint android_media_AudioTrack_get_timestamp(JNIEnv *env,  jobject thiz, jlongArray jTimestamp) {
863    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
864
865    if (lpTrack == NULL) {
866        ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
867        return (jint)AUDIO_JAVA_ERROR;
868    }
869    AudioTimestamp timestamp;
870    status_t status = lpTrack->getTimestamp(timestamp);
871    if (status == OK) {
872        jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
873        if (nTimestamp == NULL) {
874            ALOGE("Unable to get array for getTimestamp()");
875            return (jint)AUDIO_JAVA_ERROR;
876        }
877        nTimestamp[0] = (jlong) timestamp.mPosition;
878        nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
879        env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
880    }
881    return (jint) nativeToJavaStatus(status);
882}
883
884
885// ----------------------------------------------------------------------------
886static jint android_media_AudioTrack_set_loop(JNIEnv *env,  jobject thiz,
887        jint loopStart, jint loopEnd, jint loopCount) {
888    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
889    if (lpTrack == NULL) {
890        jniThrowException(env, "java/lang/IllegalStateException",
891            "Unable to retrieve AudioTrack pointer for setLoop()");
892        return (jint)AUDIO_JAVA_ERROR;
893    }
894    return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
895}
896
897
898// ----------------------------------------------------------------------------
899static jint android_media_AudioTrack_reload(JNIEnv *env,  jobject thiz) {
900    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
901    if (lpTrack == NULL) {
902        jniThrowException(env, "java/lang/IllegalStateException",
903            "Unable to retrieve AudioTrack pointer for reload()");
904        return (jint)AUDIO_JAVA_ERROR;
905    }
906    return nativeToJavaStatus( lpTrack->reload() );
907}
908
909
910// ----------------------------------------------------------------------------
911static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env,  jobject thiz,
912        jint javaStreamType) {
913    uint32_t afSamplingRate;
914    // convert the stream type from Java to native value
915    // FIXME: code duplication with android_media_AudioTrack_setup()
916    audio_stream_type_t nativeStreamType;
917    switch (javaStreamType) {
918    case AUDIO_STREAM_VOICE_CALL:
919    case AUDIO_STREAM_SYSTEM:
920    case AUDIO_STREAM_RING:
921    case AUDIO_STREAM_MUSIC:
922    case AUDIO_STREAM_ALARM:
923    case AUDIO_STREAM_NOTIFICATION:
924    case AUDIO_STREAM_BLUETOOTH_SCO:
925    case AUDIO_STREAM_DTMF:
926        nativeStreamType = (audio_stream_type_t) javaStreamType;
927        break;
928    default:
929        nativeStreamType = AUDIO_STREAM_DEFAULT;
930        break;
931    }
932
933    status_t status = AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType);
934    if (status != NO_ERROR) {
935        ALOGE("Error %d in AudioSystem::getOutputSamplingRate() for stream type %d "
936              "in AudioTrack JNI", status, nativeStreamType);
937        return DEFAULT_OUTPUT_SAMPLE_RATE;
938    } else {
939        return afSamplingRate;
940    }
941}
942
943
944// ----------------------------------------------------------------------------
945// returns the minimum required size for the successful creation of a streaming AudioTrack
946// returns -1 if there was an error querying the hardware.
947static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env,  jobject thiz,
948    jint sampleRateInHertz, jint channelCount, jint audioFormat) {
949
950    size_t frameCount;
951    const status_t status = AudioTrack::getMinFrameCount(&frameCount, AUDIO_STREAM_DEFAULT,
952            sampleRateInHertz);
953    if (status != NO_ERROR) {
954        ALOGE("AudioTrack::getMinFrameCount() for sample rate %d failed with status %d",
955                sampleRateInHertz, status);
956        return -1;
957    }
958    const audio_format_t format = audioFormatToNative(audioFormat);
959    if (audio_is_linear_pcm(format)) {
960        const size_t bytesPerSample = audio_bytes_per_sample(format);
961        return frameCount * channelCount * bytesPerSample;
962    } else {
963        return frameCount;
964    }
965}
966
967// ----------------------------------------------------------------------------
968static jint
969android_media_AudioTrack_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level )
970{
971    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
972    if (lpTrack == NULL ) {
973        jniThrowException(env, "java/lang/IllegalStateException",
974            "Unable to retrieve AudioTrack pointer for setAuxEffectSendLevel()");
975        return -1;
976    }
977
978    status_t status = lpTrack->setAuxEffectSendLevel(level);
979    if (status != NO_ERROR) {
980        ALOGE("AudioTrack::setAuxEffectSendLevel() for level %g failed with status %d",
981                level, status);
982    }
983    return (jint) status;
984}
985
986// ----------------------------------------------------------------------------
987static jint android_media_AudioTrack_attachAuxEffect(JNIEnv *env,  jobject thiz,
988        jint effectId) {
989    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
990    if (lpTrack == NULL) {
991        jniThrowException(env, "java/lang/IllegalStateException",
992            "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
993        return (jint)AUDIO_JAVA_ERROR;
994    }
995    return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
996}
997
998static jboolean android_media_AudioTrack_setOutputDevice(
999                JNIEnv *env,  jobject thiz, jint device_id) {
1000
1001    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1002    if (lpTrack == 0) {
1003        return false;
1004    }
1005    return lpTrack->setOutputDevice(device_id) == NO_ERROR;
1006}
1007
1008static jint android_media_AudioTrack_getRoutedDeviceId(
1009                JNIEnv *env,  jobject thiz) {
1010
1011    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1012    if (lpTrack == NULL) {
1013        return 0;
1014    }
1015    return (jint)lpTrack->getRoutedDeviceId();
1016}
1017
1018static void android_media_AudioTrack_enableDeviceCallback(
1019                JNIEnv *env,  jobject thiz) {
1020
1021    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1022    if (lpTrack == NULL) {
1023        return;
1024    }
1025    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1026        thiz, javaAudioTrackFields.jniData);
1027    if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
1028        return;
1029    }
1030    pJniStorage->mDeviceCallback =
1031    new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
1032                          javaAudioTrackFields.postNativeEventInJava);
1033    lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
1034}
1035
1036static void android_media_AudioTrack_disableDeviceCallback(
1037                JNIEnv *env,  jobject thiz) {
1038
1039    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
1040    if (lpTrack == NULL) {
1041        return;
1042    }
1043    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
1044        thiz, javaAudioTrackFields.jniData);
1045    if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
1046        return;
1047    }
1048    lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
1049    pJniStorage->mDeviceCallback.clear();
1050}
1051
1052
1053// ----------------------------------------------------------------------------
1054// ----------------------------------------------------------------------------
1055static JNINativeMethod gMethods[] = {
1056    // name,              signature,     funcPtr
1057    {"native_start",         "()V",      (void *)android_media_AudioTrack_start},
1058    {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
1059    {"native_pause",         "()V",      (void *)android_media_AudioTrack_pause},
1060    {"native_flush",         "()V",      (void *)android_media_AudioTrack_flush},
1061    {"native_setup",     "(Ljava/lang/Object;Ljava/lang/Object;IIIIII[I)I",
1062                                         (void *)android_media_AudioTrack_setup},
1063    {"native_finalize",      "()V",      (void *)android_media_AudioTrack_finalize},
1064    {"native_release",       "()V",      (void *)android_media_AudioTrack_release},
1065    {"native_write_byte",    "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
1066    {"native_write_native_bytes",
1067                             "(Ljava/lang/Object;IIIZ)I",
1068                                         (void *)android_media_AudioTrack_write_native_bytes},
1069    {"native_write_short",   "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
1070    {"native_write_float",   "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
1071    {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
1072    {"native_get_native_frame_count",
1073                             "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
1074    {"native_set_playback_rate",
1075                             "(I)I",     (void *)android_media_AudioTrack_set_playback_rate},
1076    {"native_get_playback_rate",
1077                             "()I",      (void *)android_media_AudioTrack_get_playback_rate},
1078    {"native_set_playback_params",
1079                             "(Landroid/media/PlaybackParams;)V",
1080                                         (void *)android_media_AudioTrack_set_playback_params},
1081    {"native_get_playback_params",
1082                             "()Landroid/media/PlaybackParams;",
1083                                         (void *)android_media_AudioTrack_get_playback_params},
1084    {"native_set_marker_pos","(I)I",     (void *)android_media_AudioTrack_set_marker_pos},
1085    {"native_get_marker_pos","()I",      (void *)android_media_AudioTrack_get_marker_pos},
1086    {"native_set_pos_update_period",
1087                             "(I)I",     (void *)android_media_AudioTrack_set_pos_update_period},
1088    {"native_get_pos_update_period",
1089                             "()I",      (void *)android_media_AudioTrack_get_pos_update_period},
1090    {"native_set_position",  "(I)I",     (void *)android_media_AudioTrack_set_position},
1091    {"native_get_position",  "()I",      (void *)android_media_AudioTrack_get_position},
1092    {"native_get_latency",   "()I",      (void *)android_media_AudioTrack_get_latency},
1093    {"native_get_timestamp", "([J)I",    (void *)android_media_AudioTrack_get_timestamp},
1094    {"native_set_loop",      "(III)I",   (void *)android_media_AudioTrack_set_loop},
1095    {"native_reload_static", "()I",      (void *)android_media_AudioTrack_reload},
1096    {"native_get_output_sample_rate",
1097                             "(I)I",      (void *)android_media_AudioTrack_get_output_sample_rate},
1098    {"native_get_min_buff_size",
1099                             "(III)I",   (void *)android_media_AudioTrack_get_min_buff_size},
1100    {"native_setAuxEffectSendLevel",
1101                             "(F)I",     (void *)android_media_AudioTrack_setAuxEffectSendLevel},
1102    {"native_attachAuxEffect",
1103                             "(I)I",     (void *)android_media_AudioTrack_attachAuxEffect},
1104    {"native_setOutputDevice", "(I)Z",
1105                             (void *)android_media_AudioTrack_setOutputDevice},
1106    {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
1107    {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
1108    {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
1109};
1110
1111
1112// field names found in android/media/AudioTrack.java
1113#define JAVA_POSTEVENT_CALLBACK_NAME                    "postEventFromNative"
1114#define JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME            "mNativeTrackInJavaObj"
1115#define JAVA_JNIDATA_FIELD_NAME                         "mJniData"
1116#define JAVA_STREAMTYPE_FIELD_NAME                      "mStreamType"
1117
1118// ----------------------------------------------------------------------------
1119// preconditions:
1120//    theClass is valid
1121bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const char* className,
1122                             const char* constName, int* constVal) {
1123    jfieldID javaConst = NULL;
1124    javaConst = pEnv->GetStaticFieldID(theClass, constName, "I");
1125    if (javaConst != NULL) {
1126        *constVal = pEnv->GetStaticIntField(theClass, javaConst);
1127        return true;
1128    } else {
1129        ALOGE("Can't find %s.%s", className, constName);
1130        return false;
1131    }
1132}
1133
1134
1135// ----------------------------------------------------------------------------
1136int register_android_media_AudioTrack(JNIEnv *env)
1137{
1138    javaAudioTrackFields.nativeTrackInJavaObj = NULL;
1139    javaAudioTrackFields.postNativeEventInJava = NULL;
1140
1141    // Get the AudioTrack class
1142    jclass audioTrackClass = FindClassOrDie(env, kClassPathName);
1143
1144    // Get the postEvent method
1145    javaAudioTrackFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
1146            audioTrackClass, JAVA_POSTEVENT_CALLBACK_NAME,
1147            "(Ljava/lang/Object;IIILjava/lang/Object;)V");
1148
1149    // Get the variables fields
1150    //      nativeTrackInJavaObj
1151    javaAudioTrackFields.nativeTrackInJavaObj = GetFieldIDOrDie(env,
1152            audioTrackClass, JAVA_NATIVETRACKINJAVAOBJ_FIELD_NAME, "J");
1153    //      jniData
1154    javaAudioTrackFields.jniData = GetFieldIDOrDie(env,
1155            audioTrackClass, JAVA_JNIDATA_FIELD_NAME, "J");
1156    //      fieldStreamType
1157    javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
1158            audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
1159
1160    env->DeleteLocalRef(audioTrackClass);
1161
1162    // Get the AudioAttributes class and fields
1163    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
1164    javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
1165    javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
1166            audioAttrClass, "mContentType", "I");
1167    javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
1168    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
1169            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
1170
1171    env->DeleteLocalRef(audioAttrClass);
1172
1173    // initialize PlaybackParams field info
1174    gPlaybackParamsFields.init(env);
1175
1176    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
1177}
1178
1179
1180// ----------------------------------------------------------------------------
1181