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 LOGE("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 //LOGV("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->SetIntField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, (int)lpJet); 91 return JNI_TRUE; 92 } else { 93 LOGE("android_media_JetPlayer_setup(): initialization failed with EAS error code %d", (int)result); 94 delete lpJet; 95 env->SetIntField(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 LOGV("android_media_JetPlayer_finalize(): entering."); 106 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 107 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 108 if(lpJet != NULL) { 109 lpJet->release(); 110 delete lpJet; 111 } 112 113 LOGV("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->SetIntField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, 0); 123 LOGV("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->GetIntField( 132 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 133 if (lpJet == NULL ) { 134 jniThrowException(env, "java/lang/IllegalStateException", 135 "Unable to retrieve JetPlayer pointer for openFile()"); 136 } 137 138 // set up event callback function 139 lpJet->setEventCallback(jetPlayerEventCallback); 140 141 const char *pathStr = env->GetStringUTFChars(path, NULL); 142 if (pathStr == NULL) { // Out of memory 143 LOGE("android_media_JetPlayer_openFile(): aborting, out of memory"); 144 return JNI_FALSE; 145 } 146 147 LOGV("android_media_JetPlayer_openFile(): trying to open %s", pathStr ); 148 EAS_RESULT result = lpJet->loadFromFile(pathStr); 149 env->ReleaseStringUTFChars(path, pathStr); 150 151 if(result==EAS_SUCCESS) { 152 //LOGV("android_media_JetPlayer_openFile(): file successfully opened"); 153 return JNI_TRUE; 154 } else { 155 LOGE("android_media_JetPlayer_openFile(): failed to open file with EAS error %d", 156 (int)result); 157 return JNI_FALSE; 158 } 159 } 160 161 162 // ---------------------------------------------------------------------------- 163 static jboolean 164 android_media_JetPlayer_loadFromFileD(JNIEnv *env, jobject thiz, 165 jobject fileDescriptor, jlong offset, jlong length) 166 { 167 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 168 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 169 if (lpJet == NULL ) { 170 jniThrowException(env, "java/lang/IllegalStateException", 171 "Unable to retrieve JetPlayer pointer for openFile()"); 172 } 173 174 // set up event callback function 175 lpJet->setEventCallback(jetPlayerEventCallback); 176 177 LOGV("android_media_JetPlayer_openFileDescr(): trying to load JET file through its fd" ); 178 EAS_RESULT result = lpJet->loadFromFD(jniGetFDFromFileDescriptor(env, fileDescriptor), 179 (long long)offset, (long long)length); // cast params to types used by EAS_FILE 180 181 if(result==EAS_SUCCESS) { 182 LOGV("android_media_JetPlayer_openFileDescr(): file successfully opened"); 183 return JNI_TRUE; 184 } else { 185 LOGE("android_media_JetPlayer_openFileDescr(): failed to open file with EAS error %d", 186 (int)result); 187 return JNI_FALSE; 188 } 189 } 190 191 192 // ---------------------------------------------------------------------------- 193 static jboolean 194 android_media_JetPlayer_closeFile(JNIEnv *env, jobject thiz) 195 { 196 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 197 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 198 if (lpJet == NULL ) { 199 jniThrowException(env, "java/lang/IllegalStateException", 200 "Unable to retrieve JetPlayer pointer for closeFile()"); 201 } 202 203 if( lpJet->closeFile()==EAS_SUCCESS) { 204 //LOGV("android_media_JetPlayer_closeFile(): file successfully closed"); 205 return JNI_TRUE; 206 } else { 207 LOGE("android_media_JetPlayer_closeFile(): failed to close file"); 208 return JNI_FALSE; 209 } 210 } 211 212 213 // ---------------------------------------------------------------------------- 214 static jboolean 215 android_media_JetPlayer_play(JNIEnv *env, jobject thiz) 216 { 217 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 218 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 219 if (lpJet == NULL ) { 220 jniThrowException(env, "java/lang/IllegalStateException", 221 "Unable to retrieve JetPlayer pointer for play()"); 222 } 223 224 EAS_RESULT result = lpJet->play(); 225 if( result==EAS_SUCCESS) { 226 //LOGV("android_media_JetPlayer_play(): play successful"); 227 return JNI_TRUE; 228 } else { 229 LOGE("android_media_JetPlayer_play(): failed to play with EAS error code %ld", 230 result); 231 return JNI_FALSE; 232 } 233 } 234 235 236 // ---------------------------------------------------------------------------- 237 static jboolean 238 android_media_JetPlayer_pause(JNIEnv *env, jobject thiz) 239 { 240 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 241 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 242 if (lpJet == NULL ) { 243 jniThrowException(env, "java/lang/IllegalStateException", 244 "Unable to retrieve JetPlayer pointer for pause()"); 245 } 246 247 EAS_RESULT result = lpJet->pause(); 248 if( result==EAS_SUCCESS) { 249 //LOGV("android_media_JetPlayer_pause(): pause successful"); 250 return JNI_TRUE; 251 } else { 252 if(result==EAS_ERROR_QUEUE_IS_EMPTY) { 253 LOGV("android_media_JetPlayer_pause(): paused with an empty queue"); 254 return JNI_TRUE; 255 } else 256 LOGE("android_media_JetPlayer_pause(): failed to pause with EAS error code %ld", 257 result); 258 return JNI_FALSE; 259 } 260 } 261 262 263 // ---------------------------------------------------------------------------- 264 static jboolean 265 android_media_JetPlayer_queueSegment(JNIEnv *env, jobject thiz, 266 jint segmentNum, jint libNum, jint repeatCount, jint transpose, jint muteFlags, 267 jbyte userID) 268 { 269 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 270 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 271 if (lpJet == NULL ) { 272 jniThrowException(env, "java/lang/IllegalStateException", 273 "Unable to retrieve JetPlayer pointer for queueSegment()"); 274 } 275 276 EAS_RESULT result 277 = lpJet->queueSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID); 278 if(result==EAS_SUCCESS) { 279 //LOGV("android_media_JetPlayer_queueSegment(): segment successfully queued"); 280 return JNI_TRUE; 281 } else { 282 LOGE("android_media_JetPlayer_queueSegment(): failed with EAS error code %ld", 283 result); 284 return JNI_FALSE; 285 } 286 } 287 288 289 // ---------------------------------------------------------------------------- 290 static jboolean 291 android_media_JetPlayer_queueSegmentMuteArray(JNIEnv *env, jobject thiz, 292 jint segmentNum, jint libNum, jint repeatCount, jint transpose, jbooleanArray muteArray, 293 jbyte userID) 294 { 295 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 296 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 297 if (lpJet == NULL ) { 298 jniThrowException(env, "java/lang/IllegalStateException", 299 "Unable to retrieve JetPlayer pointer for queueSegmentMuteArray()"); 300 } 301 302 EAS_RESULT result=EAS_FAILURE; 303 304 jboolean *muteTracks = NULL; 305 muteTracks = env->GetBooleanArrayElements(muteArray, NULL); 306 if (muteTracks == NULL) { 307 LOGE("android_media_JetPlayer_queueSegment(): failed to read track mute mask."); 308 return JNI_FALSE; 309 } 310 311 EAS_U32 muteMask=0; 312 int maxTracks = lpJet->getMaxTracks(); 313 for (jint trackIndex=0; trackIndex<maxTracks; trackIndex++) { 314 if(muteTracks[maxTracks-1-trackIndex]==JNI_TRUE) 315 muteMask = (muteMask << 1) | 0x00000001; 316 else 317 muteMask = muteMask << 1; 318 } 319 //LOGV("android_media_JetPlayer_queueSegmentMuteArray(): FINAL mute mask =0x%08lX", mask); 320 321 result = lpJet->queueSegment(segmentNum, libNum, repeatCount, transpose, muteMask, userID); 322 323 env->ReleaseBooleanArrayElements(muteArray, muteTracks, 0); 324 if(result==EAS_SUCCESS) { 325 //LOGV("android_media_JetPlayer_queueSegmentMuteArray(): segment successfully queued"); 326 return JNI_TRUE; 327 } else { 328 LOGE("android_media_JetPlayer_queueSegmentMuteArray(): failed with EAS error code %ld", 329 result); 330 return JNI_FALSE; 331 } 332 } 333 334 335 // ---------------------------------------------------------------------------- 336 static jboolean 337 android_media_JetPlayer_setMuteFlags(JNIEnv *env, jobject thiz, 338 jint muteFlags /*unsigned?*/, jboolean bSync) 339 { 340 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 341 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 342 if (lpJet == NULL ) { 343 jniThrowException(env, "java/lang/IllegalStateException", 344 "Unable to retrieve JetPlayer pointer for setMuteFlags()"); 345 } 346 347 EAS_RESULT result; 348 result = lpJet->setMuteFlags(muteFlags, bSync==JNI_TRUE ? true : false); 349 if(result==EAS_SUCCESS) { 350 //LOGV("android_media_JetPlayer_setMuteFlags(): mute flags successfully updated"); 351 return JNI_TRUE; 352 } else { 353 LOGE("android_media_JetPlayer_setMuteFlags(): failed with EAS error code %ld", result); 354 return JNI_FALSE; 355 } 356 } 357 358 359 // ---------------------------------------------------------------------------- 360 static jboolean 361 android_media_JetPlayer_setMuteArray(JNIEnv *env, jobject thiz, 362 jbooleanArray muteArray, jboolean bSync) 363 { 364 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 365 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 366 if (lpJet == NULL ) { 367 jniThrowException(env, "java/lang/IllegalStateException", 368 "Unable to retrieve JetPlayer pointer for setMuteArray()"); 369 } 370 371 EAS_RESULT result=EAS_FAILURE; 372 373 jboolean *muteTracks = NULL; 374 muteTracks = env->GetBooleanArrayElements(muteArray, NULL); 375 if (muteTracks == NULL) { 376 LOGE("android_media_JetPlayer_setMuteArray(): failed to read track mute mask."); 377 return JNI_FALSE; 378 } 379 380 EAS_U32 muteMask=0; 381 int maxTracks = lpJet->getMaxTracks(); 382 for (jint trackIndex=0; trackIndex<maxTracks; trackIndex++) { 383 if(muteTracks[maxTracks-1-trackIndex]==JNI_TRUE) 384 muteMask = (muteMask << 1) | 0x00000001; 385 else 386 muteMask = muteMask << 1; 387 } 388 //LOGV("android_media_JetPlayer_setMuteArray(): FINAL mute mask =0x%08lX", muteMask); 389 390 result = lpJet->setMuteFlags(muteMask, bSync==JNI_TRUE ? true : false); 391 392 env->ReleaseBooleanArrayElements(muteArray, muteTracks, 0); 393 if(result==EAS_SUCCESS) { 394 //LOGV("android_media_JetPlayer_setMuteArray(): mute flags successfully updated"); 395 return JNI_TRUE; 396 } else { 397 LOGE("android_media_JetPlayer_setMuteArray(): \ 398 failed to update mute flags with EAS error code %ld", result); 399 return JNI_FALSE; 400 } 401 } 402 403 404 // ---------------------------------------------------------------------------- 405 static jboolean 406 android_media_JetPlayer_setMuteFlag(JNIEnv *env, jobject thiz, 407 jint trackId, jboolean muteFlag, jboolean bSync) 408 { 409 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 410 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 411 if (lpJet == NULL ) { 412 jniThrowException(env, "java/lang/IllegalStateException", 413 "Unable to retrieve JetPlayer pointer for setMuteFlag()"); 414 } 415 416 EAS_RESULT result; 417 result = lpJet->setMuteFlag(trackId, 418 muteFlag==JNI_TRUE ? true : false, bSync==JNI_TRUE ? true : false); 419 if(result==EAS_SUCCESS) { 420 //LOGV("android_media_JetPlayer_setMuteFlag(): mute flag successfully updated for track %d", trackId); 421 return JNI_TRUE; 422 } else { 423 LOGE("android_media_JetPlayer_setMuteFlag(): failed to update mute flag for track %d with EAS error code %ld", 424 trackId, result); 425 return JNI_FALSE; 426 } 427 } 428 429 430 // ---------------------------------------------------------------------------- 431 static jboolean 432 android_media_JetPlayer_triggerClip(JNIEnv *env, jobject thiz, jint clipId) 433 { 434 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 435 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 436 if (lpJet == NULL ) { 437 jniThrowException(env, "java/lang/IllegalStateException", 438 "Unable to retrieve JetPlayer pointer for triggerClip()"); 439 } 440 441 EAS_RESULT result; 442 result = lpJet->triggerClip(clipId); 443 if(result==EAS_SUCCESS) { 444 //LOGV("android_media_JetPlayer_triggerClip(): triggerClip successful for clip %d", clipId); 445 return JNI_TRUE; 446 } else { 447 LOGE("android_media_JetPlayer_triggerClip(): triggerClip for clip %d failed with EAS error code %ld", 448 clipId, result); 449 return JNI_FALSE; 450 } 451 } 452 453 454 // ---------------------------------------------------------------------------- 455 static jboolean 456 android_media_JetPlayer_clearQueue(JNIEnv *env, jobject thiz) 457 { 458 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 459 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 460 if (lpJet == NULL ) { 461 jniThrowException(env, "java/lang/IllegalStateException", 462 "Unable to retrieve JetPlayer pointer for clearQueue()"); 463 } 464 465 EAS_RESULT result = lpJet->clearQueue(); 466 if(result==EAS_SUCCESS) { 467 //LOGV("android_media_JetPlayer_clearQueue(): clearQueue successful"); 468 return JNI_TRUE; 469 } else { 470 LOGE("android_media_JetPlayer_clearQueue(): clearQueue failed with EAS error code %ld", 471 result); 472 return JNI_FALSE; 473 } 474 } 475 476 477 // ---------------------------------------------------------------------------- 478 // ---------------------------------------------------------------------------- 479 static JNINativeMethod gMethods[] = { 480 // name, signature, funcPtr 481 {"native_setup", "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup}, 482 {"native_finalize", "()V", (void *)android_media_JetPlayer_finalize}, 483 {"native_release", "()V", (void *)android_media_JetPlayer_release}, 484 {"native_loadJetFromFile", 485 "(Ljava/lang/String;)Z", (void *)android_media_JetPlayer_loadFromFile}, 486 {"native_loadJetFromFileD", "(Ljava/io/FileDescriptor;JJ)Z", 487 (void *)android_media_JetPlayer_loadFromFileD}, 488 {"native_closeJetFile","()Z", (void *)android_media_JetPlayer_closeFile}, 489 {"native_playJet", "()Z", (void *)android_media_JetPlayer_play}, 490 {"native_pauseJet", "()Z", (void *)android_media_JetPlayer_pause}, 491 {"native_queueJetSegment", 492 "(IIIIIB)Z", (void *)android_media_JetPlayer_queueSegment}, 493 {"native_queueJetSegmentMuteArray", 494 "(IIII[ZB)Z", (void *)android_media_JetPlayer_queueSegmentMuteArray}, 495 {"native_setMuteFlags","(IZ)Z", (void *)android_media_JetPlayer_setMuteFlags}, 496 {"native_setMuteArray","([ZZ)Z", (void *)android_media_JetPlayer_setMuteArray}, 497 {"native_setMuteFlag", "(IZZ)Z", (void *)android_media_JetPlayer_setMuteFlag}, 498 {"native_triggerClip", "(I)Z", (void *)android_media_JetPlayer_triggerClip}, 499 {"native_clearQueue", "()Z", (void *)android_media_JetPlayer_clearQueue}, 500 }; 501 502 #define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj" 503 #define JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME "postEventFromNative" 504 505 506 int register_android_media_JetPlayer(JNIEnv *env) 507 { 508 jclass jetPlayerClass = NULL; 509 javaJetPlayerFields.jetClass = NULL; 510 javaJetPlayerFields.postNativeEventInJava = NULL; 511 javaJetPlayerFields.nativePlayerInJavaObj = NULL; 512 513 // Get the JetPlayer java class 514 jetPlayerClass = env->FindClass(kClassPathName); 515 if (jetPlayerClass == NULL) { 516 LOGE("Can't find %s", kClassPathName); 517 return -1; 518 } 519 javaJetPlayerFields.jetClass = (jclass)env->NewGlobalRef(jetPlayerClass); 520 521 // Get the mNativePlayerInJavaObj variable field 522 javaJetPlayerFields.nativePlayerInJavaObj = env->GetFieldID( 523 jetPlayerClass, 524 JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "I"); 525 if (javaJetPlayerFields.nativePlayerInJavaObj == NULL) { 526 LOGE("Can't find AudioTrack.%s", JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME); 527 return -1; 528 } 529 530 // Get the callback to post events from this native code to Java 531 javaJetPlayerFields.postNativeEventInJava = env->GetStaticMethodID(javaJetPlayerFields.jetClass, 532 JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;III)V"); 533 if (javaJetPlayerFields.postNativeEventInJava == NULL) { 534 LOGE("Can't find Jet.%s", JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME); 535 return -1; 536 } 537 538 return AndroidRuntime::registerNativeMethods(env, 539 kClassPathName, gMethods, NELEM(gMethods)); 540 } 541