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