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 33using namespace android; 34 35// ---------------------------------------------------------------------------- 36static const char* const kClassPathName = "android/media/JetPlayer"; 37 38// ---------------------------------------------------------------------------- 39struct 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 46static fields_t javaJetPlayerFields; 47 48 49// ---------------------------------------------------------------------------- 50// ---------------------------------------------------------------------------- 51 52/* 53 * This function is called from JetPlayer instance's render thread 54 */ 55static void 56jetPlayerEventCallback(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 78static jboolean 79android_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->SetIntField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, (int)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->SetIntField(weak_this, javaJetPlayerFields.nativePlayerInJavaObj, 0); 96 return JNI_FALSE; 97 } 98} 99 100 101// ---------------------------------------------------------------------------- 102static void 103android_media_JetPlayer_finalize(JNIEnv *env, jobject thiz) 104{ 105 ALOGV("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 ALOGV("android_media_JetPlayer_finalize(): exiting."); 114} 115 116 117// ---------------------------------------------------------------------------- 118static void 119android_media_JetPlayer_release(JNIEnv *env, jobject thiz) 120{ 121 android_media_JetPlayer_finalize(env, thiz); 122 env->SetIntField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, 0); 123 ALOGV("android_media_JetPlayer_release() done"); 124} 125 126 127// ---------------------------------------------------------------------------- 128static jboolean 129android_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 ALOGE("android_media_JetPlayer_openFile(): aborting, out of memory"); 144 return JNI_FALSE; 145 } 146 147 ALOGV("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 //ALOGV("android_media_JetPlayer_openFile(): file successfully opened"); 153 return JNI_TRUE; 154 } else { 155 ALOGE("android_media_JetPlayer_openFile(): failed to open file with EAS error %d", 156 (int)result); 157 return JNI_FALSE; 158 } 159} 160 161 162// ---------------------------------------------------------------------------- 163static jboolean 164android_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 ALOGV("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 ALOGV("android_media_JetPlayer_openFileDescr(): file successfully opened"); 183 return JNI_TRUE; 184 } else { 185 ALOGE("android_media_JetPlayer_openFileDescr(): failed to open file with EAS error %d", 186 (int)result); 187 return JNI_FALSE; 188 } 189} 190 191 192// ---------------------------------------------------------------------------- 193static jboolean 194android_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 //ALOGV("android_media_JetPlayer_closeFile(): file successfully closed"); 205 return JNI_TRUE; 206 } else { 207 ALOGE("android_media_JetPlayer_closeFile(): failed to close file"); 208 return JNI_FALSE; 209 } 210} 211 212 213// ---------------------------------------------------------------------------- 214static jboolean 215android_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 //ALOGV("android_media_JetPlayer_play(): play successful"); 227 return JNI_TRUE; 228 } else { 229 ALOGE("android_media_JetPlayer_play(): failed to play with EAS error code %ld", 230 result); 231 return JNI_FALSE; 232 } 233} 234 235 236// ---------------------------------------------------------------------------- 237static jboolean 238android_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 //ALOGV("android_media_JetPlayer_pause(): pause successful"); 250 return JNI_TRUE; 251 } else { 252 if (result==EAS_ERROR_QUEUE_IS_EMPTY) { 253 ALOGV("android_media_JetPlayer_pause(): paused with an empty queue"); 254 return JNI_TRUE; 255 } else 256 ALOGE("android_media_JetPlayer_pause(): failed to pause with EAS error code %ld", 257 result); 258 return JNI_FALSE; 259 } 260} 261 262 263// ---------------------------------------------------------------------------- 264static jboolean 265android_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 //ALOGV("android_media_JetPlayer_queueSegment(): segment successfully queued"); 280 return JNI_TRUE; 281 } else { 282 ALOGE("android_media_JetPlayer_queueSegment(): failed with EAS error code %ld", 283 result); 284 return JNI_FALSE; 285 } 286} 287 288 289// ---------------------------------------------------------------------------- 290static jboolean 291android_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 ALOGE("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 //ALOGV("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 //ALOGV("android_media_JetPlayer_queueSegmentMuteArray(): segment successfully queued"); 326 return JNI_TRUE; 327 } else { 328 ALOGE("android_media_JetPlayer_queueSegmentMuteArray(): failed with EAS error code %ld", 329 result); 330 return JNI_FALSE; 331 } 332} 333 334 335// ---------------------------------------------------------------------------- 336static jboolean 337android_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 //ALOGV("android_media_JetPlayer_setMuteFlags(): mute flags successfully updated"); 351 return JNI_TRUE; 352 } else { 353 ALOGE("android_media_JetPlayer_setMuteFlags(): failed with EAS error code %ld", result); 354 return JNI_FALSE; 355 } 356} 357 358 359// ---------------------------------------------------------------------------- 360static jboolean 361android_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 ALOGE("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 //ALOGV("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 //ALOGV("android_media_JetPlayer_setMuteArray(): mute flags successfully updated"); 395 return JNI_TRUE; 396 } else { 397 ALOGE("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// ---------------------------------------------------------------------------- 405static jboolean 406android_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 //ALOGV("android_media_JetPlayer_setMuteFlag(): mute flag successfully updated for track %d", trackId); 421 return JNI_TRUE; 422 } else { 423 ALOGE("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// ---------------------------------------------------------------------------- 431static jboolean 432android_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 //ALOGV("android_media_JetPlayer_triggerClip(): triggerClip successful for clip %d", clipId); 445 return JNI_TRUE; 446 } else { 447 ALOGE("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// ---------------------------------------------------------------------------- 455static jboolean 456android_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 //ALOGV("android_media_JetPlayer_clearQueue(): clearQueue successful"); 468 return JNI_TRUE; 469 } else { 470 ALOGE("android_media_JetPlayer_clearQueue(): clearQueue failed with EAS error code %ld", 471 result); 472 return JNI_FALSE; 473 } 474} 475 476 477// ---------------------------------------------------------------------------- 478// ---------------------------------------------------------------------------- 479static 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 506int 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 ALOGE("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 ALOGE("Can't find JetPlayer.%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 ALOGE("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