android_media_MediaPlayer.cpp revision 8902097bb686752ff207e3bda12713be1a8c74eb
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/ISurfaceTexture.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}; 59static fields_t fields; 60 61static Mutex sLock; 62 63// ---------------------------------------------------------------------------- 64// ref-counted object for callbacks 65class JNIMediaPlayerListener: public MediaPlayerListener 66{ 67public: 68 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz); 69 ~JNIMediaPlayerListener(); 70 virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL); 71private: 72 JNIMediaPlayerListener(); 73 jclass mClass; // Reference to MediaPlayer class 74 jobject mObject; // Weak ref to MediaPlayer Java object to call on 75 jobject mParcel; 76}; 77 78JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz) 79{ 80 81 // Hold onto the MediaPlayer class for use in calling the static method 82 // that posts events to the application thread. 83 jclass clazz = env->GetObjectClass(thiz); 84 if (clazz == NULL) { 85 ALOGE("Can't find android/media/MediaPlayer"); 86 jniThrowException(env, "java/lang/Exception", NULL); 87 return; 88 } 89 mClass = (jclass)env->NewGlobalRef(clazz); 90 91 // We use a weak reference so the MediaPlayer object can be garbage collected. 92 // The reference is only used as a proxy for callbacks. 93 mObject = env->NewGlobalRef(weak_thiz); 94 mParcel = env->NewGlobalRef(createJavaParcelObject(env)); 95} 96 97JNIMediaPlayerListener::~JNIMediaPlayerListener() 98{ 99 // remove global references 100 JNIEnv *env = AndroidRuntime::getJNIEnv(); 101 env->DeleteGlobalRef(mObject); 102 env->DeleteGlobalRef(mClass); 103 104 recycleJavaParcelObject(env, mParcel); 105 env->DeleteGlobalRef(mParcel); 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 if (mParcel != NULL) { 113 Parcel* nativeParcel = parcelForJavaObject(env, mParcel); 114 nativeParcel->setData(obj->data(), obj->dataSize()); 115 env->CallStaticVoidMethod(mClass, fields.post_event, mObject, 116 msg, ext1, ext2, mParcel); 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(thiz); 144 } 145 if (old != 0) { 146 old->decStrong(thiz); 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<ISurfaceTexture> 244getVideoSurfaceTexture(JNIEnv* env, jobject thiz) { 245 ISurfaceTexture * const p = (ISurfaceTexture*)env->GetIntField(thiz, fields.surface_texture); 246 return sp<ISurfaceTexture>(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<ISurfaceTexture> old_st = getVideoSurfaceTexture(env, thiz); 258 if (old_st != NULL) { 259 old_st->decStrong(thiz); 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<ISurfaceTexture> new_st; 277 if (jsurface) { 278 sp<Surface> surface(Surface_getSurface(env, jsurface)); 279 if (surface != NULL) { 280 new_st = surface->getSurfaceTexture(); 281 new_st->incStrong(thiz); 282 } else { 283 jniThrowException(env, "java/lang/IllegalArgumentException", 284 "The surface has been released"); 285 return; 286 } 287 } 288 289 env->SetIntField(thiz, fields.surface_texture, (int)new_st.get()); 290 291 // This will fail if the media player has not been initialized yet. This 292 // can be the case if setDisplay() on MediaPlayer.java has been called 293 // before setDataSource(). The redundant call to setVideoSurfaceTexture() 294 // in prepare/prepareAsync covers for this case. 295 mp->setVideoSurfaceTexture(new_st); 296} 297 298static void 299android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface) 300{ 301 setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */); 302} 303 304static void 305android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz) 306{ 307 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 308 if (mp == NULL ) { 309 jniThrowException(env, "java/lang/IllegalStateException", NULL); 310 return; 311 } 312 313 // Handle the case where the display surface was set before the mp was 314 // initialized. We try again to make it stick. 315 sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz); 316 mp->setVideoSurfaceTexture(st); 317 318 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." ); 319} 320 321static void 322android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz) 323{ 324 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 325 if (mp == NULL ) { 326 jniThrowException(env, "java/lang/IllegalStateException", NULL); 327 return; 328 } 329 330 // Handle the case where the display surface was set before the mp was 331 // initialized. We try again to make it stick. 332 sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz); 333 mp->setVideoSurfaceTexture(st); 334 335 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." ); 336} 337 338static void 339android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) 340{ 341 ALOGV("start"); 342 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 343 if (mp == NULL ) { 344 jniThrowException(env, "java/lang/IllegalStateException", NULL); 345 return; 346 } 347 process_media_player_call( env, thiz, mp->start(), NULL, NULL ); 348} 349 350static void 351android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz) 352{ 353 ALOGV("stop"); 354 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 355 if (mp == NULL ) { 356 jniThrowException(env, "java/lang/IllegalStateException", NULL); 357 return; 358 } 359 process_media_player_call( env, thiz, mp->stop(), NULL, NULL ); 360} 361 362static void 363android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz) 364{ 365 ALOGV("pause"); 366 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 367 if (mp == NULL ) { 368 jniThrowException(env, "java/lang/IllegalStateException", NULL); 369 return; 370 } 371 process_media_player_call( env, thiz, mp->pause(), NULL, NULL ); 372} 373 374static jboolean 375android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz) 376{ 377 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 378 if (mp == NULL ) { 379 jniThrowException(env, "java/lang/IllegalStateException", NULL); 380 return false; 381 } 382 const jboolean is_playing = mp->isPlaying(); 383 384 ALOGV("isPlaying: %d", is_playing); 385 return is_playing; 386} 387 388static void 389android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec) 390{ 391 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 392 if (mp == NULL ) { 393 jniThrowException(env, "java/lang/IllegalStateException", NULL); 394 return; 395 } 396 ALOGV("seekTo: %d(msec)", msec); 397 process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL ); 398} 399 400static int 401android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz) 402{ 403 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 404 if (mp == NULL ) { 405 jniThrowException(env, "java/lang/IllegalStateException", NULL); 406 return 0; 407 } 408 int w; 409 if (0 != mp->getVideoWidth(&w)) { 410 ALOGE("getVideoWidth failed"); 411 w = 0; 412 } 413 ALOGV("getVideoWidth: %d", w); 414 return w; 415} 416 417static int 418android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz) 419{ 420 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 421 if (mp == NULL ) { 422 jniThrowException(env, "java/lang/IllegalStateException", NULL); 423 return 0; 424 } 425 int h; 426 if (0 != mp->getVideoHeight(&h)) { 427 ALOGE("getVideoHeight failed"); 428 h = 0; 429 } 430 ALOGV("getVideoHeight: %d", h); 431 return h; 432} 433 434 435static int 436android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz) 437{ 438 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 439 if (mp == NULL ) { 440 jniThrowException(env, "java/lang/IllegalStateException", NULL); 441 return 0; 442 } 443 int msec; 444 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL ); 445 ALOGV("getCurrentPosition: %d (msec)", msec); 446 return msec; 447} 448 449static int 450android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz) 451{ 452 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 453 if (mp == NULL ) { 454 jniThrowException(env, "java/lang/IllegalStateException", NULL); 455 return 0; 456 } 457 int msec; 458 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL ); 459 ALOGV("getDuration: %d (msec)", msec); 460 return msec; 461} 462 463static void 464android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz) 465{ 466 ALOGV("reset"); 467 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 468 if (mp == NULL ) { 469 jniThrowException(env, "java/lang/IllegalStateException", NULL); 470 return; 471 } 472 process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); 473} 474 475static void 476android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype) 477{ 478 ALOGV("setAudioStreamType: %d", streamtype); 479 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 480 if (mp == NULL ) { 481 jniThrowException(env, "java/lang/IllegalStateException", NULL); 482 return; 483 } 484 process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL ); 485} 486 487static void 488android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping) 489{ 490 ALOGV("setLooping: %d", looping); 491 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 492 if (mp == NULL ) { 493 jniThrowException(env, "java/lang/IllegalStateException", NULL); 494 return; 495 } 496 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL ); 497} 498 499static jboolean 500android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz) 501{ 502 ALOGV("isLooping"); 503 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 504 if (mp == NULL ) { 505 jniThrowException(env, "java/lang/IllegalStateException", NULL); 506 return false; 507 } 508 return mp->isLooping(); 509} 510 511static void 512android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume) 513{ 514 ALOGV("setVolume: left %f right %f", leftVolume, rightVolume); 515 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 516 if (mp == NULL ) { 517 jniThrowException(env, "java/lang/IllegalStateException", NULL); 518 return; 519 } 520 process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL ); 521} 522 523// FIXME: deprecated 524static jobject 525android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) 526{ 527 return NULL; 528} 529 530 531// Sends the request and reply parcels to the media player via the 532// binder interface. 533static jint 534android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz, 535 jobject java_request, jobject java_reply) 536{ 537 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 538 if (media_player == NULL ) { 539 jniThrowException(env, "java/lang/IllegalStateException", NULL); 540 return UNKNOWN_ERROR; 541 } 542 543 Parcel *request = parcelForJavaObject(env, java_request); 544 Parcel *reply = parcelForJavaObject(env, java_reply); 545 546 // Don't use process_media_player_call which use the async loop to 547 // report errors, instead returns the status. 548 return media_player->invoke(*request, reply); 549} 550 551// Sends the new filter to the client. 552static jint 553android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request) 554{ 555 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 556 if (media_player == NULL ) { 557 jniThrowException(env, "java/lang/IllegalStateException", NULL); 558 return UNKNOWN_ERROR; 559 } 560 561 Parcel *filter = parcelForJavaObject(env, request); 562 563 if (filter == NULL ) { 564 jniThrowException(env, "java/lang/RuntimeException", "Filter is null"); 565 return UNKNOWN_ERROR; 566 } 567 568 return media_player->setMetadataFilter(*filter); 569} 570 571static jboolean 572android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, 573 jboolean apply_filter, jobject reply) 574{ 575 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 576 if (media_player == NULL ) { 577 jniThrowException(env, "java/lang/IllegalStateException", NULL); 578 return false; 579 } 580 581 Parcel *metadata = parcelForJavaObject(env, reply); 582 583 if (metadata == NULL ) { 584 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null"); 585 return false; 586 } 587 588 metadata->freeData(); 589 // On return metadata is positioned at the beginning of the 590 // metadata. Note however that the parcel actually starts with the 591 // return code so you should not rewind the parcel using 592 // setDataPosition(0). 593 return media_player->getMetadata(update_only, apply_filter, metadata) == OK; 594} 595 596// This function gets some field IDs, which in turn causes class initialization. 597// It is called from a static block in MediaPlayer, which won't run until the 598// first time an instance of this class is used. 599static void 600android_media_MediaPlayer_native_init(JNIEnv *env) 601{ 602 jclass clazz; 603 604 clazz = env->FindClass("android/media/MediaPlayer"); 605 if (clazz == NULL) { 606 return; 607 } 608 609 fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 610 if (fields.context == NULL) { 611 return; 612 } 613 614 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 615 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 616 if (fields.post_event == NULL) { 617 return; 618 } 619 620 fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "I"); 621 if (fields.surface_texture == NULL) { 622 return; 623 } 624} 625 626static void 627android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) 628{ 629 ALOGV("native_setup"); 630 sp<MediaPlayer> mp = new MediaPlayer(); 631 if (mp == NULL) { 632 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 633 return; 634 } 635 636 // create new listener and give it to MediaPlayer 637 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); 638 mp->setListener(listener); 639 640 // Stow our new C++ MediaPlayer in an opaque field in the Java object. 641 setMediaPlayer(env, thiz, mp); 642} 643 644static void 645android_media_MediaPlayer_release(JNIEnv *env, jobject thiz) 646{ 647 ALOGV("release"); 648 decVideoSurfaceRef(env, thiz); 649 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0); 650 if (mp != NULL) { 651 // this prevents native callbacks after the object is released 652 mp->setListener(0); 653 mp->disconnect(); 654 } 655} 656 657static void 658android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz) 659{ 660 ALOGV("native_finalize"); 661 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 662 if (mp != NULL) { 663 ALOGW("MediaPlayer finalized without being released"); 664 } 665 android_media_MediaPlayer_release(env, thiz); 666} 667 668static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) { 669 ALOGV("set_session_id(): %d", sessionId); 670 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 671 if (mp == NULL ) { 672 jniThrowException(env, "java/lang/IllegalStateException", NULL); 673 return; 674 } 675 process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL ); 676} 677 678static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) { 679 ALOGV("get_session_id()"); 680 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 681 if (mp == NULL ) { 682 jniThrowException(env, "java/lang/IllegalStateException", NULL); 683 return 0; 684 } 685 686 return mp->getAudioSessionId(); 687} 688 689static void 690android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level) 691{ 692 ALOGV("setAuxEffectSendLevel: level %f", level); 693 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 694 if (mp == NULL ) { 695 jniThrowException(env, "java/lang/IllegalStateException", NULL); 696 return; 697 } 698 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL ); 699} 700 701static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) { 702 ALOGV("attachAuxEffect(): %d", effectId); 703 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 704 if (mp == NULL ) { 705 jniThrowException(env, "java/lang/IllegalStateException", NULL); 706 return; 707 } 708 process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL ); 709} 710 711static jint 712android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply) 713{ 714 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player")); 715 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 716 if (service.get() == NULL) { 717 jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService"); 718 return UNKNOWN_ERROR; 719 } 720 721 Parcel *reply = parcelForJavaObject(env, java_reply); 722 723 return service->pullBatteryData(reply); 724} 725 726static jint 727android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz, 728 jstring addrString, jint port) { 729 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 730 if (mp == NULL ) { 731 jniThrowException(env, "java/lang/IllegalStateException", NULL); 732 return INVALID_OPERATION; 733 } 734 735 const char *cAddrString = NULL; 736 737 if (NULL != addrString) { 738 cAddrString = env->GetStringUTFChars(addrString, NULL); 739 if (cAddrString == NULL) { // Out of memory 740 return NO_MEMORY; 741 } 742 } 743 ALOGV("setRetransmitEndpoint: %s:%d", 744 cAddrString ? cAddrString : "(null)", port); 745 746 status_t ret; 747 if (cAddrString && (port > 0xFFFF)) { 748 ret = BAD_VALUE; 749 } else { 750 ret = mp->setRetransmitEndpoint(cAddrString, 751 static_cast<uint16_t>(port)); 752 } 753 754 if (NULL != addrString) { 755 env->ReleaseStringUTFChars(addrString, cAddrString); 756 } 757 758 if (ret == INVALID_OPERATION ) { 759 jniThrowException(env, "java/lang/IllegalStateException", NULL); 760 } 761 762 return ret; 763} 764 765static jboolean 766android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request) 767{ 768 ALOGV("setParameter: key %d", key); 769 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 770 if (mp == NULL ) { 771 jniThrowException(env, "java/lang/IllegalStateException", NULL); 772 return false; 773 } 774 775 Parcel *request = parcelForJavaObject(env, java_request); 776 status_t err = mp->setParameter(key, *request); 777 if (err == OK) { 778 return true; 779 } else { 780 return false; 781 } 782} 783 784static void 785android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply) 786{ 787 ALOGV("getParameter: key %d", key); 788 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 789 if (mp == NULL ) { 790 jniThrowException(env, "java/lang/IllegalStateException", NULL); 791 return; 792 } 793 794 Parcel *reply = parcelForJavaObject(env, java_reply); 795 process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL ); 796} 797 798static void 799android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player) 800{ 801 ALOGV("setNextMediaPlayer"); 802 sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz); 803 if (thisplayer == NULL) { 804 jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized"); 805 return; 806 } 807 sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player); 808 if (nextplayer == NULL && java_player != NULL) { 809 jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized"); 810 return; 811 } 812 813 if (nextplayer == thisplayer) { 814 jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self"); 815 return; 816 } 817 // tie the two players together 818 process_media_player_call( 819 env, thiz, thisplayer->setNextMediaPlayer(nextplayer), 820 "java/lang/IllegalArgumentException", 821 "setNextMediaPlayer failed." ); 822 ; 823} 824 825// ---------------------------------------------------------------------------- 826 827static JNINativeMethod gMethods[] = { 828 { 829 "_setDataSource", 830 "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V", 831 (void *)android_media_MediaPlayer_setDataSourceAndHeaders 832 }, 833 834 {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, 835 {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface}, 836 {"prepare", "()V", (void *)android_media_MediaPlayer_prepare}, 837 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, 838 {"_start", "()V", (void *)android_media_MediaPlayer_start}, 839 {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, 840 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, 841 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, 842 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, 843 {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, 844 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, 845 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, 846 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, 847 {"_release", "()V", (void *)android_media_MediaPlayer_release}, 848 {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, 849 {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, 850 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, 851 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, 852 {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, 853 {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, 854 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, 855 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, 856 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, 857 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, 858 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, 859 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, 860 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, 861 {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, 862 {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, 863 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, 864 {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, 865 {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter}, 866 {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter}, 867 {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, 868 {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer}, 869}; 870 871static const char* const kClassPathName = "android/media/MediaPlayer"; 872 873// This function only registers the native methods 874static int register_android_media_MediaPlayer(JNIEnv *env) 875{ 876 return AndroidRuntime::registerNativeMethods(env, 877 "android/media/MediaPlayer", gMethods, NELEM(gMethods)); 878} 879 880extern int register_android_media_Crypto(JNIEnv *env); 881extern int register_android_media_MediaCodec(JNIEnv *env); 882extern int register_android_media_MediaExtractor(JNIEnv *env); 883extern int register_android_media_MediaCodecList(JNIEnv *env); 884extern int register_android_media_MediaMetadataRetriever(JNIEnv *env); 885extern int register_android_media_MediaRecorder(JNIEnv *env); 886extern int register_android_media_MediaScanner(JNIEnv *env); 887extern int register_android_media_ResampleInputStream(JNIEnv *env); 888extern int register_android_media_MediaProfiles(JNIEnv *env); 889extern int register_android_media_AmrInputStream(JNIEnv *env); 890extern int register_android_mtp_MtpDatabase(JNIEnv *env); 891extern int register_android_mtp_MtpDevice(JNIEnv *env); 892extern int register_android_mtp_MtpServer(JNIEnv *env); 893 894jint JNI_OnLoad(JavaVM* vm, void* reserved) 895{ 896 JNIEnv* env = NULL; 897 jint result = -1; 898 899 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 900 ALOGE("ERROR: GetEnv failed\n"); 901 goto bail; 902 } 903 assert(env != NULL); 904 905 if (register_android_media_MediaPlayer(env) < 0) { 906 ALOGE("ERROR: MediaPlayer native registration failed\n"); 907 goto bail; 908 } 909 910 if (register_android_media_MediaRecorder(env) < 0) { 911 ALOGE("ERROR: MediaRecorder native registration failed\n"); 912 goto bail; 913 } 914 915 if (register_android_media_MediaScanner(env) < 0) { 916 ALOGE("ERROR: MediaScanner native registration failed\n"); 917 goto bail; 918 } 919 920 if (register_android_media_MediaMetadataRetriever(env) < 0) { 921 ALOGE("ERROR: MediaMetadataRetriever native registration failed\n"); 922 goto bail; 923 } 924 925 if (register_android_media_AmrInputStream(env) < 0) { 926 ALOGE("ERROR: AmrInputStream native registration failed\n"); 927 goto bail; 928 } 929 930 if (register_android_media_ResampleInputStream(env) < 0) { 931 ALOGE("ERROR: ResampleInputStream native registration failed\n"); 932 goto bail; 933 } 934 935 if (register_android_media_MediaProfiles(env) < 0) { 936 ALOGE("ERROR: MediaProfiles native registration failed"); 937 goto bail; 938 } 939 940 if (register_android_mtp_MtpDatabase(env) < 0) { 941 ALOGE("ERROR: MtpDatabase native registration failed"); 942 goto bail; 943 } 944 945 if (register_android_mtp_MtpDevice(env) < 0) { 946 ALOGE("ERROR: MtpDevice native registration failed"); 947 goto bail; 948 } 949 950 if (register_android_mtp_MtpServer(env) < 0) { 951 ALOGE("ERROR: MtpServer native registration failed"); 952 goto bail; 953 } 954 955 if (register_android_media_MediaCodec(env) < 0) { 956 ALOGE("ERROR: MediaCodec native registration failed"); 957 goto bail; 958 } 959 960 if (register_android_media_MediaExtractor(env) < 0) { 961 ALOGE("ERROR: MediaCodec native registration failed"); 962 goto bail; 963 } 964 965 if (register_android_media_MediaCodecList(env) < 0) { 966 ALOGE("ERROR: MediaCodec native registration failed"); 967 goto bail; 968 } 969 970 if (register_android_media_Crypto(env) < 0) { 971 ALOGE("ERROR: MediaCodec native registration failed"); 972 goto bail; 973 } 974 975 /* success -- return valid version number */ 976 result = JNI_VERSION_1_4; 977 978bail: 979 return result; 980} 981 982// KTHXBYE 983