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 <JNIHelp.h> 27 #include <android_runtime/AndroidRuntime.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 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 jclass jetPlayerClass = NULL; 521 javaJetPlayerFields.jetClass = NULL; 522 javaJetPlayerFields.postNativeEventInJava = NULL; 523 javaJetPlayerFields.nativePlayerInJavaObj = NULL; 524 525 // Get the JetPlayer java class 526 jetPlayerClass = env->FindClass(kClassPathName); 527 if (jetPlayerClass == NULL) { 528 ALOGE("Can't find %s", kClassPathName); 529 return -1; 530 } 531 javaJetPlayerFields.jetClass = (jclass)env->NewGlobalRef(jetPlayerClass); 532 533 // Get the mNativePlayerInJavaObj variable field 534 javaJetPlayerFields.nativePlayerInJavaObj = env->GetFieldID( 535 jetPlayerClass, 536 JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "J"); 537 if (javaJetPlayerFields.nativePlayerInJavaObj == NULL) { 538 ALOGE("Can't find JetPlayer.%s", JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME); 539 return -1; 540 } 541 542 // Get the callback to post events from this native code to Java 543 javaJetPlayerFields.postNativeEventInJava = env->GetStaticMethodID(javaJetPlayerFields.jetClass, 544 JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;III)V"); 545 if (javaJetPlayerFields.postNativeEventInJava == NULL) { 546 ALOGE("Can't find Jet.%s", JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME); 547 return -1; 548 } 549 550 return AndroidRuntime::registerNativeMethods(env, 551 kClassPathName, gMethods, NELEM(gMethods)); 552 } 553