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