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