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