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