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