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