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 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "JET_JNI"
     19 
     20 
     21 #include <stdio.h>
     22 #include <unistd.h>
     23 #include <fcntl.h>
     24 
     25 #include <jni.h>
     26 #include <nativehelper/JNIHelp.h>
     27 #include "core_jni_helpers.h"
     28 
     29 #include <utils/Log.h>
     30 #include <media/JetPlayer.h>
     31 
     32 
     33 using namespace android;
     34 
     35 // ----------------------------------------------------------------------------
     36 static const char* const kClassPathName = "android/media/JetPlayer";
     37 
     38 // ----------------------------------------------------------------------------
     39 struct fields_t {
     40     // these fields provide access from C++ to the...
     41     jclass    jetClass;              // JetPlayer java class global ref
     42     jmethodID postNativeEventInJava; // java method to post events to the Java thread from native
     43     jfieldID  nativePlayerInJavaObj; // stores in Java the native JetPlayer object
     44 };
     45 
     46 static fields_t javaJetPlayerFields;
     47 
     48 
     49 // ----------------------------------------------------------------------------
     50 // ----------------------------------------------------------------------------
     51 
     52 /*
     53  * This function is called from JetPlayer instance's render thread
     54  */
     55 static void
     56 jetPlayerEventCallback(int what, int arg1=0, int arg2=0, void* javaTarget = NULL)
     57 {
     58     JNIEnv *env = AndroidRuntime::getJNIEnv();
     59     if (env) {
     60         env->CallStaticVoidMethod(
     61             javaJetPlayerFields.jetClass, javaJetPlayerFields.postNativeEventInJava,
     62             javaTarget,
     63             what, arg1, arg2);
     64         if (env->ExceptionCheck()) {
     65             env->ExceptionDescribe();
     66             env->ExceptionClear();
     67         }
     68     } else {
     69         ALOGE("JET jetPlayerEventCallback(): No JNI env for JET event callback, can't post event.");
     70         return;
     71     }
     72 }
     73 
     74 
     75 // ----------------------------------------------------------------------------
     76 // ----------------------------------------------------------------------------
     77 
     78 static jboolean
     79 android_media_JetPlayer_setup(JNIEnv *env, jobject thiz, jobject weak_this,
     80     jint maxTracks, jint trackBufferSize)
     81 {
     82     //ALOGV("android_media_JetPlayer_setup(): entering.");
     83     JetPlayer* lpJet = new JetPlayer(env->NewGlobalRef(weak_this), maxTracks, trackBufferSize);
     84 
     85     EAS_RESULT result = lpJet->init();
     86 
     87     if (result==EAS_SUCCESS) {
     88         // save our newly created C++ JetPlayer in the "nativePlayerInJavaObj" field
     89         // of the Java object (in mNativePlayerInJavaObj)
     90         env->SetLongField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, (jlong)lpJet);
     91         return JNI_TRUE;
     92     } else {
     93         ALOGE("android_media_JetPlayer_setup(): initialization failed with EAS error code %d", (int)result);
     94         delete lpJet;
     95         env->SetLongField(weak_this, javaJetPlayerFields.nativePlayerInJavaObj, 0);
     96         return JNI_FALSE;
     97     }
     98 }
     99 
    100 
    101 // ----------------------------------------------------------------------------
    102 static void
    103 android_media_JetPlayer_finalize(JNIEnv *env, jobject thiz)
    104 {
    105     ALOGV("android_media_JetPlayer_finalize(): entering.");
    106     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    107         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    108     if (lpJet != NULL) {
    109         lpJet->release();
    110         delete lpJet;
    111     }
    112 
    113     ALOGV("android_media_JetPlayer_finalize(): exiting.");
    114 }
    115 
    116 
    117 // ----------------------------------------------------------------------------
    118 static void
    119 android_media_JetPlayer_release(JNIEnv *env, jobject thiz)
    120 {
    121     android_media_JetPlayer_finalize(env, thiz);
    122     env->SetLongField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, 0);
    123     ALOGV("android_media_JetPlayer_release() done");
    124 }
    125 
    126 
    127 // ----------------------------------------------------------------------------
    128 static jboolean
    129 android_media_JetPlayer_loadFromFile(JNIEnv *env, jobject thiz, jstring path)
    130 {
    131     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    132         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    133     if (lpJet == NULL) {
    134         jniThrowException(env, "java/lang/IllegalStateException",
    135             "Unable to retrieve JetPlayer pointer for openFile()");
    136         return JNI_FALSE;
    137     }
    138 
    139     // set up event callback function
    140     lpJet->setEventCallback(jetPlayerEventCallback);
    141 
    142     const char *pathStr = env->GetStringUTFChars(path, NULL);
    143     if (pathStr == NULL) {  // Out of memory
    144         ALOGE("android_media_JetPlayer_openFile(): aborting, out of memory");
    145         return JNI_FALSE;
    146     }
    147 
    148     ALOGV("android_media_JetPlayer_openFile(): trying to open %s", pathStr );
    149     EAS_RESULT result = lpJet->loadFromFile(pathStr);
    150     env->ReleaseStringUTFChars(path, pathStr);
    151 
    152     if (result==EAS_SUCCESS) {
    153         //ALOGV("android_media_JetPlayer_openFile(): file successfully opened");
    154         return JNI_TRUE;
    155     } else {
    156         ALOGE("android_media_JetPlayer_openFile(): failed to open file with EAS error %d",
    157             (int)result);
    158         return JNI_FALSE;
    159     }
    160 }
    161 
    162 
    163 // ----------------------------------------------------------------------------
    164 static jboolean
    165 android_media_JetPlayer_loadFromFileD(JNIEnv *env, jobject thiz,
    166     jobject fileDescriptor, jlong offset, jlong length)
    167 {
    168     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    169         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    170     if (lpJet == NULL) {
    171         jniThrowException(env, "java/lang/IllegalStateException",
    172             "Unable to retrieve JetPlayer pointer for openFile()");
    173         return JNI_FALSE;
    174     }
    175 
    176     // set up event callback function
    177     lpJet->setEventCallback(jetPlayerEventCallback);
    178 
    179     ALOGV("android_media_JetPlayer_openFileDescr(): trying to load JET file through its fd" );
    180     EAS_RESULT result = lpJet->loadFromFD(jniGetFDFromFileDescriptor(env, fileDescriptor),
    181         (long long)offset, (long long)length); // cast params to types used by EAS_FILE
    182 
    183     if (result==EAS_SUCCESS) {
    184         ALOGV("android_media_JetPlayer_openFileDescr(): file successfully opened");
    185         return JNI_TRUE;
    186     } else {
    187         ALOGE("android_media_JetPlayer_openFileDescr(): failed to open file with EAS error %d",
    188             (int)result);
    189         return JNI_FALSE;
    190     }
    191 }
    192 
    193 
    194 // ----------------------------------------------------------------------------
    195 static jboolean
    196 android_media_JetPlayer_closeFile(JNIEnv *env, jobject thiz)
    197 {
    198     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    199         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    200     if (lpJet == NULL) {
    201         jniThrowException(env, "java/lang/IllegalStateException",
    202             "Unable to retrieve JetPlayer pointer for closeFile()");
    203         return JNI_FALSE;
    204     }
    205 
    206     if (lpJet->closeFile()==EAS_SUCCESS) {
    207         //ALOGV("android_media_JetPlayer_closeFile(): file successfully closed");
    208         return JNI_TRUE;
    209     } else {
    210         ALOGE("android_media_JetPlayer_closeFile(): failed to close file");
    211         return JNI_FALSE;
    212     }
    213 }
    214 
    215 
    216 // ----------------------------------------------------------------------------
    217 static jboolean
    218 android_media_JetPlayer_play(JNIEnv *env, jobject thiz)
    219 {
    220     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    221         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    222     if (lpJet == NULL) {
    223         jniThrowException(env, "java/lang/IllegalStateException",
    224             "Unable to retrieve JetPlayer pointer for play()");
    225         return JNI_FALSE;
    226     }
    227 
    228     EAS_RESULT result = lpJet->play();
    229     if (result==EAS_SUCCESS) {
    230         //ALOGV("android_media_JetPlayer_play(): play successful");
    231         return JNI_TRUE;
    232     } else {
    233         ALOGE("android_media_JetPlayer_play(): failed to play with EAS error code %ld",
    234             result);
    235         return JNI_FALSE;
    236     }
    237 }
    238 
    239 
    240 // ----------------------------------------------------------------------------
    241 static jboolean
    242 android_media_JetPlayer_pause(JNIEnv *env, jobject thiz)
    243 {
    244     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    245         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    246     if (lpJet == NULL) {
    247         jniThrowException(env, "java/lang/IllegalStateException",
    248             "Unable to retrieve JetPlayer pointer for pause()");
    249         return JNI_FALSE;
    250     }
    251 
    252     EAS_RESULT result = lpJet->pause();
    253     if (result==EAS_SUCCESS) {
    254         //ALOGV("android_media_JetPlayer_pause(): pause successful");
    255         return JNI_TRUE;
    256     } else {
    257         if (result==EAS_ERROR_QUEUE_IS_EMPTY) {
    258             ALOGV("android_media_JetPlayer_pause(): paused with an empty queue");
    259             return JNI_TRUE;
    260         } else
    261             ALOGE("android_media_JetPlayer_pause(): failed to pause with EAS error code %ld",
    262                 result);
    263         return JNI_FALSE;
    264     }
    265 }
    266 
    267 
    268 // ----------------------------------------------------------------------------
    269 static jboolean
    270 android_media_JetPlayer_queueSegment(JNIEnv *env, jobject thiz,
    271         jint segmentNum, jint libNum, jint repeatCount, jint transpose, jint muteFlags,
    272         jbyte userID)
    273 {
    274     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    275         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    276     if (lpJet == NULL) {
    277         jniThrowException(env, "java/lang/IllegalStateException",
    278             "Unable to retrieve JetPlayer pointer for queueSegment()");
    279         return JNI_FALSE;
    280     }
    281 
    282     EAS_RESULT result
    283         = lpJet->queueSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
    284     if (result==EAS_SUCCESS) {
    285         //ALOGV("android_media_JetPlayer_queueSegment(): segment successfully queued");
    286         return JNI_TRUE;
    287     } else {
    288         ALOGE("android_media_JetPlayer_queueSegment(): failed with EAS error code %ld",
    289             result);
    290         return JNI_FALSE;
    291     }
    292 }
    293 
    294 
    295 // ----------------------------------------------------------------------------
    296 static jboolean
    297 android_media_JetPlayer_queueSegmentMuteArray(JNIEnv *env, jobject thiz,
    298         jint segmentNum, jint libNum, jint repeatCount, jint transpose, jbooleanArray muteArray,
    299         jbyte userID)
    300 {
    301     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    302         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    303     if (lpJet == NULL) {
    304         jniThrowException(env, "java/lang/IllegalStateException",
    305             "Unable to retrieve JetPlayer pointer for queueSegmentMuteArray()");
    306         return JNI_FALSE;
    307     }
    308 
    309     EAS_RESULT result=EAS_FAILURE;
    310 
    311     jboolean *muteTracks = NULL;
    312     muteTracks = env->GetBooleanArrayElements(muteArray, NULL);
    313     if (muteTracks == NULL) {
    314         ALOGE("android_media_JetPlayer_queueSegment(): failed to read track mute mask.");
    315         return JNI_FALSE;
    316     }
    317 
    318     EAS_U32 muteMask=0;
    319     int maxTracks = lpJet->getMaxTracks();
    320     for (jint trackIndex=0; trackIndex<maxTracks; trackIndex++) {
    321         if (muteTracks[maxTracks-1-trackIndex]==JNI_TRUE)
    322             muteMask = (muteMask << 1) | 0x00000001;
    323         else
    324             muteMask = muteMask << 1;
    325     }
    326     //ALOGV("android_media_JetPlayer_queueSegmentMuteArray(): FINAL mute mask =0x%08lX", mask);
    327 
    328     result = lpJet->queueSegment(segmentNum, libNum, repeatCount, transpose, muteMask, userID);
    329 
    330     env->ReleaseBooleanArrayElements(muteArray, muteTracks, 0);
    331     if (result==EAS_SUCCESS) {
    332         //ALOGV("android_media_JetPlayer_queueSegmentMuteArray(): segment successfully queued");
    333         return JNI_TRUE;
    334     } else {
    335         ALOGE("android_media_JetPlayer_queueSegmentMuteArray(): failed with EAS error code %ld",
    336             result);
    337         return JNI_FALSE;
    338     }
    339 }
    340 
    341 
    342 // ----------------------------------------------------------------------------
    343 static jboolean
    344 android_media_JetPlayer_setMuteFlags(JNIEnv *env, jobject thiz,
    345          jint muteFlags /*unsigned?*/, jboolean bSync)
    346 {
    347     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    348         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    349     if (lpJet == NULL) {
    350         jniThrowException(env, "java/lang/IllegalStateException",
    351             "Unable to retrieve JetPlayer pointer for setMuteFlags()");
    352         return JNI_FALSE;
    353     }
    354 
    355     EAS_RESULT result;
    356     result = lpJet->setMuteFlags(muteFlags, bSync==JNI_TRUE ? true : false);
    357     if (result==EAS_SUCCESS) {
    358         //ALOGV("android_media_JetPlayer_setMuteFlags(): mute flags successfully updated");
    359         return JNI_TRUE;
    360     } else {
    361         ALOGE("android_media_JetPlayer_setMuteFlags(): failed with EAS error code %ld", result);
    362         return JNI_FALSE;
    363     }
    364 }
    365 
    366 
    367 // ----------------------------------------------------------------------------
    368 static jboolean
    369 android_media_JetPlayer_setMuteArray(JNIEnv *env, jobject thiz,
    370         jbooleanArray muteArray, jboolean bSync)
    371 {
    372     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    373         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    374     if (lpJet == NULL) {
    375         jniThrowException(env, "java/lang/IllegalStateException",
    376             "Unable to retrieve JetPlayer pointer for setMuteArray()");
    377         return JNI_FALSE;
    378     }
    379 
    380     EAS_RESULT result=EAS_FAILURE;
    381 
    382     jboolean *muteTracks = NULL;
    383     muteTracks = env->GetBooleanArrayElements(muteArray, NULL);
    384     if (muteTracks == NULL) {
    385         ALOGE("android_media_JetPlayer_setMuteArray(): failed to read track mute mask.");
    386         return JNI_FALSE;
    387     }
    388 
    389     EAS_U32 muteMask=0;
    390     int maxTracks = lpJet->getMaxTracks();
    391     for (jint trackIndex=0; trackIndex<maxTracks; trackIndex++) {
    392         if (muteTracks[maxTracks-1-trackIndex]==JNI_TRUE)
    393             muteMask = (muteMask << 1) | 0x00000001;
    394         else
    395             muteMask = muteMask << 1;
    396     }
    397     //ALOGV("android_media_JetPlayer_setMuteArray(): FINAL mute mask =0x%08lX", muteMask);
    398 
    399     result = lpJet->setMuteFlags(muteMask, bSync==JNI_TRUE ? true : false);
    400 
    401     env->ReleaseBooleanArrayElements(muteArray, muteTracks, 0);
    402     if (result==EAS_SUCCESS) {
    403         //ALOGV("android_media_JetPlayer_setMuteArray(): mute flags successfully updated");
    404         return JNI_TRUE;
    405     } else {
    406         ALOGE("android_media_JetPlayer_setMuteArray(): \
    407             failed to update mute flags with EAS error code %ld", result);
    408         return JNI_FALSE;
    409     }
    410 }
    411 
    412 
    413 // ----------------------------------------------------------------------------
    414 static jboolean
    415 android_media_JetPlayer_setMuteFlag(JNIEnv *env, jobject thiz,
    416          jint trackId, jboolean muteFlag, jboolean bSync)
    417 {
    418     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    419         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    420     if (lpJet == NULL) {
    421         jniThrowException(env, "java/lang/IllegalStateException",
    422             "Unable to retrieve JetPlayer pointer for setMuteFlag()");
    423         return JNI_FALSE;
    424     }
    425 
    426     EAS_RESULT result;
    427     result = lpJet->setMuteFlag(trackId,
    428         muteFlag==JNI_TRUE ? true : false, bSync==JNI_TRUE ? true : false);
    429     if (result==EAS_SUCCESS) {
    430         //ALOGV("android_media_JetPlayer_setMuteFlag(): mute flag successfully updated for track %d", trackId);
    431         return JNI_TRUE;
    432     } else {
    433         ALOGE("android_media_JetPlayer_setMuteFlag(): failed to update mute flag for track %d with EAS error code %ld",
    434                 trackId, result);
    435         return JNI_FALSE;
    436     }
    437 }
    438 
    439 
    440 // ----------------------------------------------------------------------------
    441 static jboolean
    442 android_media_JetPlayer_triggerClip(JNIEnv *env, jobject thiz, jint clipId)
    443 {
    444     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    445         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    446     if (lpJet == NULL) {
    447         jniThrowException(env, "java/lang/IllegalStateException",
    448             "Unable to retrieve JetPlayer pointer for triggerClip()");
    449         return JNI_FALSE;
    450     }
    451 
    452     EAS_RESULT result;
    453     result = lpJet->triggerClip(clipId);
    454     if (result==EAS_SUCCESS) {
    455         //ALOGV("android_media_JetPlayer_triggerClip(): triggerClip successful for clip %d", clipId);
    456         return JNI_TRUE;
    457     } else {
    458         ALOGE("android_media_JetPlayer_triggerClip(): triggerClip for clip %d failed with EAS error code %ld",
    459                 clipId, result);
    460         return JNI_FALSE;
    461     }
    462 }
    463 
    464 
    465 // ----------------------------------------------------------------------------
    466 static jboolean
    467 android_media_JetPlayer_clearQueue(JNIEnv *env, jobject thiz)
    468 {
    469     JetPlayer *lpJet = (JetPlayer *)env->GetLongField(
    470         thiz, javaJetPlayerFields.nativePlayerInJavaObj);
    471     if (lpJet == NULL) {
    472         jniThrowException(env, "java/lang/IllegalStateException",
    473             "Unable to retrieve JetPlayer pointer for clearQueue()");
    474         return JNI_FALSE;
    475     }
    476 
    477     EAS_RESULT result = lpJet->clearQueue();
    478     if (result==EAS_SUCCESS) {
    479         //ALOGV("android_media_JetPlayer_clearQueue(): clearQueue successful");
    480         return JNI_TRUE;
    481     } else {
    482         ALOGE("android_media_JetPlayer_clearQueue(): clearQueue failed with EAS error code %ld",
    483                 result);
    484         return JNI_FALSE;
    485     }
    486 }
    487 
    488 
    489 // ----------------------------------------------------------------------------
    490 // ----------------------------------------------------------------------------
    491 static const JNINativeMethod gMethods[] = {
    492     // name,               signature,               funcPtr
    493     {"native_setup",       "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup},
    494     {"native_finalize",    "()V",                   (void *)android_media_JetPlayer_finalize},
    495     {"native_release",     "()V",                   (void *)android_media_JetPlayer_release},
    496     {"native_loadJetFromFile",
    497                            "(Ljava/lang/String;)Z", (void *)android_media_JetPlayer_loadFromFile},
    498     {"native_loadJetFromFileD", "(Ljava/io/FileDescriptor;JJ)Z",
    499                                                     (void *)android_media_JetPlayer_loadFromFileD},
    500     {"native_closeJetFile","()Z",                   (void *)android_media_JetPlayer_closeFile},
    501     {"native_playJet",     "()Z",                   (void *)android_media_JetPlayer_play},
    502     {"native_pauseJet",    "()Z",                   (void *)android_media_JetPlayer_pause},
    503     {"native_queueJetSegment",
    504                            "(IIIIIB)Z",             (void *)android_media_JetPlayer_queueSegment},
    505     {"native_queueJetSegmentMuteArray",
    506                            "(IIII[ZB)Z",     (void *)android_media_JetPlayer_queueSegmentMuteArray},
    507     {"native_setMuteFlags","(IZ)Z",                 (void *)android_media_JetPlayer_setMuteFlags},
    508     {"native_setMuteArray","([ZZ)Z",                (void *)android_media_JetPlayer_setMuteArray},
    509     {"native_setMuteFlag", "(IZZ)Z",                (void *)android_media_JetPlayer_setMuteFlag},
    510     {"native_triggerClip", "(I)Z",                  (void *)android_media_JetPlayer_triggerClip},
    511     {"native_clearQueue",  "()Z",                   (void *)android_media_JetPlayer_clearQueue},
    512 };
    513 
    514 #define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj"
    515 #define JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME "postEventFromNative"
    516 
    517 
    518 int register_android_media_JetPlayer(JNIEnv *env)
    519 {
    520     javaJetPlayerFields.jetClass = NULL;
    521     javaJetPlayerFields.postNativeEventInJava = NULL;
    522     javaJetPlayerFields.nativePlayerInJavaObj = NULL;
    523 
    524     // Get the JetPlayer java class
    525     jclass jetPlayerClass = FindClassOrDie(env, kClassPathName);
    526     javaJetPlayerFields.jetClass = MakeGlobalRefOrDie(env, jetPlayerClass);
    527 
    528     // Get the mNativePlayerInJavaObj variable field
    529     javaJetPlayerFields.nativePlayerInJavaObj = GetFieldIDOrDie(env,
    530             jetPlayerClass, JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J");
    531 
    532     // Get the callback to post events from this native code to Java
    533     javaJetPlayerFields.postNativeEventInJava = GetStaticMethodIDOrDie(env,
    534             javaJetPlayerFields.jetClass, JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME,
    535             "(Ljava/lang/Object;III)V");
    536 
    537     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
    538 }
    539