android_media_JetPlayer.cpp revision 3001a035439d8134a7d70d796376d1dfbff3cdcd
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//FIXME: remove log before release 18#define LOG_NDEBUG 0 19#define LOG_TAG "JET_JNI" 20 21 22#include <stdio.h> 23#include <unistd.h> 24#include <fcntl.h> 25 26#include "jni.h" 27#include "JNIHelp.h" 28#include "android_runtime/AndroidRuntime.h" 29 30#include "utils/Log.h" 31#include "media/JetPlayer.h" 32 33 34using namespace android; 35 36// ---------------------------------------------------------------------------- 37static const char* const kClassPathName = "android/media/JetPlayer"; 38 39// ---------------------------------------------------------------------------- 40struct fields_t { 41 // these fields provide access from C++ to the... 42 jclass jetClass; // JetPlayer java class global ref 43 jmethodID postNativeEventInJava; // java method to post events to the Java thread from native 44 jfieldID nativePlayerInJavaObj; // stores in Java the native JetPlayer object 45}; 46 47static fields_t javaJetPlayerFields; 48 49 50// ---------------------------------------------------------------------------- 51// ---------------------------------------------------------------------------- 52 53/* 54 * This function is called from JetPlayer instance's render thread 55 */ 56static void 57jetPlayerEventCallback(int what, int arg1=0, int arg2=0, void* javaTarget = NULL) 58{ 59 JNIEnv *env = AndroidRuntime::getJNIEnv(); 60 if(env) { 61 env->CallStaticVoidMethod( 62 javaJetPlayerFields.jetClass, javaJetPlayerFields.postNativeEventInJava, 63 javaTarget, 64 what, arg1, arg2); 65 if (env->ExceptionCheck()) { 66 env->ExceptionDescribe(); 67 env->ExceptionClear(); 68 } 69 } else { 70 LOGE("JET jetPlayerEventCallback(): No JNI env for JET event callback, can't post event."); 71 return; 72 } 73} 74 75 76// ---------------------------------------------------------------------------- 77// ---------------------------------------------------------------------------- 78 79static jboolean 80android_media_JetPlayer_setup(JNIEnv *env, jobject thiz, jobject weak_this, 81 jint maxTracks, jint trackBufferSize) 82{ 83 //LOGV("android_media_JetPlayer_setup(): entering."); 84 JetPlayer* lpJet = new JetPlayer(env->NewGlobalRef(weak_this), maxTracks, trackBufferSize); 85 86 EAS_RESULT result = lpJet->init(); 87 88 if(result==EAS_SUCCESS) { 89 // save our newly created C++ JetPlayer in the "nativePlayerInJavaObj" field 90 // of the Java object (in mNativePlayerInJavaObj) 91 env->SetIntField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, (int)lpJet); 92 return JNI_TRUE; 93 } else { 94 LOGE("android_media_JetPlayer_setup(): initialization failed with EAS error code %d", (int)result); 95 delete lpJet; 96 env->SetIntField(weak_this, javaJetPlayerFields.nativePlayerInJavaObj, 0); 97 return JNI_FALSE; 98 } 99} 100 101 102// ---------------------------------------------------------------------------- 103static void 104android_media_JetPlayer_finalize(JNIEnv *env, jobject thiz) 105{ 106 LOGV("android_media_JetPlayer_finalize(): entering."); 107 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 108 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 109 if(lpJet != NULL) { 110 lpJet->release(); 111 delete lpJet; 112 } 113 114 LOGV("android_media_JetPlayer_finalize(): exiting."); 115} 116 117 118// ---------------------------------------------------------------------------- 119static void 120android_media_JetPlayer_release(JNIEnv *env, jobject thiz) 121{ 122 android_media_JetPlayer_finalize(env, thiz); 123 env->SetIntField(thiz, javaJetPlayerFields.nativePlayerInJavaObj, 0); 124 LOGV("android_media_JetPlayer_release() done"); 125} 126 127 128// ---------------------------------------------------------------------------- 129static jboolean 130android_media_JetPlayer_loadFromFile(JNIEnv *env, jobject thiz, jstring path) 131{ 132 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 133 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 134 if (lpJet == NULL ) { 135 jniThrowException(env, "java/lang/IllegalStateException", 136 "Unable to retrieve JetPlayer pointer for openFile()"); 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 LOGE("android_media_JetPlayer_openFile(): aborting, out of memory"); 145 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 146 return JNI_FALSE; 147 } 148 149 LOGV("android_media_JetPlayer_openFile(): trying to open %s", pathStr ); 150 EAS_RESULT result = lpJet->loadFromFile(pathStr); 151 env->ReleaseStringUTFChars(path, pathStr); 152 153 if(result==EAS_SUCCESS) { 154 //LOGV("android_media_JetPlayer_openFile(): file successfully opened"); 155 return JNI_TRUE; 156 } else { 157 LOGE("android_media_JetPlayer_openFile(): failed to open file with EAS error %d", 158 (int)result); 159 return JNI_FALSE; 160 } 161} 162 163 164// ---------------------------------------------------------------------------- 165static jboolean 166android_media_JetPlayer_loadFromFileD(JNIEnv *env, jobject thiz, 167 jobject fileDescriptor, jlong offset, jlong length) 168{ 169 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 170 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 171 if (lpJet == NULL ) { 172 jniThrowException(env, "java/lang/IllegalStateException", 173 "Unable to retrieve JetPlayer pointer for openFile()"); 174 } 175 176 // set up event callback function 177 lpJet->setEventCallback(jetPlayerEventCallback); 178 179 LOGV("android_media_JetPlayer_openFileDescr(): trying to load JET file through its fd" ); 180 EAS_RESULT result = lpJet->loadFromFD(getParcelFileDescriptorFD(env, fileDescriptor), 181 (long long)offset, (long long)length); // cast params to types used by EAS_FILE 182 183 if(result==EAS_SUCCESS) { 184 LOGV("android_media_JetPlayer_openFileDescr(): file successfully opened"); 185 return JNI_TRUE; 186 } else { 187 LOGE("android_media_JetPlayer_openFileDescr(): failed to open file with EAS error %d", 188 (int)result); 189 return JNI_FALSE; 190 } 191} 192 193 194// ---------------------------------------------------------------------------- 195static jboolean 196android_media_JetPlayer_closeFile(JNIEnv *env, jobject thiz) 197{ 198 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 199 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 200 if (lpJet == NULL ) { 201 jniThrowException(env, "java/lang/IllegalStateException", 202 "Unable to retrieve JetPlayer pointer for closeFile()"); 203 } 204 205 if( lpJet->closeFile()==EAS_SUCCESS) { 206 //LOGV("android_media_JetPlayer_closeFile(): file successfully closed"); 207 return JNI_TRUE; 208 } else { 209 LOGE("android_media_JetPlayer_closeFile(): failed to close file"); 210 return JNI_FALSE; 211 } 212} 213 214 215// ---------------------------------------------------------------------------- 216static jboolean 217android_media_JetPlayer_play(JNIEnv *env, jobject thiz) 218{ 219 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 220 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 221 if (lpJet == NULL ) { 222 jniThrowException(env, "java/lang/IllegalStateException", 223 "Unable to retrieve JetPlayer pointer for play()"); 224 } 225 226 EAS_RESULT result = lpJet->play(); 227 if( result==EAS_SUCCESS) { 228 //LOGV("android_media_JetPlayer_play(): play successful"); 229 return JNI_TRUE; 230 } else { 231 LOGE("android_media_JetPlayer_play(): failed to play with EAS error code %ld", 232 result); 233 return JNI_FALSE; 234 } 235} 236 237 238// ---------------------------------------------------------------------------- 239static jboolean 240android_media_JetPlayer_pause(JNIEnv *env, jobject thiz) 241{ 242 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 243 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 244 if (lpJet == NULL ) { 245 jniThrowException(env, "java/lang/IllegalStateException", 246 "Unable to retrieve JetPlayer pointer for pause()"); 247 } 248 249 EAS_RESULT result = lpJet->pause(); 250 if( result==EAS_SUCCESS) { 251 //LOGV("android_media_JetPlayer_pause(): pause successful"); 252 return JNI_TRUE; 253 } else { 254 if(result==EAS_ERROR_QUEUE_IS_EMPTY) { 255 LOGV("android_media_JetPlayer_pause(): paused with an empty queue"); 256 return JNI_TRUE; 257 } else 258 LOGE("android_media_JetPlayer_pause(): failed to pause with EAS error code %ld", 259 result); 260 return JNI_FALSE; 261 } 262} 263 264 265// ---------------------------------------------------------------------------- 266static jboolean 267android_media_JetPlayer_queueSegment(JNIEnv *env, jobject thiz, 268 jint segmentNum, jint libNum, jint repeatCount, jint transpose, jint muteFlags, 269 jbyte userID) 270{ 271 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 272 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 273 if (lpJet == NULL ) { 274 jniThrowException(env, "java/lang/IllegalStateException", 275 "Unable to retrieve JetPlayer pointer for queueSegment()"); 276 } 277 278 EAS_RESULT result 279 = lpJet->queueSegment(segmentNum, libNum, repeatCount, transpose, muteFlags, userID); 280 if(result==EAS_SUCCESS) { 281 //LOGV("android_media_JetPlayer_queueSegment(): segment successfully queued"); 282 return JNI_TRUE; 283 } else { 284 LOGE("android_media_JetPlayer_queueSegment(): failed with EAS error code %ld", 285 result); 286 return JNI_FALSE; 287 } 288} 289 290 291// ---------------------------------------------------------------------------- 292static jboolean 293android_media_JetPlayer_queueSegmentMuteArray(JNIEnv *env, jobject thiz, 294 jint segmentNum, jint libNum, jint repeatCount, jint transpose, jbooleanArray muteArray, 295 jbyte userID) 296{ 297 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 298 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 299 if (lpJet == NULL ) { 300 jniThrowException(env, "java/lang/IllegalStateException", 301 "Unable to retrieve JetPlayer pointer for queueSegmentMuteArray()"); 302 } 303 304 EAS_RESULT result=EAS_FAILURE; 305 306 jboolean *muteTracks = NULL; 307 muteTracks = env->GetBooleanArrayElements(muteArray, NULL); 308 if (muteTracks == NULL) { 309 LOGE("android_media_JetPlayer_queueSegment(): failed to read track mute mask."); 310 return JNI_FALSE; 311 } 312 313 EAS_U32 muteMask=0; 314 int maxTracks = lpJet->getMaxTracks(); 315 for (jint trackIndex=0; trackIndex<maxTracks; trackIndex++) { 316 if(muteTracks[maxTracks-1-trackIndex]==JNI_TRUE) 317 muteMask = (muteMask << 1) | 0x00000001; 318 else 319 muteMask = muteMask << 1; 320 } 321 //LOGV("android_media_JetPlayer_queueSegmentMuteArray(): FINAL mute mask =0x%08lX", mask); 322 323 result = lpJet->queueSegment(segmentNum, libNum, repeatCount, transpose, muteMask, userID); 324 325 env->ReleaseBooleanArrayElements(muteArray, muteTracks, 0); 326 if(result==EAS_SUCCESS) { 327 //LOGV("android_media_JetPlayer_queueSegmentMuteArray(): segment successfully queued"); 328 return JNI_TRUE; 329 } else { 330 LOGE("android_media_JetPlayer_queueSegmentMuteArray(): failed with EAS error code %ld", 331 result); 332 return JNI_FALSE; 333 } 334} 335 336 337// ---------------------------------------------------------------------------- 338static jboolean 339android_media_JetPlayer_setMuteFlags(JNIEnv *env, jobject thiz, 340 jint muteFlags /*unsigned?*/, jboolean bSync) 341{ 342 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 343 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 344 if (lpJet == NULL ) { 345 jniThrowException(env, "java/lang/IllegalStateException", 346 "Unable to retrieve JetPlayer pointer for setMuteFlags()"); 347 } 348 349 EAS_RESULT result; 350 result = lpJet->setMuteFlags(muteFlags, bSync==JNI_TRUE ? true : false); 351 if(result==EAS_SUCCESS) { 352 //LOGV("android_media_JetPlayer_setMuteFlags(): mute flags successfully updated"); 353 return JNI_TRUE; 354 } else { 355 LOGE("android_media_JetPlayer_setMuteFlags(): failed with EAS error code %ld", result); 356 return JNI_FALSE; 357 } 358} 359 360 361// ---------------------------------------------------------------------------- 362static jboolean 363android_media_JetPlayer_setMuteArray(JNIEnv *env, jobject thiz, 364 jbooleanArray muteArray, jboolean bSync) 365{ 366 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 367 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 368 if (lpJet == NULL ) { 369 jniThrowException(env, "java/lang/IllegalStateException", 370 "Unable to retrieve JetPlayer pointer for setMuteArray()"); 371 } 372 373 EAS_RESULT result=EAS_FAILURE; 374 375 jboolean *muteTracks = NULL; 376 muteTracks = env->GetBooleanArrayElements(muteArray, NULL); 377 if (muteTracks == NULL) { 378 LOGE("android_media_JetPlayer_setMuteArray(): failed to read track mute mask."); 379 return JNI_FALSE; 380 } 381 382 EAS_U32 muteMask=0; 383 int maxTracks = lpJet->getMaxTracks(); 384 for (jint trackIndex=0; trackIndex<maxTracks; trackIndex++) { 385 if(muteTracks[maxTracks-1-trackIndex]==JNI_TRUE) 386 muteMask = (muteMask << 1) | 0x00000001; 387 else 388 muteMask = muteMask << 1; 389 } 390 //LOGV("android_media_JetPlayer_setMuteArray(): FINAL mute mask =0x%08lX", muteMask); 391 392 result = lpJet->setMuteFlags(muteMask, bSync==JNI_TRUE ? true : false); 393 394 env->ReleaseBooleanArrayElements(muteArray, muteTracks, 0); 395 if(result==EAS_SUCCESS) { 396 //LOGV("android_media_JetPlayer_setMuteArray(): mute flags successfully updated"); 397 return JNI_TRUE; 398 } else { 399 LOGE("android_media_JetPlayer_setMuteArray(): \ 400 failed to update mute flags with EAS error code %ld", result); 401 return JNI_FALSE; 402 } 403} 404 405 406// ---------------------------------------------------------------------------- 407static jboolean 408android_media_JetPlayer_setMuteFlag(JNIEnv *env, jobject thiz, 409 jint trackId, jboolean muteFlag, jboolean bSync) 410{ 411 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 412 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 413 if (lpJet == NULL ) { 414 jniThrowException(env, "java/lang/IllegalStateException", 415 "Unable to retrieve JetPlayer pointer for setMuteFlag()"); 416 } 417 418 EAS_RESULT result; 419 result = lpJet->setMuteFlag(trackId, 420 muteFlag==JNI_TRUE ? true : false, bSync==JNI_TRUE ? true : false); 421 if(result==EAS_SUCCESS) { 422 //LOGV("android_media_JetPlayer_setMuteFlag(): mute flag successfully updated for track %d", trackId); 423 return JNI_TRUE; 424 } else { 425 LOGE("android_media_JetPlayer_setMuteFlag(): failed to update mute flag for track %d with EAS error code %ld", 426 trackId, result); 427 return JNI_FALSE; 428 } 429} 430 431 432// ---------------------------------------------------------------------------- 433static jboolean 434android_media_JetPlayer_triggerClip(JNIEnv *env, jobject thiz, jint clipId) 435{ 436 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 437 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 438 if (lpJet == NULL ) { 439 jniThrowException(env, "java/lang/IllegalStateException", 440 "Unable to retrieve JetPlayer pointer for triggerClip()"); 441 } 442 443 EAS_RESULT result; 444 result = lpJet->triggerClip(clipId); 445 if(result==EAS_SUCCESS) { 446 //LOGV("android_media_JetPlayer_triggerClip(): triggerClip successful for clip %d", clipId); 447 return JNI_TRUE; 448 } else { 449 LOGE("android_media_JetPlayer_triggerClip(): triggerClip for clip %d failed with EAS error code %ld", 450 clipId, result); 451 return JNI_FALSE; 452 } 453} 454 455 456// ---------------------------------------------------------------------------- 457static jboolean 458android_media_JetPlayer_clearQueue(JNIEnv *env, jobject thiz) 459{ 460 JetPlayer *lpJet = (JetPlayer *)env->GetIntField( 461 thiz, javaJetPlayerFields.nativePlayerInJavaObj); 462 if (lpJet == NULL ) { 463 jniThrowException(env, "java/lang/IllegalStateException", 464 "Unable to retrieve JetPlayer pointer for clearQueue()"); 465 } 466 467 EAS_RESULT result = lpJet->clearQueue(); 468 if(result==EAS_SUCCESS) { 469 //LOGV("android_media_JetPlayer_clearQueue(): clearQueue successful"); 470 return JNI_TRUE; 471 } else { 472 LOGE("android_media_JetPlayer_clearQueue(): clearQueue failed with EAS error code %ld", 473 result); 474 return JNI_FALSE; 475 } 476} 477 478 479// ---------------------------------------------------------------------------- 480// ---------------------------------------------------------------------------- 481static JNINativeMethod gMethods[] = { 482 // name, signature, funcPtr 483 {"native_setup", "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup}, 484 {"native_finalize", "()V", (void *)android_media_JetPlayer_finalize}, 485 {"native_release", "()V", (void *)android_media_JetPlayer_release}, 486 {"native_loadJetFromFile", 487 "(Ljava/lang/String;)Z", (void *)android_media_JetPlayer_loadFromFile}, 488 {"native_loadJetFromFileD", "(Ljava/io/FileDescriptor;JJ)Z", 489 (void *)android_media_JetPlayer_loadFromFileD}, 490 {"native_closeJetFile","()Z", (void *)android_media_JetPlayer_closeFile}, 491 {"native_playJet", "()Z", (void *)android_media_JetPlayer_play}, 492 {"native_pauseJet", "()Z", (void *)android_media_JetPlayer_pause}, 493 {"native_queueJetSegment", 494 "(IIIIIB)Z", (void *)android_media_JetPlayer_queueSegment}, 495 {"native_queueJetSegmentMuteArray", 496 "(IIII[ZB)Z", (void *)android_media_JetPlayer_queueSegmentMuteArray}, 497 {"native_setMuteFlags","(IZ)Z", (void *)android_media_JetPlayer_setMuteFlags}, 498 {"native_setMuteArray","([ZZ)Z", (void *)android_media_JetPlayer_setMuteArray}, 499 {"native_setMuteFlag", "(IZZ)Z", (void *)android_media_JetPlayer_setMuteFlag}, 500 {"native_triggerClip", "(I)Z", (void *)android_media_JetPlayer_triggerClip}, 501 {"native_clearQueue", "()Z", (void *)android_media_JetPlayer_clearQueue}, 502}; 503 504#define JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME "mNativePlayerInJavaObj" 505#define JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME "postEventFromNative" 506 507 508int register_android_media_JetPlayer(JNIEnv *env) 509{ 510 jclass jetPlayerClass = NULL; 511 javaJetPlayerFields.jetClass = NULL; 512 javaJetPlayerFields.postNativeEventInJava = NULL; 513 javaJetPlayerFields.nativePlayerInJavaObj = NULL; 514 515 // Get the JetPlayer java class 516 jetPlayerClass = env->FindClass(kClassPathName); 517 if (jetPlayerClass == NULL) { 518 LOGE("Can't find %s", kClassPathName); 519 return -1; 520 } 521 javaJetPlayerFields.jetClass = (jclass)env->NewGlobalRef(jetPlayerClass); 522 523 // Get the mNativePlayerInJavaObj variable field 524 javaJetPlayerFields.nativePlayerInJavaObj = env->GetFieldID( 525 jetPlayerClass, 526 JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME, "I"); 527 if (javaJetPlayerFields.nativePlayerInJavaObj == NULL) { 528 LOGE("Can't find AudioTrack.%s", JAVA_NATIVEJETPLAYERINJAVAOBJ_FIELD_NAME); 529 return -1; 530 } 531 532 // Get the callback to post events from this native code to Java 533 javaJetPlayerFields.postNativeEventInJava = env->GetStaticMethodID(javaJetPlayerFields.jetClass, 534 JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME, "(Ljava/lang/Object;III)V"); 535 if (javaJetPlayerFields.postNativeEventInJava == NULL) { 536 LOGE("Can't find Jet.%s", JAVA_NATIVEJETPOSTEVENT_CALLBACK_NAME); 537 return -1; 538 } 539 540 return AndroidRuntime::registerNativeMethods(env, 541 kClassPathName, gMethods, NELEM(gMethods)); 542} 543