android_media_MediaPlayer.cpp revision 99f752149b1a0df9ea0ba311d609d4d6e103787c
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 49using namespace android; 50 51// ---------------------------------------------------------------------------- 52 53struct 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}; 63static fields_t fields; 64 65static Mutex sLock; 66 67// ---------------------------------------------------------------------------- 68// ref-counted object for callbacks 69class JNIMediaPlayerListener: public MediaPlayerListener 70{ 71public: 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); 75private: 76 JNIMediaPlayerListener(); 77 jclass mClass; // Reference to MediaPlayer class 78 jobject mObject; // Weak ref to MediaPlayer Java object to call on 79}; 80 81JNIMediaPlayerListener::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 99JNIMediaPlayerListener::~JNIMediaPlayerListener() 100{ 101 // remove global references 102 JNIEnv *env = AndroidRuntime::getJNIEnv(); 103 env->DeleteGlobalRef(mObject); 104 env->DeleteGlobalRef(mClass); 105} 106 107void 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 env->DeleteLocalRef(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 132static 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 139static 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. 157static 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 183static void 184android_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 226static void 227android_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 244static sp<IGraphicBufferProducer> 245getVideoSurfaceTexture(JNIEnv* env, jobject thiz) { 246 IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetIntField(thiz, fields.surface_texture); 247 return sp<IGraphicBufferProducer>(p); 248} 249 250static void 251decVideoSurfaceRef(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 264static void 265setVideoSurface(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 304static void 305android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface) 306{ 307 setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */); 308} 309 310static void 311android_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 327static void 328android_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 344static void 345android_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 356static void 357android_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 368static void 369android_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 380static jboolean 381android_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 394static void 395android_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 406static int 407android_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 423static int 424android_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 441static int 442android_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 455static int 456android_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 469static void 470android_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 481static void 482android_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 493static void 494android_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 505static jboolean 506android_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 517static void 518android_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// FIXME: deprecated 530static jobject 531android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) 532{ 533 return NULL; 534} 535 536 537// Sends the request and reply parcels to the media player via the 538// binder interface. 539static jint 540android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz, 541 jobject java_request, jobject java_reply) 542{ 543 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 544 if (media_player == NULL ) { 545 jniThrowException(env, "java/lang/IllegalStateException", NULL); 546 return UNKNOWN_ERROR; 547 } 548 549 Parcel *request = parcelForJavaObject(env, java_request); 550 Parcel *reply = parcelForJavaObject(env, java_reply); 551 552 // Don't use process_media_player_call which use the async loop to 553 // report errors, instead returns the status. 554 return media_player->invoke(*request, reply); 555} 556 557// Sends the new filter to the client. 558static jint 559android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request) 560{ 561 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 562 if (media_player == NULL ) { 563 jniThrowException(env, "java/lang/IllegalStateException", NULL); 564 return UNKNOWN_ERROR; 565 } 566 567 Parcel *filter = parcelForJavaObject(env, request); 568 569 if (filter == NULL ) { 570 jniThrowException(env, "java/lang/RuntimeException", "Filter is null"); 571 return UNKNOWN_ERROR; 572 } 573 574 return media_player->setMetadataFilter(*filter); 575} 576 577static jboolean 578android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, 579 jboolean apply_filter, jobject reply) 580{ 581 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 582 if (media_player == NULL ) { 583 jniThrowException(env, "java/lang/IllegalStateException", NULL); 584 return false; 585 } 586 587 Parcel *metadata = parcelForJavaObject(env, reply); 588 589 if (metadata == NULL ) { 590 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null"); 591 return false; 592 } 593 594 metadata->freeData(); 595 // On return metadata is positioned at the beginning of the 596 // metadata. Note however that the parcel actually starts with the 597 // return code so you should not rewind the parcel using 598 // setDataPosition(0). 599 return media_player->getMetadata(update_only, apply_filter, metadata) == OK; 600} 601 602// This function gets some field IDs, which in turn causes class initialization. 603// It is called from a static block in MediaPlayer, which won't run until the 604// first time an instance of this class is used. 605static void 606android_media_MediaPlayer_native_init(JNIEnv *env) 607{ 608 jclass clazz; 609 610 clazz = env->FindClass("android/media/MediaPlayer"); 611 if (clazz == NULL) { 612 return; 613 } 614 615 fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 616 if (fields.context == NULL) { 617 return; 618 } 619 620 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 621 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 622 if (fields.post_event == NULL) { 623 return; 624 } 625 626 fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "I"); 627 if (fields.surface_texture == NULL) { 628 return; 629 } 630 631 clazz = env->FindClass("android/net/ProxyProperties"); 632 if (clazz == NULL) { 633 return; 634 } 635 636 fields.proxyConfigGetHost = 637 env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;"); 638 639 fields.proxyConfigGetPort = 640 env->GetMethodID(clazz, "getPort", "()I"); 641 642 fields.proxyConfigGetExclusionList = 643 env->GetMethodID(clazz, "getExclusionList", "()Ljava/lang/String;"); 644} 645 646static void 647android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) 648{ 649 ALOGV("native_setup"); 650 sp<MediaPlayer> mp = new MediaPlayer(); 651 if (mp == NULL) { 652 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 653 return; 654 } 655 656 // create new listener and give it to MediaPlayer 657 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); 658 mp->setListener(listener); 659 660 // Stow our new C++ MediaPlayer in an opaque field in the Java object. 661 setMediaPlayer(env, thiz, mp); 662} 663 664static void 665android_media_MediaPlayer_release(JNIEnv *env, jobject thiz) 666{ 667 ALOGV("release"); 668 decVideoSurfaceRef(env, thiz); 669 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0); 670 if (mp != NULL) { 671 // this prevents native callbacks after the object is released 672 mp->setListener(0); 673 mp->disconnect(); 674 } 675} 676 677static void 678android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz) 679{ 680 ALOGV("native_finalize"); 681 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 682 if (mp != NULL) { 683 ALOGW("MediaPlayer finalized without being released"); 684 } 685 android_media_MediaPlayer_release(env, thiz); 686} 687 688static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) { 689 ALOGV("set_session_id(): %d", sessionId); 690 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 691 if (mp == NULL ) { 692 jniThrowException(env, "java/lang/IllegalStateException", NULL); 693 return; 694 } 695 process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL ); 696} 697 698static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) { 699 ALOGV("get_session_id()"); 700 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 701 if (mp == NULL ) { 702 jniThrowException(env, "java/lang/IllegalStateException", NULL); 703 return 0; 704 } 705 706 return mp->getAudioSessionId(); 707} 708 709static void 710android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level) 711{ 712 ALOGV("setAuxEffectSendLevel: level %f", level); 713 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 714 if (mp == NULL ) { 715 jniThrowException(env, "java/lang/IllegalStateException", NULL); 716 return; 717 } 718 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL ); 719} 720 721static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) { 722 ALOGV("attachAuxEffect(): %d", effectId); 723 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 724 if (mp == NULL ) { 725 jniThrowException(env, "java/lang/IllegalStateException", NULL); 726 return; 727 } 728 process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL ); 729} 730 731static jint 732android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply) 733{ 734 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player")); 735 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 736 if (service.get() == NULL) { 737 jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService"); 738 return UNKNOWN_ERROR; 739 } 740 741 Parcel *reply = parcelForJavaObject(env, java_reply); 742 743 return service->pullBatteryData(reply); 744} 745 746static jint 747android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz, 748 jstring addrString, jint port) { 749 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 750 if (mp == NULL ) { 751 jniThrowException(env, "java/lang/IllegalStateException", NULL); 752 return INVALID_OPERATION; 753 } 754 755 const char *cAddrString = NULL; 756 757 if (NULL != addrString) { 758 cAddrString = env->GetStringUTFChars(addrString, NULL); 759 if (cAddrString == NULL) { // Out of memory 760 return NO_MEMORY; 761 } 762 } 763 ALOGV("setRetransmitEndpoint: %s:%d", 764 cAddrString ? cAddrString : "(null)", port); 765 766 status_t ret; 767 if (cAddrString && (port > 0xFFFF)) { 768 ret = BAD_VALUE; 769 } else { 770 ret = mp->setRetransmitEndpoint(cAddrString, 771 static_cast<uint16_t>(port)); 772 } 773 774 if (NULL != addrString) { 775 env->ReleaseStringUTFChars(addrString, cAddrString); 776 } 777 778 if (ret == INVALID_OPERATION ) { 779 jniThrowException(env, "java/lang/IllegalStateException", NULL); 780 } 781 782 return ret; 783} 784 785static jboolean 786android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request) 787{ 788 ALOGV("setParameter: key %d", key); 789 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 790 if (mp == NULL ) { 791 jniThrowException(env, "java/lang/IllegalStateException", NULL); 792 return false; 793 } 794 795 Parcel *request = parcelForJavaObject(env, java_request); 796 status_t err = mp->setParameter(key, *request); 797 if (err == OK) { 798 return true; 799 } else { 800 return false; 801 } 802} 803 804static void 805android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply) 806{ 807 ALOGV("getParameter: key %d", key); 808 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 809 if (mp == NULL ) { 810 jniThrowException(env, "java/lang/IllegalStateException", NULL); 811 return; 812 } 813 814 Parcel *reply = parcelForJavaObject(env, java_reply); 815 process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL ); 816} 817 818static void 819android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player) 820{ 821 ALOGV("setNextMediaPlayer"); 822 sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz); 823 if (thisplayer == NULL) { 824 jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized"); 825 return; 826 } 827 sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player); 828 if (nextplayer == NULL && java_player != NULL) { 829 jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized"); 830 return; 831 } 832 833 if (nextplayer == thisplayer) { 834 jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self"); 835 return; 836 } 837 // tie the two players together 838 process_media_player_call( 839 env, thiz, thisplayer->setNextMediaPlayer(nextplayer), 840 "java/lang/IllegalArgumentException", 841 "setNextMediaPlayer failed." ); 842 ; 843} 844 845static void 846android_media_MediaPlayer_updateProxyConfig( 847 JNIEnv *env, jobject thiz, jobject proxyProps) 848{ 849 ALOGV("updateProxyConfig"); 850 sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz); 851 if (thisplayer == NULL) { 852 return; 853 } 854 855 if (proxyProps == NULL) { 856 thisplayer->updateProxyConfig( 857 NULL /* host */, 0 /* port */, NULL /* exclusionList */); 858 } else { 859 jstring hostObj = (jstring)env->CallObjectMethod( 860 proxyProps, fields.proxyConfigGetHost); 861 862 const char *host = env->GetStringUTFChars(hostObj, NULL); 863 864 int port = env->CallIntMethod(proxyProps, fields.proxyConfigGetPort); 865 866 jstring exclusionListObj = (jstring)env->CallObjectMethod( 867 proxyProps, fields.proxyConfigGetExclusionList); 868 869 const char *exclusionList = 870 env->GetStringUTFChars(exclusionListObj, NULL); 871 872 if (host != NULL && exclusionListObj != NULL) { 873 thisplayer->updateProxyConfig(host, port, exclusionList); 874 } 875 876 if (exclusionList != NULL) { 877 env->ReleaseStringUTFChars(exclusionListObj, exclusionList); 878 exclusionList = NULL; 879 } 880 881 if (host != NULL) { 882 env->ReleaseStringUTFChars(hostObj, host); 883 host = NULL; 884 } 885 } 886} 887 888// ---------------------------------------------------------------------------- 889 890static JNINativeMethod gMethods[] = { 891 { 892 "_setDataSource", 893 "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", 894 (void *)android_media_MediaPlayer_setDataSourceAndHeaders 895 }, 896 897 {"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, 898 {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface}, 899 {"prepare", "()V", (void *)android_media_MediaPlayer_prepare}, 900 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, 901 {"_start", "()V", (void *)android_media_MediaPlayer_start}, 902 {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, 903 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, 904 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, 905 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, 906 {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, 907 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, 908 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, 909 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, 910 {"_release", "()V", (void *)android_media_MediaPlayer_release}, 911 {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, 912 {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, 913 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, 914 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, 915 {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, 916 {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, 917 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, 918 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, 919 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, 920 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, 921 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, 922 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, 923 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, 924 {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, 925 {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, 926 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, 927 {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, 928 {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter}, 929 {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter}, 930 {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, 931 {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer}, 932 {"updateProxyConfig", "(Landroid/net/ProxyProperties;)V", (void *)android_media_MediaPlayer_updateProxyConfig}, 933}; 934 935static const char* const kClassPathName = "android/media/MediaPlayer"; 936 937// This function only registers the native methods 938static int register_android_media_MediaPlayer(JNIEnv *env) 939{ 940 return AndroidRuntime::registerNativeMethods(env, 941 "android/media/MediaPlayer", gMethods, NELEM(gMethods)); 942} 943 944extern int register_android_media_Crypto(JNIEnv *env); 945extern int register_android_media_Drm(JNIEnv *env); 946extern int register_android_media_MediaCodec(JNIEnv *env); 947extern int register_android_media_MediaExtractor(JNIEnv *env); 948extern int register_android_media_MediaCodecList(JNIEnv *env); 949extern int register_android_media_MediaMetadataRetriever(JNIEnv *env); 950extern int register_android_media_MediaMuxer(JNIEnv *env); 951extern int register_android_media_MediaRecorder(JNIEnv *env); 952extern int register_android_media_MediaScanner(JNIEnv *env); 953extern int register_android_media_ResampleInputStream(JNIEnv *env); 954extern int register_android_media_MediaProfiles(JNIEnv *env); 955extern int register_android_media_AmrInputStream(JNIEnv *env); 956extern int register_android_mtp_MtpDatabase(JNIEnv *env); 957extern int register_android_mtp_MtpDevice(JNIEnv *env); 958extern int register_android_mtp_MtpServer(JNIEnv *env); 959 960jint JNI_OnLoad(JavaVM* vm, void* reserved) 961{ 962 JNIEnv* env = NULL; 963 jint result = -1; 964 965 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 966 ALOGE("ERROR: GetEnv failed\n"); 967 goto bail; 968 } 969 assert(env != NULL); 970 971 if (register_android_media_MediaPlayer(env) < 0) { 972 ALOGE("ERROR: MediaPlayer native registration failed\n"); 973 goto bail; 974 } 975 976 if (register_android_media_MediaRecorder(env) < 0) { 977 ALOGE("ERROR: MediaRecorder native registration failed\n"); 978 goto bail; 979 } 980 981 if (register_android_media_MediaScanner(env) < 0) { 982 ALOGE("ERROR: MediaScanner native registration failed\n"); 983 goto bail; 984 } 985 986 if (register_android_media_MediaMetadataRetriever(env) < 0) { 987 ALOGE("ERROR: MediaMetadataRetriever native registration failed\n"); 988 goto bail; 989 } 990 991 if (register_android_media_AmrInputStream(env) < 0) { 992 ALOGE("ERROR: AmrInputStream native registration failed\n"); 993 goto bail; 994 } 995 996 if (register_android_media_ResampleInputStream(env) < 0) { 997 ALOGE("ERROR: ResampleInputStream native registration failed\n"); 998 goto bail; 999 } 1000 1001 if (register_android_media_MediaProfiles(env) < 0) { 1002 ALOGE("ERROR: MediaProfiles native registration failed"); 1003 goto bail; 1004 } 1005 1006 if (register_android_mtp_MtpDatabase(env) < 0) { 1007 ALOGE("ERROR: MtpDatabase native registration failed"); 1008 goto bail; 1009 } 1010 1011 if (register_android_mtp_MtpDevice(env) < 0) { 1012 ALOGE("ERROR: MtpDevice native registration failed"); 1013 goto bail; 1014 } 1015 1016 if (register_android_mtp_MtpServer(env) < 0) { 1017 ALOGE("ERROR: MtpServer native registration failed"); 1018 goto bail; 1019 } 1020 1021 if (register_android_media_MediaCodec(env) < 0) { 1022 ALOGE("ERROR: MediaCodec native registration failed"); 1023 goto bail; 1024 } 1025 1026 if (register_android_media_MediaExtractor(env) < 0) { 1027 ALOGE("ERROR: MediaCodec native registration failed"); 1028 goto bail; 1029 } 1030 1031 if (register_android_media_MediaMuxer(env) < 0) { 1032 ALOGE("ERROR: MediaMuxer native registration failed"); 1033 goto bail; 1034 } 1035 1036 if (register_android_media_MediaCodecList(env) < 0) { 1037 ALOGE("ERROR: MediaCodec native registration failed"); 1038 goto bail; 1039 } 1040 1041 if (register_android_media_Crypto(env) < 0) { 1042 ALOGE("ERROR: MediaCodec native registration failed"); 1043 goto bail; 1044 } 1045 1046 if (register_android_media_Drm(env) < 0) { 1047 ALOGE("ERROR: MediaDrm native registration failed"); 1048 goto bail; 1049 } 1050 1051 /* success -- return valid version number */ 1052 result = JNI_VERSION_1_4; 1053 1054bail: 1055 return result; 1056} 1057 1058// KTHXBYE 1059