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