1 /* 2 ** 3 ** Copyright 2007, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 //#define LOG_NDEBUG 0 19 #define LOG_TAG "MediaPlayer-JNI" 20 #include "utils/Log.h" 21 22 #include <media/mediaplayer.h> 23 #include <media/MediaPlayerInterface.h> 24 #include <stdio.h> 25 #include <assert.h> 26 #include <limits.h> 27 #include <unistd.h> 28 #include <fcntl.h> 29 #include <utils/threads.h> 30 #include "jni.h" 31 #include "JNIHelp.h" 32 #include "android_runtime/AndroidRuntime.h" 33 #include "android_runtime/android_view_Surface.h" 34 #include "utils/Errors.h" // for status_t 35 #include "utils/KeyedVector.h" 36 #include "utils/String8.h" 37 #include "android_media_Utils.h" 38 39 #include "android_os_Parcel.h" 40 #include "android_util_Binder.h" 41 #include <binder/Parcel.h> 42 #include <gui/ISurfaceTexture.h> 43 #include <gui/Surface.h> 44 #include <binder/IPCThreadState.h> 45 #include <binder/IServiceManager.h> 46 47 // ---------------------------------------------------------------------------- 48 49 using namespace android; 50 51 // ---------------------------------------------------------------------------- 52 53 struct fields_t { 54 jfieldID context; 55 jfieldID surface_texture; 56 57 jmethodID post_event; 58 }; 59 static fields_t fields; 60 61 static Mutex sLock; 62 63 // ---------------------------------------------------------------------------- 64 // ref-counted object for callbacks 65 class JNIMediaPlayerListener: public MediaPlayerListener 66 { 67 public: 68 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz); 69 ~JNIMediaPlayerListener(); 70 virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL); 71 private: 72 JNIMediaPlayerListener(); 73 jclass mClass; // Reference to MediaPlayer class 74 jobject mObject; // Weak ref to MediaPlayer Java object to call on 75 jobject mParcel; 76 }; 77 78 JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz) 79 { 80 81 // Hold onto the MediaPlayer class for use in calling the static method 82 // that posts events to the application thread. 83 jclass clazz = env->GetObjectClass(thiz); 84 if (clazz == NULL) { 85 ALOGE("Can't find android/media/MediaPlayer"); 86 jniThrowException(env, "java/lang/Exception", NULL); 87 return; 88 } 89 mClass = (jclass)env->NewGlobalRef(clazz); 90 91 // We use a weak reference so the MediaPlayer object can be garbage collected. 92 // The reference is only used as a proxy for callbacks. 93 mObject = env->NewGlobalRef(weak_thiz); 94 mParcel = env->NewGlobalRef(createJavaParcelObject(env)); 95 } 96 97 JNIMediaPlayerListener::~JNIMediaPlayerListener() 98 { 99 // remove global references 100 JNIEnv *env = AndroidRuntime::getJNIEnv(); 101 env->DeleteGlobalRef(mObject); 102 env->DeleteGlobalRef(mClass); 103 104 recycleJavaParcelObject(env, mParcel); 105 env->DeleteGlobalRef(mParcel); 106 } 107 108 void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj) 109 { 110 JNIEnv *env = AndroidRuntime::getJNIEnv(); 111 if (obj && obj->dataSize() > 0) { 112 if (mParcel != NULL) { 113 Parcel* nativeParcel = parcelForJavaObject(env, mParcel); 114 nativeParcel->setData(obj->data(), obj->dataSize()); 115 env->CallStaticVoidMethod(mClass, fields.post_event, mObject, 116 msg, ext1, ext2, mParcel); 117 } 118 } else { 119 env->CallStaticVoidMethod(mClass, fields.post_event, mObject, 120 msg, ext1, ext2, NULL); 121 } 122 if (env->ExceptionCheck()) { 123 ALOGW("An exception occurred while notifying an event."); 124 LOGW_EX(env); 125 env->ExceptionClear(); 126 } 127 } 128 129 // ---------------------------------------------------------------------------- 130 131 static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz) 132 { 133 Mutex::Autolock l(sLock); 134 MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context); 135 return sp<MediaPlayer>(p); 136 } 137 138 static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player) 139 { 140 Mutex::Autolock l(sLock); 141 sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context); 142 if (player.get()) { 143 player->incStrong(thiz); 144 } 145 if (old != 0) { 146 old->decStrong(thiz); 147 } 148 env->SetIntField(thiz, fields.context, (int)player.get()); 149 return old; 150 } 151 152 // If exception is NULL and opStatus is not OK, this method sends an error 153 // event to the client application; otherwise, if exception is not NULL and 154 // opStatus is not OK, this method throws the given exception to the client 155 // application. 156 static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message) 157 { 158 if (exception == NULL) { // Don't throw exception. Instead, send an event. 159 if (opStatus != (status_t) OK) { 160 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 161 if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0); 162 } 163 } else { // Throw exception! 164 if ( opStatus == (status_t) INVALID_OPERATION ) { 165 jniThrowException(env, "java/lang/IllegalStateException", NULL); 166 } else if ( opStatus == (status_t) PERMISSION_DENIED ) { 167 jniThrowException(env, "java/lang/SecurityException", NULL); 168 } else if ( opStatus != (status_t) OK ) { 169 if (strlen(message) > 230) { 170 // if the message is too long, don't bother displaying the status code 171 jniThrowException( env, exception, message); 172 } else { 173 char msg[256]; 174 // append the status code to the message 175 sprintf(msg, "%s: status=0x%X", message, opStatus); 176 jniThrowException( env, exception, msg); 177 } 178 } 179 } 180 } 181 182 static void 183 android_media_MediaPlayer_setDataSourceAndHeaders( 184 JNIEnv *env, jobject thiz, jstring path, 185 jobjectArray keys, jobjectArray values) { 186 187 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 188 if (mp == NULL ) { 189 jniThrowException(env, "java/lang/IllegalStateException", NULL); 190 return; 191 } 192 193 if (path == NULL) { 194 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 195 return; 196 } 197 198 const char *tmp = env->GetStringUTFChars(path, NULL); 199 if (tmp == NULL) { // Out of memory 200 return; 201 } 202 ALOGV("setDataSource: path %s", tmp); 203 204 String8 pathStr(tmp); 205 env->ReleaseStringUTFChars(path, tmp); 206 tmp = NULL; 207 208 // We build a KeyedVector out of the key and val arrays 209 KeyedVector<String8, String8> headersVector; 210 if (!ConvertKeyValueArraysToKeyedVector( 211 env, keys, values, &headersVector)) { 212 return; 213 } 214 215 status_t opStatus = 216 mp->setDataSource( 217 pathStr, 218 headersVector.size() > 0? &headersVector : NULL); 219 220 process_media_player_call( 221 env, thiz, opStatus, "java/io/IOException", 222 "setDataSource failed." ); 223 } 224 225 static void 226 android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) 227 { 228 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 229 if (mp == NULL ) { 230 jniThrowException(env, "java/lang/IllegalStateException", NULL); 231 return; 232 } 233 234 if (fileDescriptor == NULL) { 235 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 236 return; 237 } 238 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 239 ALOGV("setDataSourceFD: fd %d", fd); 240 process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." ); 241 } 242 243 static sp<ISurfaceTexture> 244 getVideoSurfaceTexture(JNIEnv* env, jobject thiz) { 245 ISurfaceTexture * const p = (ISurfaceTexture*)env->GetIntField(thiz, fields.surface_texture); 246 return sp<ISurfaceTexture>(p); 247 } 248 249 static void 250 decVideoSurfaceRef(JNIEnv *env, jobject thiz) 251 { 252 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 253 if (mp == NULL) { 254 return; 255 } 256 257 sp<ISurfaceTexture> old_st = getVideoSurfaceTexture(env, thiz); 258 if (old_st != NULL) { 259 old_st->decStrong(thiz); 260 } 261 } 262 263 static void 264 setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive) 265 { 266 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 267 if (mp == NULL) { 268 if (mediaPlayerMustBeAlive) { 269 jniThrowException(env, "java/lang/IllegalStateException", NULL); 270 } 271 return; 272 } 273 274 decVideoSurfaceRef(env, thiz); 275 276 sp<ISurfaceTexture> new_st; 277 if (jsurface) { 278 sp<Surface> surface(Surface_getSurface(env, jsurface)); 279 if (surface != NULL) { 280 new_st = surface->getSurfaceTexture(); 281 new_st->incStrong(thiz); 282 } else { 283 jniThrowException(env, "java/lang/IllegalArgumentException", 284 "The surface has been released"); 285 return; 286 } 287 } 288 289 env->SetIntField(thiz, fields.surface_texture, (int)new_st.get()); 290 291 // This will fail if the media player has not been initialized yet. This 292 // can be the case if setDisplay() on MediaPlayer.java has been called 293 // before setDataSource(). The redundant call to setVideoSurfaceTexture() 294 // in prepare/prepareAsync covers for this case. 295 mp->setVideoSurfaceTexture(new_st); 296 } 297 298 static void 299 android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface) 300 { 301 setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */); 302 } 303 304 static void 305 android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz) 306 { 307 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 308 if (mp == NULL ) { 309 jniThrowException(env, "java/lang/IllegalStateException", NULL); 310 return; 311 } 312 313 // Handle the case where the display surface was set before the mp was 314 // initialized. We try again to make it stick. 315 sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz); 316 mp->setVideoSurfaceTexture(st); 317 318 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." ); 319 } 320 321 static void 322 android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz) 323 { 324 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 325 if (mp == NULL ) { 326 jniThrowException(env, "java/lang/IllegalStateException", NULL); 327 return; 328 } 329 330 // Handle the case where the display surface was set before the mp was 331 // initialized. We try again to make it stick. 332 sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz); 333 mp->setVideoSurfaceTexture(st); 334 335 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." ); 336 } 337 338 static void 339 android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) 340 { 341 ALOGV("start"); 342 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 343 if (mp == NULL ) { 344 jniThrowException(env, "java/lang/IllegalStateException", NULL); 345 return; 346 } 347 process_media_player_call( env, thiz, mp->start(), NULL, NULL ); 348 } 349 350 static void 351 android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz) 352 { 353 ALOGV("stop"); 354 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 355 if (mp == NULL ) { 356 jniThrowException(env, "java/lang/IllegalStateException", NULL); 357 return; 358 } 359 process_media_player_call( env, thiz, mp->stop(), NULL, NULL ); 360 } 361 362 static void 363 android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz) 364 { 365 ALOGV("pause"); 366 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 367 if (mp == NULL ) { 368 jniThrowException(env, "java/lang/IllegalStateException", NULL); 369 return; 370 } 371 process_media_player_call( env, thiz, mp->pause(), NULL, NULL ); 372 } 373 374 static jboolean 375 android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz) 376 { 377 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 378 if (mp == NULL ) { 379 jniThrowException(env, "java/lang/IllegalStateException", NULL); 380 return false; 381 } 382 const jboolean is_playing = mp->isPlaying(); 383 384 ALOGV("isPlaying: %d", is_playing); 385 return is_playing; 386 } 387 388 static void 389 android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec) 390 { 391 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 392 if (mp == NULL ) { 393 jniThrowException(env, "java/lang/IllegalStateException", NULL); 394 return; 395 } 396 ALOGV("seekTo: %d(msec)", msec); 397 process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL ); 398 } 399 400 static int 401 android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz) 402 { 403 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 404 if (mp == NULL ) { 405 jniThrowException(env, "java/lang/IllegalStateException", NULL); 406 return 0; 407 } 408 int w; 409 if (0 != mp->getVideoWidth(&w)) { 410 ALOGE("getVideoWidth failed"); 411 w = 0; 412 } 413 ALOGV("getVideoWidth: %d", w); 414 return w; 415 } 416 417 static int 418 android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz) 419 { 420 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 421 if (mp == NULL ) { 422 jniThrowException(env, "java/lang/IllegalStateException", NULL); 423 return 0; 424 } 425 int h; 426 if (0 != mp->getVideoHeight(&h)) { 427 ALOGE("getVideoHeight failed"); 428 h = 0; 429 } 430 ALOGV("getVideoHeight: %d", h); 431 return h; 432 } 433 434 435 static int 436 android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz) 437 { 438 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 439 if (mp == NULL ) { 440 jniThrowException(env, "java/lang/IllegalStateException", NULL); 441 return 0; 442 } 443 int msec; 444 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL ); 445 ALOGV("getCurrentPosition: %d (msec)", msec); 446 return msec; 447 } 448 449 static int 450 android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz) 451 { 452 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 453 if (mp == NULL ) { 454 jniThrowException(env, "java/lang/IllegalStateException", NULL); 455 return 0; 456 } 457 int msec; 458 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL ); 459 ALOGV("getDuration: %d (msec)", msec); 460 return msec; 461 } 462 463 static void 464 android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz) 465 { 466 ALOGV("reset"); 467 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 468 if (mp == NULL ) { 469 jniThrowException(env, "java/lang/IllegalStateException", NULL); 470 return; 471 } 472 process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); 473 } 474 475 static void 476 android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype) 477 { 478 ALOGV("setAudioStreamType: %d", streamtype); 479 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 480 if (mp == NULL ) { 481 jniThrowException(env, "java/lang/IllegalStateException", NULL); 482 return; 483 } 484 process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL ); 485 } 486 487 static void 488 android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping) 489 { 490 ALOGV("setLooping: %d", looping); 491 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 492 if (mp == NULL ) { 493 jniThrowException(env, "java/lang/IllegalStateException", NULL); 494 return; 495 } 496 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL ); 497 } 498 499 static jboolean 500 android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz) 501 { 502 ALOGV("isLooping"); 503 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 504 if (mp == NULL ) { 505 jniThrowException(env, "java/lang/IllegalStateException", NULL); 506 return false; 507 } 508 return mp->isLooping(); 509 } 510 511 static void 512 android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume) 513 { 514 ALOGV("setVolume: left %f right %f", leftVolume, rightVolume); 515 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 516 if (mp == NULL ) { 517 jniThrowException(env, "java/lang/IllegalStateException", NULL); 518 return; 519 } 520 process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL ); 521 } 522 523 // FIXME: deprecated 524 static jobject 525 android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) 526 { 527 return NULL; 528 } 529 530 531 // Sends the request and reply parcels to the media player via the 532 // binder interface. 533 static jint 534 android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz, 535 jobject java_request, jobject java_reply) 536 { 537 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 538 if (media_player == NULL ) { 539 jniThrowException(env, "java/lang/IllegalStateException", NULL); 540 return UNKNOWN_ERROR; 541 } 542 543 Parcel *request = parcelForJavaObject(env, java_request); 544 Parcel *reply = parcelForJavaObject(env, java_reply); 545 546 // Don't use process_media_player_call which use the async loop to 547 // report errors, instead returns the status. 548 return media_player->invoke(*request, reply); 549 } 550 551 // Sends the new filter to the client. 552 static jint 553 android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request) 554 { 555 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 556 if (media_player == NULL ) { 557 jniThrowException(env, "java/lang/IllegalStateException", NULL); 558 return UNKNOWN_ERROR; 559 } 560 561 Parcel *filter = parcelForJavaObject(env, request); 562 563 if (filter == NULL ) { 564 jniThrowException(env, "java/lang/RuntimeException", "Filter is null"); 565 return UNKNOWN_ERROR; 566 } 567 568 return media_player->setMetadataFilter(*filter); 569 } 570 571 static jboolean 572 android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, 573 jboolean apply_filter, jobject reply) 574 { 575 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 576 if (media_player == NULL ) { 577 jniThrowException(env, "java/lang/IllegalStateException", NULL); 578 return false; 579 } 580 581 Parcel *metadata = parcelForJavaObject(env, reply); 582 583 if (metadata == NULL ) { 584 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null"); 585 return false; 586 } 587 588 metadata->freeData(); 589 // On return metadata is positioned at the beginning of the 590 // metadata. Note however that the parcel actually starts with the 591 // return code so you should not rewind the parcel using 592 // setDataPosition(0). 593 return media_player->getMetadata(update_only, apply_filter, metadata) == OK; 594 } 595 596 // This function gets some field IDs, which in turn causes class initialization. 597 // It is called from a static block in MediaPlayer, which won't run until the 598 // first time an instance of this class is used. 599 static void 600 android_media_MediaPlayer_native_init(JNIEnv *env) 601 { 602 jclass clazz; 603 604 clazz = env->FindClass("android/media/MediaPlayer"); 605 if (clazz == NULL) { 606 return; 607 } 608 609 fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 610 if (fields.context == NULL) { 611 return; 612 } 613 614 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 615 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 616 if (fields.post_event == NULL) { 617 return; 618 } 619 620 fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "I"); 621 if (fields.surface_texture == NULL) { 622 return; 623 } 624 } 625 626 static void 627 android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) 628 { 629 ALOGV("native_setup"); 630 sp<MediaPlayer> mp = new MediaPlayer(); 631 if (mp == NULL) { 632 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 633 return; 634 } 635 636 // create new listener and give it to MediaPlayer 637 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); 638 mp->setListener(listener); 639 640 // Stow our new C++ MediaPlayer in an opaque field in the Java object. 641 setMediaPlayer(env, thiz, mp); 642 } 643 644 static void 645 android_media_MediaPlayer_release(JNIEnv *env, jobject thiz) 646 { 647 ALOGV("release"); 648 decVideoSurfaceRef(env, thiz); 649 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0); 650 if (mp != NULL) { 651 // this prevents native callbacks after the object is released 652 mp->setListener(0); 653 mp->disconnect(); 654 } 655 } 656 657 static void 658 android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz) 659 { 660 ALOGV("native_finalize"); 661 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 662 if (mp != NULL) { 663 ALOGW("MediaPlayer finalized without being released"); 664 } 665 android_media_MediaPlayer_release(env, thiz); 666 } 667 668 static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) { 669 ALOGV("set_session_id(): %d", sessionId); 670 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 671 if (mp == NULL ) { 672 jniThrowException(env, "java/lang/IllegalStateException", NULL); 673 return; 674 } 675 process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL ); 676 } 677 678 static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) { 679 ALOGV("get_session_id()"); 680 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 681 if (mp == NULL ) { 682 jniThrowException(env, "java/lang/IllegalStateException", NULL); 683 return 0; 684 } 685 686 return mp->getAudioSessionId(); 687 } 688 689 static void 690 android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level) 691 { 692 ALOGV("setAuxEffectSendLevel: level %f", level); 693 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 694 if (mp == NULL ) { 695 jniThrowException(env, "java/lang/IllegalStateException", NULL); 696 return; 697 } 698 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL ); 699 } 700 701 static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) { 702 ALOGV("attachAuxEffect(): %d", effectId); 703 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 704 if (mp == NULL ) { 705 jniThrowException(env, "java/lang/IllegalStateException", NULL); 706 return; 707 } 708 process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL ); 709 } 710 711 static jint 712 android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply) 713 { 714 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player")); 715 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 716 if (service.get() == NULL) { 717 jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService"); 718 return UNKNOWN_ERROR; 719 } 720 721 Parcel *reply = parcelForJavaObject(env, java_reply); 722 723 return service->pullBatteryData(reply); 724 } 725 726 static jint 727 android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz, 728 jstring addrString, jint port) { 729 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 730 if (mp == NULL ) { 731 jniThrowException(env, "java/lang/IllegalStateException", NULL); 732 return INVALID_OPERATION; 733 } 734 735 const char *cAddrString = NULL; 736 737 if (NULL != addrString) { 738 cAddrString = env->GetStringUTFChars(addrString, NULL); 739 if (cAddrString == NULL) { // Out of memory 740 return NO_MEMORY; 741 } 742 } 743 ALOGV("setRetransmitEndpoint: %s:%d", 744 cAddrString ? cAddrString : "(null)", port); 745 746 status_t ret; 747 if (cAddrString && (port > 0xFFFF)) { 748 ret = BAD_VALUE; 749 } else { 750 ret = mp->setRetransmitEndpoint(cAddrString, 751 static_cast<uint16_t>(port)); 752 } 753 754 if (NULL != addrString) { 755 env->ReleaseStringUTFChars(addrString, cAddrString); 756 } 757 758 if (ret == INVALID_OPERATION ) { 759 jniThrowException(env, "java/lang/IllegalStateException", NULL); 760 } 761 762 return ret; 763 } 764 765 static jboolean 766 android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request) 767 { 768 ALOGV("setParameter: key %d", key); 769 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 770 if (mp == NULL ) { 771 jniThrowException(env, "java/lang/IllegalStateException", NULL); 772 return false; 773 } 774 775 Parcel *request = parcelForJavaObject(env, java_request); 776 status_t err = mp->setParameter(key, *request); 777 if (err == OK) { 778 return true; 779 } else { 780 return false; 781 } 782 } 783 784 static void 785 android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply) 786 { 787 ALOGV("getParameter: key %d", key); 788 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 789 if (mp == NULL ) { 790 jniThrowException(env, "java/lang/IllegalStateException", NULL); 791 return; 792 } 793 794 Parcel *reply = parcelForJavaObject(env, java_reply); 795 process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL ); 796 } 797 798 static void 799 android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player) 800 { 801 ALOGV("setNextMediaPlayer"); 802 sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz); 803 if (thisplayer == NULL) { 804 jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized"); 805 return; 806 } 807 sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player); 808 if (nextplayer == NULL && java_player != NULL) { 809 jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized"); 810 return; 811 } 812 813 if (nextplayer == thisplayer) { 814 jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self"); 815 return; 816 } 817 // tie the two players together 818 process_media_player_call( 819 env, thiz, thisplayer->setNextMediaPlayer(nextplayer), 820 "java/lang/IllegalArgumentException", 821 "setNextMediaPlayer failed." ); 822 ; 823 } 824 825 // ---------------------------------------------------------------------------- 826 827 static JNINativeMethod gMethods[] = { 828 { 829 "_setDataSource", 830 "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", 831 (void *)android_media_MediaPlayer_setDataSourceAndHeaders 832 }, 833 834 {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, 835 {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface}, 836 {"prepare", "()V", (void *)android_media_MediaPlayer_prepare}, 837 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, 838 {"_start", "()V", (void *)android_media_MediaPlayer_start}, 839 {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, 840 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, 841 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, 842 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, 843 {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, 844 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, 845 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, 846 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, 847 {"_release", "()V", (void *)android_media_MediaPlayer_release}, 848 {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, 849 {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, 850 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, 851 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, 852 {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, 853 {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, 854 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, 855 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, 856 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, 857 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, 858 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, 859 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, 860 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, 861 {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, 862 {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, 863 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, 864 {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, 865 {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter}, 866 {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter}, 867 {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, 868 {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer}, 869 }; 870 871 static const char* const kClassPathName = "android/media/MediaPlayer"; 872 873 // This function only registers the native methods 874 static int register_android_media_MediaPlayer(JNIEnv *env) 875 { 876 return AndroidRuntime::registerNativeMethods(env, 877 "android/media/MediaPlayer", gMethods, NELEM(gMethods)); 878 } 879 880 extern int register_android_media_Crypto(JNIEnv *env); 881 extern int register_android_media_MediaCodec(JNIEnv *env); 882 extern int register_android_media_MediaExtractor(JNIEnv *env); 883 extern int register_android_media_MediaCodecList(JNIEnv *env); 884 extern int register_android_media_MediaMetadataRetriever(JNIEnv *env); 885 extern int register_android_media_MediaRecorder(JNIEnv *env); 886 extern int register_android_media_MediaScanner(JNIEnv *env); 887 extern int register_android_media_ResampleInputStream(JNIEnv *env); 888 extern int register_android_media_MediaProfiles(JNIEnv *env); 889 extern int register_android_media_AmrInputStream(JNIEnv *env); 890 extern int register_android_mtp_MtpDatabase(JNIEnv *env); 891 extern int register_android_mtp_MtpDevice(JNIEnv *env); 892 extern int register_android_mtp_MtpServer(JNIEnv *env); 893 894 jint JNI_OnLoad(JavaVM* vm, void* reserved) 895 { 896 JNIEnv* env = NULL; 897 jint result = -1; 898 899 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 900 ALOGE("ERROR: GetEnv failed\n"); 901 goto bail; 902 } 903 assert(env != NULL); 904 905 if (register_android_media_MediaPlayer(env) < 0) { 906 ALOGE("ERROR: MediaPlayer native registration failed\n"); 907 goto bail; 908 } 909 910 if (register_android_media_MediaRecorder(env) < 0) { 911 ALOGE("ERROR: MediaRecorder native registration failed\n"); 912 goto bail; 913 } 914 915 if (register_android_media_MediaScanner(env) < 0) { 916 ALOGE("ERROR: MediaScanner native registration failed\n"); 917 goto bail; 918 } 919 920 if (register_android_media_MediaMetadataRetriever(env) < 0) { 921 ALOGE("ERROR: MediaMetadataRetriever native registration failed\n"); 922 goto bail; 923 } 924 925 if (register_android_media_AmrInputStream(env) < 0) { 926 ALOGE("ERROR: AmrInputStream native registration failed\n"); 927 goto bail; 928 } 929 930 if (register_android_media_ResampleInputStream(env) < 0) { 931 ALOGE("ERROR: ResampleInputStream native registration failed\n"); 932 goto bail; 933 } 934 935 if (register_android_media_MediaProfiles(env) < 0) { 936 ALOGE("ERROR: MediaProfiles native registration failed"); 937 goto bail; 938 } 939 940 if (register_android_mtp_MtpDatabase(env) < 0) { 941 ALOGE("ERROR: MtpDatabase native registration failed"); 942 goto bail; 943 } 944 945 if (register_android_mtp_MtpDevice(env) < 0) { 946 ALOGE("ERROR: MtpDevice native registration failed"); 947 goto bail; 948 } 949 950 if (register_android_mtp_MtpServer(env) < 0) { 951 ALOGE("ERROR: MtpServer native registration failed"); 952 goto bail; 953 } 954 955 if (register_android_media_MediaCodec(env) < 0) { 956 ALOGE("ERROR: MediaCodec native registration failed"); 957 goto bail; 958 } 959 960 if (register_android_media_MediaExtractor(env) < 0) { 961 ALOGE("ERROR: MediaCodec native registration failed"); 962 goto bail; 963 } 964 965 if (register_android_media_MediaCodecList(env) < 0) { 966 ALOGE("ERROR: MediaCodec native registration failed"); 967 goto bail; 968 } 969 970 if (register_android_media_Crypto(env) < 0) { 971 ALOGE("ERROR: MediaCodec native registration failed"); 972 goto bail; 973 } 974 975 /* success -- return valid version number */ 976 result = JNI_VERSION_1_4; 977 978 bail: 979 return result; 980 } 981 982 // KTHXBYE 983