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