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