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