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