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