android_media_JetPlayer.cpp revision e89554b02d65eb87fb502b675b366d41abfa4979
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 LOGE("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 //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// ---------------------------------------------------------------------------- 102static void 103android_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// ---------------------------------------------------------------------------- 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 LOGV("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 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// ---------------------------------------------------------------------------- 164static jboolean 165android_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// ---------------------------------------------------------------------------- 194static jboolean 195android_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// ---------------------------------------------------------------------------- 215static jboolean 216android_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// ---------------------------------------------------------------------------- 238static jboolean 239android_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// ---------------------------------------------------------------------------- 265static jboolean 266android_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// ---------------------------------------------------------------------------- 291static jboolean 292android_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// ---------------------------------------------------------------------------- 337static jboolean 338android_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// ---------------------------------------------------------------------------- 361static jboolean 362android_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// ---------------------------------------------------------------------------- 406static jboolean 407android_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// ---------------------------------------------------------------------------- 432static jboolean 433android_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// ---------------------------------------------------------------------------- 456static jboolean 457android_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// ---------------------------------------------------------------------------- 480static 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 507int 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