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