1/* //device/libs/android_runtime/android_media_MediaPlayer.cpp 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 "utils/Errors.h" // for status_t 34#include "utils/KeyedVector.h" 35#include "utils/String8.h" 36#include "android_util_Binder.h" 37#include <binder/Parcel.h> 38#include <surfaceflinger/Surface.h> 39 40// ---------------------------------------------------------------------------- 41 42using namespace android; 43 44// ---------------------------------------------------------------------------- 45 46struct fields_t { 47 jfieldID context; 48 jfieldID surface; 49 /* actually in android.view.Surface XXX */ 50 jfieldID surface_native; 51 52 jmethodID post_event; 53}; 54static fields_t fields; 55 56static Mutex sLock; 57 58// ---------------------------------------------------------------------------- 59// ref-counted object for callbacks 60class JNIMediaPlayerListener: public MediaPlayerListener 61{ 62public: 63 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz); 64 ~JNIMediaPlayerListener(); 65 void notify(int msg, int ext1, int ext2); 66private: 67 JNIMediaPlayerListener(); 68 jclass mClass; // Reference to MediaPlayer class 69 jobject mObject; // Weak ref to MediaPlayer Java object to call on 70}; 71 72JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz) 73{ 74 75 // Hold onto the MediaPlayer class for use in calling the static method 76 // that posts events to the application thread. 77 jclass clazz = env->GetObjectClass(thiz); 78 if (clazz == NULL) { 79 LOGE("Can't find android/media/MediaPlayer"); 80 jniThrowException(env, "java/lang/Exception", NULL); 81 return; 82 } 83 mClass = (jclass)env->NewGlobalRef(clazz); 84 85 // We use a weak reference so the MediaPlayer object can be garbage collected. 86 // The reference is only used as a proxy for callbacks. 87 mObject = env->NewGlobalRef(weak_thiz); 88} 89 90JNIMediaPlayerListener::~JNIMediaPlayerListener() 91{ 92 // remove global references 93 JNIEnv *env = AndroidRuntime::getJNIEnv(); 94 env->DeleteGlobalRef(mObject); 95 env->DeleteGlobalRef(mClass); 96} 97 98void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2) 99{ 100 JNIEnv *env = AndroidRuntime::getJNIEnv(); 101 env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0); 102} 103 104// ---------------------------------------------------------------------------- 105 106static Surface* get_surface(JNIEnv* env, jobject clazz) 107{ 108 return (Surface*)env->GetIntField(clazz, fields.surface_native); 109} 110 111static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz) 112{ 113 Mutex::Autolock l(sLock); 114 MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context); 115 return sp<MediaPlayer>(p); 116} 117 118static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player) 119{ 120 Mutex::Autolock l(sLock); 121 sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context); 122 if (player.get()) { 123 player->incStrong(thiz); 124 } 125 if (old != 0) { 126 old->decStrong(thiz); 127 } 128 env->SetIntField(thiz, fields.context, (int)player.get()); 129 return old; 130} 131 132// If exception is NULL and opStatus is not OK, this method sends an error 133// event to the client application; otherwise, if exception is not NULL and 134// opStatus is not OK, this method throws the given exception to the client 135// application. 136static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message) 137{ 138 if (exception == NULL) { // Don't throw exception. Instead, send an event. 139 if (opStatus != (status_t) OK) { 140 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 141 if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0); 142 } 143 } else { // Throw exception! 144 if ( opStatus == (status_t) INVALID_OPERATION ) { 145 jniThrowException(env, "java/lang/IllegalStateException", NULL); 146 } else if ( opStatus != (status_t) OK ) { 147 if (strlen(message) > 230) { 148 // if the message is too long, don't bother displaying the status code 149 jniThrowException( env, exception, message); 150 } else { 151 char msg[256]; 152 // append the status code to the message 153 sprintf(msg, "%s: status=0x%X", message, opStatus); 154 jniThrowException( env, exception, msg); 155 } 156 } 157 } 158} 159 160static void 161android_media_MediaPlayer_setDataSourceAndHeaders( 162 JNIEnv *env, jobject thiz, jstring path, jobject headers) { 163 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 164 if (mp == NULL ) { 165 jniThrowException(env, "java/lang/IllegalStateException", NULL); 166 return; 167 } 168 169 if (path == NULL) { 170 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 171 return; 172 } 173 174 const char *pathStr = env->GetStringUTFChars(path, NULL); 175 if (pathStr == NULL) { // Out of memory 176 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 177 return; 178 } 179 180 // headers is a Map<String, String>. 181 // We build a similar KeyedVector out of it. 182 KeyedVector<String8, String8> headersVector; 183 if (headers) { 184 // Get the Map's entry Set. 185 jclass mapClass = env->FindClass("java/util/Map"); 186 187 jmethodID entrySet = 188 env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;"); 189 190 jobject set = env->CallObjectMethod(headers, entrySet); 191 // Obtain an iterator over the Set 192 jclass setClass = env->FindClass("java/util/Set"); 193 194 jmethodID iterator = 195 env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;"); 196 197 jobject iter = env->CallObjectMethod(set, iterator); 198 // Get the Iterator method IDs 199 jclass iteratorClass = env->FindClass("java/util/Iterator"); 200 jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); 201 202 jmethodID next = 203 env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); 204 205 // Get the Entry class method IDs 206 jclass entryClass = env->FindClass("java/util/Map$Entry"); 207 208 jmethodID getKey = 209 env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;"); 210 211 jmethodID getValue = 212 env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;"); 213 214 // Iterate over the entry Set 215 while (env->CallBooleanMethod(iter, hasNext)) { 216 jobject entry = env->CallObjectMethod(iter, next); 217 jstring key = (jstring) env->CallObjectMethod(entry, getKey); 218 jstring value = (jstring) env->CallObjectMethod(entry, getValue); 219 220 const char* keyStr = env->GetStringUTFChars(key, NULL); 221 if (!keyStr) { // Out of memory 222 jniThrowException( 223 env, "java/lang/RuntimeException", "Out of memory"); 224 return; 225 } 226 227 const char* valueStr = env->GetStringUTFChars(value, NULL); 228 if (!valueStr) { // Out of memory 229 jniThrowException( 230 env, "java/lang/RuntimeException", "Out of memory"); 231 return; 232 } 233 234 headersVector.add(String8(keyStr), String8(valueStr)); 235 236 env->DeleteLocalRef(entry); 237 env->ReleaseStringUTFChars(key, keyStr); 238 env->DeleteLocalRef(key); 239 env->ReleaseStringUTFChars(value, valueStr); 240 env->DeleteLocalRef(value); 241 } 242 243 env->DeleteLocalRef(entryClass); 244 env->DeleteLocalRef(iteratorClass); 245 env->DeleteLocalRef(iter); 246 env->DeleteLocalRef(setClass); 247 env->DeleteLocalRef(set); 248 env->DeleteLocalRef(mapClass); 249 } 250 251 LOGV("setDataSource: path %s", pathStr); 252 status_t opStatus = 253 mp->setDataSource( 254 String8(pathStr), 255 headers ? &headersVector : NULL); 256 257 // Make sure that local ref is released before a potential exception 258 env->ReleaseStringUTFChars(path, pathStr); 259 260 process_media_player_call( 261 env, thiz, opStatus, "java/io/IOException", 262 "setDataSource failed." ); 263} 264 265static void 266android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path) 267{ 268 android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, 0); 269} 270 271static void 272android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) 273{ 274 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 275 if (mp == NULL ) { 276 jniThrowException(env, "java/lang/IllegalStateException", NULL); 277 return; 278 } 279 280 if (fileDescriptor == NULL) { 281 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 282 return; 283 } 284 int fd = getParcelFileDescriptorFD(env, fileDescriptor); 285 LOGV("setDataSourceFD: fd %d", fd); 286 process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." ); 287} 288 289static void setVideoSurface(const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz) 290{ 291 jobject surface = env->GetObjectField(thiz, fields.surface); 292 if (surface != NULL) { 293 const sp<Surface> native_surface = get_surface(env, surface); 294 LOGV("prepare: surface=%p (id=%d)", 295 native_surface.get(), native_surface->getIdentity()); 296 mp->setVideoSurface(native_surface); 297 } 298} 299 300static void 301android_media_MediaPlayer_setVideoSurface(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 setVideoSurface(mp, env, thiz); 309} 310 311static void 312android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz) 313{ 314 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 315 if (mp == NULL ) { 316 jniThrowException(env, "java/lang/IllegalStateException", NULL); 317 return; 318 } 319 setVideoSurface(mp, env, thiz); 320 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." ); 321} 322 323static void 324android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz) 325{ 326 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 327 if (mp == NULL ) { 328 jniThrowException(env, "java/lang/IllegalStateException", NULL); 329 return; 330 } 331 jobject surface = env->GetObjectField(thiz, fields.surface); 332 if (surface != NULL) { 333 const sp<Surface> native_surface = get_surface(env, surface); 334 LOGV("prepareAsync: surface=%p (id=%d)", 335 native_surface.get(), native_surface->getIdentity()); 336 mp->setVideoSurface(native_surface); 337 } 338 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." ); 339} 340 341static void 342android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) 343{ 344 LOGV("start"); 345 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 346 if (mp == NULL ) { 347 jniThrowException(env, "java/lang/IllegalStateException", NULL); 348 return; 349 } 350 process_media_player_call( env, thiz, mp->start(), NULL, NULL ); 351} 352 353static void 354android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz) 355{ 356 LOGV("stop"); 357 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 358 if (mp == NULL ) { 359 jniThrowException(env, "java/lang/IllegalStateException", NULL); 360 return; 361 } 362 process_media_player_call( env, thiz, mp->stop(), NULL, NULL ); 363} 364 365static void 366android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz) 367{ 368 LOGV("pause"); 369 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 370 if (mp == NULL ) { 371 jniThrowException(env, "java/lang/IllegalStateException", NULL); 372 return; 373 } 374 process_media_player_call( env, thiz, mp->pause(), NULL, NULL ); 375} 376 377static jboolean 378android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz) 379{ 380 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 381 if (mp == NULL ) { 382 jniThrowException(env, "java/lang/IllegalStateException", NULL); 383 return false; 384 } 385 const jboolean is_playing = mp->isPlaying(); 386 387 LOGV("isPlaying: %d", is_playing); 388 return is_playing; 389} 390 391static void 392android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec) 393{ 394 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 395 if (mp == NULL ) { 396 jniThrowException(env, "java/lang/IllegalStateException", NULL); 397 return; 398 } 399 LOGV("seekTo: %d(msec)", msec); 400 process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL ); 401} 402 403static int 404android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz) 405{ 406 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 407 if (mp == NULL ) { 408 jniThrowException(env, "java/lang/IllegalStateException", NULL); 409 return 0; 410 } 411 int w; 412 if (0 != mp->getVideoWidth(&w)) { 413 LOGE("getVideoWidth failed"); 414 w = 0; 415 } 416 LOGV("getVideoWidth: %d", w); 417 return w; 418} 419 420static int 421android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz) 422{ 423 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 424 if (mp == NULL ) { 425 jniThrowException(env, "java/lang/IllegalStateException", NULL); 426 return 0; 427 } 428 int h; 429 if (0 != mp->getVideoHeight(&h)) { 430 LOGE("getVideoHeight failed"); 431 h = 0; 432 } 433 LOGV("getVideoHeight: %d", h); 434 return h; 435} 436 437 438static int 439android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz) 440{ 441 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 442 if (mp == NULL ) { 443 jniThrowException(env, "java/lang/IllegalStateException", NULL); 444 return 0; 445 } 446 int msec; 447 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL ); 448 LOGV("getCurrentPosition: %d (msec)", msec); 449 return msec; 450} 451 452static int 453android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz) 454{ 455 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 456 if (mp == NULL ) { 457 jniThrowException(env, "java/lang/IllegalStateException", NULL); 458 return 0; 459 } 460 int msec; 461 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL ); 462 LOGV("getDuration: %d (msec)", msec); 463 return msec; 464} 465 466static void 467android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz) 468{ 469 LOGV("reset"); 470 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 471 if (mp == NULL ) { 472 jniThrowException(env, "java/lang/IllegalStateException", NULL); 473 return; 474 } 475 process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); 476} 477 478static void 479android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype) 480{ 481 LOGV("setAudioStreamType: %d", streamtype); 482 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 483 if (mp == NULL ) { 484 jniThrowException(env, "java/lang/IllegalStateException", NULL); 485 return; 486 } 487 process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL ); 488} 489 490static void 491android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping) 492{ 493 LOGV("setLooping: %d", looping); 494 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 495 if (mp == NULL ) { 496 jniThrowException(env, "java/lang/IllegalStateException", NULL); 497 return; 498 } 499 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL ); 500} 501 502static jboolean 503android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz) 504{ 505 LOGV("isLooping"); 506 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 507 if (mp == NULL ) { 508 jniThrowException(env, "java/lang/IllegalStateException", NULL); 509 return false; 510 } 511 return mp->isLooping(); 512} 513 514static void 515android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume) 516{ 517 LOGV("setVolume: left %f right %f", leftVolume, rightVolume); 518 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 519 if (mp == NULL ) { 520 jniThrowException(env, "java/lang/IllegalStateException", NULL); 521 return; 522 } 523 process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL ); 524} 525 526// FIXME: deprecated 527static jobject 528android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) 529{ 530 return NULL; 531} 532 533 534// Sends the request and reply parcels to the media player via the 535// binder interface. 536static jint 537android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz, 538 jobject java_request, jobject java_reply) 539{ 540 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 541 if (media_player == NULL ) { 542 jniThrowException(env, "java/lang/IllegalStateException", NULL); 543 return UNKNOWN_ERROR; 544 } 545 546 547 Parcel *request = parcelForJavaObject(env, java_request); 548 Parcel *reply = parcelForJavaObject(env, java_reply); 549 550 // Don't use process_media_player_call which use the async loop to 551 // report errors, instead returns the status. 552 return media_player->invoke(*request, reply); 553} 554 555// Sends the new filter to the client. 556static jint 557android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request) 558{ 559 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 560 if (media_player == NULL ) { 561 jniThrowException(env, "java/lang/IllegalStateException", NULL); 562 return UNKNOWN_ERROR; 563 } 564 565 Parcel *filter = parcelForJavaObject(env, request); 566 567 if (filter == NULL ) { 568 jniThrowException(env, "java/lang/RuntimeException", "Filter is null"); 569 return UNKNOWN_ERROR; 570 } 571 572 return media_player->setMetadataFilter(*filter); 573} 574 575static jboolean 576android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, 577 jboolean apply_filter, jobject reply) 578{ 579 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 580 if (media_player == NULL ) { 581 jniThrowException(env, "java/lang/IllegalStateException", NULL); 582 return false; 583 } 584 585 Parcel *metadata = parcelForJavaObject(env, reply); 586 587 if (metadata == NULL ) { 588 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null"); 589 return false; 590 } 591 592 metadata->freeData(); 593 // On return metadata is positioned at the beginning of the 594 // metadata. Note however that the parcel actually starts with the 595 // return code so you should not rewind the parcel using 596 // setDataPosition(0). 597 return media_player->getMetadata(update_only, apply_filter, metadata) == OK; 598} 599 600// This function gets some field IDs, which in turn causes class initialization. 601// It is called from a static block in MediaPlayer, which won't run until the 602// first time an instance of this class is used. 603static void 604android_media_MediaPlayer_native_init(JNIEnv *env) 605{ 606 jclass clazz; 607 608 clazz = env->FindClass("android/media/MediaPlayer"); 609 if (clazz == NULL) { 610 jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaPlayer"); 611 return; 612 } 613 614 fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 615 if (fields.context == NULL) { 616 jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mNativeContext"); 617 return; 618 } 619 620 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 621 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 622 if (fields.post_event == NULL) { 623 jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.postEventFromNative"); 624 return; 625 } 626 627 fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;"); 628 if (fields.surface == NULL) { 629 jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mSurface"); 630 return; 631 } 632 633 jclass surface = env->FindClass("android/view/Surface"); 634 if (surface == NULL) { 635 jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface"); 636 return; 637 } 638 639 fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I"); 640 if (fields.surface_native == NULL) { 641 jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface"); 642 return; 643 } 644} 645 646static void 647android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) 648{ 649 LOGV("native_setup"); 650 sp<MediaPlayer> mp = new MediaPlayer(); 651 if (mp == NULL) { 652 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 653 return; 654 } 655 656 // create new listener and give it to MediaPlayer 657 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); 658 mp->setListener(listener); 659 660 // Stow our new C++ MediaPlayer in an opaque field in the Java object. 661 setMediaPlayer(env, thiz, mp); 662} 663 664static void 665android_media_MediaPlayer_release(JNIEnv *env, jobject thiz) 666{ 667 LOGV("release"); 668 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0); 669 if (mp != NULL) { 670 // this prevents native callbacks after the object is released 671 mp->setListener(0); 672 mp->disconnect(); 673 } 674} 675 676static void 677android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz) 678{ 679 LOGV("native_finalize"); 680 android_media_MediaPlayer_release(env, thiz); 681} 682 683static jint 684android_media_MediaPlayer_native_suspend_resume( 685 JNIEnv *env, jobject thiz, jboolean isSuspend) { 686 LOGV("suspend_resume(%d)", isSuspend); 687 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 688 if (mp == NULL ) { 689 jniThrowException(env, "java/lang/IllegalStateException", NULL); 690 return UNKNOWN_ERROR; 691 } 692 693 return isSuspend ? mp->suspend() : mp->resume(); 694} 695 696static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) { 697 LOGV("set_session_id(): %d", sessionId); 698 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 699 if (mp == NULL ) { 700 jniThrowException(env, "java/lang/IllegalStateException", NULL); 701 return; 702 } 703 process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL ); 704} 705 706static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) { 707 LOGV("get_session_id()"); 708 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 709 if (mp == NULL ) { 710 jniThrowException(env, "java/lang/IllegalStateException", NULL); 711 return 0; 712 } 713 714 return mp->getAudioSessionId(); 715} 716 717static void 718android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level) 719{ 720 LOGV("setAuxEffectSendLevel: level %f", level); 721 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 722 if (mp == NULL ) { 723 jniThrowException(env, "java/lang/IllegalStateException", NULL); 724 return; 725 } 726 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL ); 727} 728 729static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) { 730 LOGV("attachAuxEffect(): %d", effectId); 731 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 732 if (mp == NULL ) { 733 jniThrowException(env, "java/lang/IllegalStateException", NULL); 734 return; 735 } 736 process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL ); 737} 738 739// ---------------------------------------------------------------------------- 740 741static JNINativeMethod gMethods[] = { 742 {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource}, 743 {"setDataSource", "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders}, 744 {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, 745 {"_setVideoSurface", "()V", (void *)android_media_MediaPlayer_setVideoSurface}, 746 {"prepare", "()V", (void *)android_media_MediaPlayer_prepare}, 747 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, 748 {"_start", "()V", (void *)android_media_MediaPlayer_start}, 749 {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, 750 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, 751 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, 752 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, 753 {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, 754 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, 755 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, 756 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, 757 {"_release", "()V", (void *)android_media_MediaPlayer_release}, 758 {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, 759 {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, 760 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, 761 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, 762 {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, 763 {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, 764 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, 765 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, 766 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, 767 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, 768 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, 769 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, 770 {"native_suspend_resume", "(Z)I", (void *)android_media_MediaPlayer_native_suspend_resume}, 771 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, 772 {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, 773 {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, 774 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, 775}; 776 777static const char* const kClassPathName = "android/media/MediaPlayer"; 778 779// This function only registers the native methods 780static int register_android_media_MediaPlayer(JNIEnv *env) 781{ 782 return AndroidRuntime::registerNativeMethods(env, 783 "android/media/MediaPlayer", gMethods, NELEM(gMethods)); 784} 785 786extern int register_android_media_MediaMetadataRetriever(JNIEnv *env); 787extern int register_android_media_MediaRecorder(JNIEnv *env); 788extern int register_android_media_MediaScanner(JNIEnv *env); 789extern int register_android_media_ResampleInputStream(JNIEnv *env); 790extern int register_android_media_MediaProfiles(JNIEnv *env); 791extern int register_android_media_AmrInputStream(JNIEnv *env); 792 793jint JNI_OnLoad(JavaVM* vm, void* reserved) 794{ 795 JNIEnv* env = NULL; 796 jint result = -1; 797 798 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 799 LOGE("ERROR: GetEnv failed\n"); 800 goto bail; 801 } 802 assert(env != NULL); 803 804 if (register_android_media_MediaPlayer(env) < 0) { 805 LOGE("ERROR: MediaPlayer native registration failed\n"); 806 goto bail; 807 } 808 809 if (register_android_media_MediaRecorder(env) < 0) { 810 LOGE("ERROR: MediaRecorder native registration failed\n"); 811 goto bail; 812 } 813 814 if (register_android_media_MediaScanner(env) < 0) { 815 LOGE("ERROR: MediaScanner native registration failed\n"); 816 goto bail; 817 } 818 819 if (register_android_media_MediaMetadataRetriever(env) < 0) { 820 LOGE("ERROR: MediaMetadataRetriever native registration failed\n"); 821 goto bail; 822 } 823 824 if (register_android_media_AmrInputStream(env) < 0) { 825 LOGE("ERROR: AmrInputStream native registration failed\n"); 826 goto bail; 827 } 828 829 if (register_android_media_ResampleInputStream(env) < 0) { 830 LOGE("ERROR: ResampleInputStream native registration failed\n"); 831 goto bail; 832 } 833 834 if (register_android_media_MediaProfiles(env) < 0) { 835 LOGE("ERROR: MediaProfiles native registration failed"); 836 goto bail; 837 } 838 839 /* success -- return valid version number */ 840 result = JNI_VERSION_1_4; 841 842bail: 843 return result; 844} 845 846// KTHXBYE 847