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