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