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