android_media_MediaPlayer.cpp revision 5d55c7119820ee9bb06fc072e416fe98ba77cd28
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 "android_util_Binder.h" 35#include <binder/Parcel.h> 36 37 38// ---------------------------------------------------------------------------- 39 40using namespace android; 41 42// ---------------------------------------------------------------------------- 43 44struct fields_t { 45 jfieldID context; 46 jfieldID surface; 47 /* actually in android.view.Surface XXX */ 48 jfieldID surface_native; 49 50 jmethodID post_event; 51}; 52static fields_t fields; 53 54static Mutex sLock; 55 56// ---------------------------------------------------------------------------- 57// ref-counted object for callbacks 58class JNIMediaPlayerListener: public MediaPlayerListener 59{ 60public: 61 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz); 62 ~JNIMediaPlayerListener(); 63 void notify(int msg, int ext1, int ext2); 64private: 65 JNIMediaPlayerListener(); 66 jclass mClass; // Reference to MediaPlayer class 67 jobject mObject; // Weak ref to MediaPlayer Java object to call on 68}; 69 70JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz) 71{ 72 73 // Hold onto the MediaPlayer class for use in calling the static method 74 // that posts events to the application thread. 75 jclass clazz = env->GetObjectClass(thiz); 76 if (clazz == NULL) { 77 LOGE("Can't find android/media/MediaPlayer"); 78 jniThrowException(env, "java/lang/Exception", NULL); 79 return; 80 } 81 mClass = (jclass)env->NewGlobalRef(clazz); 82 83 // We use a weak reference so the MediaPlayer object can be garbage collected. 84 // The reference is only used as a proxy for callbacks. 85 mObject = env->NewGlobalRef(weak_thiz); 86} 87 88JNIMediaPlayerListener::~JNIMediaPlayerListener() 89{ 90 // remove global references 91 JNIEnv *env = AndroidRuntime::getJNIEnv(); 92 env->DeleteGlobalRef(mObject); 93 env->DeleteGlobalRef(mClass); 94} 95 96void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2) 97{ 98 JNIEnv *env = AndroidRuntime::getJNIEnv(); 99 env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0); 100} 101 102// ---------------------------------------------------------------------------- 103 104static sp<Surface> get_surface(JNIEnv* env, jobject clazz) 105{ 106 Surface* const p = (Surface*)env->GetIntField(clazz, fields.surface_native); 107 return sp<Surface>(p); 108} 109 110static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz) 111{ 112 Mutex::Autolock l(sLock); 113 MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context); 114 return sp<MediaPlayer>(p); 115} 116 117static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player) 118{ 119 Mutex::Autolock l(sLock); 120 sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context); 121 if (player.get()) { 122 player->incStrong(thiz); 123 } 124 if (old != 0) { 125 old->decStrong(thiz); 126 } 127 env->SetIntField(thiz, fields.context, (int)player.get()); 128 return old; 129} 130 131// If exception is NULL and opStatus is not OK, this method sends an error 132// event to the client application; otherwise, if exception is not NULL and 133// opStatus is not OK, this method throws the given exception to the client 134// application. 135static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message) 136{ 137 if (exception == NULL) { // Don't throw exception. Instead, send an event. 138 if (opStatus != (status_t) OK) { 139 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 140 if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0); 141 } 142 } else { // Throw exception! 143 if ( opStatus == (status_t) INVALID_OPERATION ) { 144 jniThrowException(env, "java/lang/IllegalStateException", NULL); 145 } else if ( opStatus != (status_t) OK ) { 146 if (strlen(message) > 230) { 147 // if the message is too long, don't bother displaying the status code 148 jniThrowException( env, exception, message); 149 } else { 150 char msg[256]; 151 // append the status code to the message 152 sprintf(msg, "%s: status=0x%X", message, opStatus); 153 jniThrowException( env, exception, msg); 154 } 155 } 156 } 157} 158 159static void 160android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path) 161{ 162 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 163 if (mp == NULL ) { 164 jniThrowException(env, "java/lang/IllegalStateException", NULL); 165 return; 166 } 167 168 if (path == NULL) { 169 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 170 return; 171 } 172 173 const char *pathStr = env->GetStringUTFChars(path, NULL); 174 if (pathStr == NULL) { // Out of memory 175 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 176 return; 177 } 178 LOGV("setDataSource: path %s", pathStr); 179 status_t opStatus = mp->setDataSource(pathStr); 180 181 // Make sure that local ref is released before a potential exception 182 env->ReleaseStringUTFChars(path, pathStr); 183 process_media_player_call( env, thiz, opStatus, "java/io/IOException", "setDataSource failed." ); 184} 185 186static void 187android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) 188{ 189 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 190 if (mp == NULL ) { 191 jniThrowException(env, "java/lang/IllegalStateException", NULL); 192 return; 193 } 194 195 if (fileDescriptor == NULL) { 196 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 197 return; 198 } 199 int fd = getParcelFileDescriptorFD(env, fileDescriptor); 200 LOGV("setDataSourceFD: fd %d", fd); 201 process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." ); 202} 203 204static void setVideoSurface(const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz) 205{ 206 jobject surface = env->GetObjectField(thiz, fields.surface); 207 if (surface != NULL) { 208 const sp<Surface>& native_surface = get_surface(env, surface); 209 LOGV("prepare: surface=%p (id=%d)", 210 native_surface.get(), native_surface->ID()); 211 mp->setVideoSurface(native_surface); 212 } 213} 214 215static void 216android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz) 217{ 218 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 219 if (mp == NULL ) { 220 jniThrowException(env, "java/lang/IllegalStateException", NULL); 221 return; 222 } 223 setVideoSurface(mp, env, thiz); 224} 225 226static void 227android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz) 228{ 229 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 230 if (mp == NULL ) { 231 jniThrowException(env, "java/lang/IllegalStateException", NULL); 232 return; 233 } 234 setVideoSurface(mp, env, thiz); 235 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." ); 236} 237 238static void 239android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz) 240{ 241 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 242 if (mp == NULL ) { 243 jniThrowException(env, "java/lang/IllegalStateException", NULL); 244 return; 245 } 246 jobject surface = env->GetObjectField(thiz, fields.surface); 247 if (surface != NULL) { 248 const sp<Surface>& native_surface = get_surface(env, surface); 249 LOGV("prepareAsync: surface=%p (id=%d)", 250 native_surface.get(), native_surface->ID()); 251 mp->setVideoSurface(native_surface); 252 } 253 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." ); 254} 255 256static void 257android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) 258{ 259 LOGV("start"); 260 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 261 if (mp == NULL ) { 262 jniThrowException(env, "java/lang/IllegalStateException", NULL); 263 return; 264 } 265 process_media_player_call( env, thiz, mp->start(), NULL, NULL ); 266} 267 268static void 269android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz) 270{ 271 LOGV("stop"); 272 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 273 if (mp == NULL ) { 274 jniThrowException(env, "java/lang/IllegalStateException", NULL); 275 return; 276 } 277 process_media_player_call( env, thiz, mp->stop(), NULL, NULL ); 278} 279 280static void 281android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz) 282{ 283 LOGV("pause"); 284 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 285 if (mp == NULL ) { 286 jniThrowException(env, "java/lang/IllegalStateException", NULL); 287 return; 288 } 289 process_media_player_call( env, thiz, mp->pause(), NULL, NULL ); 290} 291 292static jboolean 293android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz) 294{ 295 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 296 if (mp == NULL ) { 297 jniThrowException(env, "java/lang/IllegalStateException", NULL); 298 return false; 299 } 300 const jboolean is_playing = mp->isPlaying(); 301 302 LOGV("isPlaying: %d", is_playing); 303 return is_playing; 304} 305 306static void 307android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec) 308{ 309 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 310 if (mp == NULL ) { 311 jniThrowException(env, "java/lang/IllegalStateException", NULL); 312 return; 313 } 314 LOGV("seekTo: %d(msec)", msec); 315 process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL ); 316} 317 318static int 319android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz) 320{ 321 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 322 if (mp == NULL ) { 323 jniThrowException(env, "java/lang/IllegalStateException", NULL); 324 return 0; 325 } 326 int w; 327 if (0 != mp->getVideoWidth(&w)) { 328 LOGE("getVideoWidth failed"); 329 w = 0; 330 } 331 LOGV("getVideoWidth: %d", w); 332 return w; 333} 334 335static int 336android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz) 337{ 338 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 339 if (mp == NULL ) { 340 jniThrowException(env, "java/lang/IllegalStateException", NULL); 341 return 0; 342 } 343 int h; 344 if (0 != mp->getVideoHeight(&h)) { 345 LOGE("getVideoHeight failed"); 346 h = 0; 347 } 348 LOGV("getVideoHeight: %d", h); 349 return h; 350} 351 352 353static int 354android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz) 355{ 356 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 357 if (mp == NULL ) { 358 jniThrowException(env, "java/lang/IllegalStateException", NULL); 359 return 0; 360 } 361 int msec; 362 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL ); 363 LOGV("getCurrentPosition: %d (msec)", msec); 364 return msec; 365} 366 367static int 368android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz) 369{ 370 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 371 if (mp == NULL ) { 372 jniThrowException(env, "java/lang/IllegalStateException", NULL); 373 return 0; 374 } 375 int msec; 376 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL ); 377 LOGV("getDuration: %d (msec)", msec); 378 return msec; 379} 380 381static void 382android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz) 383{ 384 LOGV("reset"); 385 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 386 if (mp == NULL ) { 387 jniThrowException(env, "java/lang/IllegalStateException", NULL); 388 return; 389 } 390 process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); 391} 392 393static void 394android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype) 395{ 396 LOGV("setAudioStreamType: %d", streamtype); 397 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 398 if (mp == NULL ) { 399 jniThrowException(env, "java/lang/IllegalStateException", NULL); 400 return; 401 } 402 process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL ); 403} 404 405static void 406android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping) 407{ 408 LOGV("setLooping: %d", looping); 409 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 410 if (mp == NULL ) { 411 jniThrowException(env, "java/lang/IllegalStateException", NULL); 412 return; 413 } 414 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL ); 415} 416 417static jboolean 418android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz) 419{ 420 LOGV("isLooping"); 421 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 422 if (mp == NULL ) { 423 jniThrowException(env, "java/lang/IllegalStateException", NULL); 424 return false; 425 } 426 return mp->isLooping(); 427} 428 429static void 430android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume) 431{ 432 LOGV("setVolume: left %f right %f", leftVolume, rightVolume); 433 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 434 if (mp == NULL ) { 435 jniThrowException(env, "java/lang/IllegalStateException", NULL); 436 return; 437 } 438 process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL ); 439} 440 441// FIXME: deprecated 442static jobject 443android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) 444{ 445 return NULL; 446} 447 448 449// Sends the request and reply parcels to the media player via the 450// binder interface. 451static jint 452android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz, 453 jobject java_request, jobject java_reply) 454{ 455 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 456 if (media_player == NULL ) { 457 jniThrowException(env, "java/lang/IllegalStateException", NULL); 458 return UNKNOWN_ERROR; 459 } 460 461 462 Parcel *request = parcelForJavaObject(env, java_request); 463 Parcel *reply = parcelForJavaObject(env, java_reply); 464 465 // Don't use process_media_player_call which use the async loop to 466 // report errors, instead returns the status. 467 return media_player->invoke(*request, reply); 468} 469 470// Sends the new filter to the client. 471static jint 472android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request) 473{ 474 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 475 if (media_player == NULL ) { 476 jniThrowException(env, "java/lang/IllegalStateException", NULL); 477 return UNKNOWN_ERROR; 478 } 479 480 Parcel *filter = parcelForJavaObject(env, request); 481 482 if (filter == NULL ) { 483 jniThrowException(env, "java/lang/RuntimeException", "Filter is null"); 484 return UNKNOWN_ERROR; 485 } 486 487 return media_player->setMetadataFilter(*filter); 488} 489 490static jboolean 491android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, 492 jboolean apply_filter, jobject reply) 493{ 494 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 495 if (media_player == NULL ) { 496 jniThrowException(env, "java/lang/IllegalStateException", NULL); 497 return false; 498 } 499 500 Parcel *metadata = parcelForJavaObject(env, reply); 501 502 if (metadata == NULL ) { 503 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null"); 504 return false; 505 } 506 507 metadata->freeData(); 508 // On return metadata is positioned at the beginning of the 509 // metadata. Note however that the parcel actually starts with the 510 // return code so you should not rewind the parcel using 511 // setDataPosition(0). 512 return media_player->getMetadata(update_only, apply_filter, metadata) == OK; 513} 514 515 516static void 517android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) 518{ 519 LOGV("native_setup"); 520 sp<MediaPlayer> mp = new MediaPlayer(); 521 if (mp == NULL) { 522 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 523 return; 524 } 525 526 // create new listener and give it to MediaPlayer 527 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); 528 mp->setListener(listener); 529 530 // Stow our new C++ MediaPlayer in an opaque field in the Java object. 531 setMediaPlayer(env, thiz, mp); 532} 533 534static void 535android_media_MediaPlayer_release(JNIEnv *env, jobject thiz) 536{ 537 LOGV("release"); 538 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0); 539 if (mp != NULL) { 540 // this prevents native callbacks after the object is released 541 mp->setListener(0); 542 mp->disconnect(); 543 } 544} 545 546static void 547android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz) 548{ 549 LOGV("native_finalize"); 550 android_media_MediaPlayer_release(env, thiz); 551} 552 553// ---------------------------------------------------------------------------- 554 555static JNINativeMethod gMethods[] = { 556 {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource}, 557 {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, 558 {"_setVideoSurface", "()V", (void *)android_media_MediaPlayer_setVideoSurface}, 559 {"prepare", "()V", (void *)android_media_MediaPlayer_prepare}, 560 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, 561 {"_start", "()V", (void *)android_media_MediaPlayer_start}, 562 {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, 563 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, 564 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, 565 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, 566 {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, 567 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, 568 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, 569 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, 570 {"_release", "()V", (void *)android_media_MediaPlayer_release}, 571 {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, 572 {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, 573 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, 574 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, 575 {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, 576 {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, 577 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, 578 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, 579 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, 580 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, 581 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, 582}; 583 584static const char* const kClassPathName = "android/media/MediaPlayer"; 585 586static int register_android_media_MediaPlayer(JNIEnv *env) 587{ 588 jclass clazz; 589 590 clazz = env->FindClass("android/media/MediaPlayer"); 591 if (clazz == NULL) { 592 LOGE("Can't find android/media/MediaPlayer"); 593 return -1; 594 } 595 596 fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); 597 if (fields.context == NULL) { 598 LOGE("Can't find MediaPlayer.mNativeContext"); 599 return -1; 600 } 601 602 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 603 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 604 if (fields.post_event == NULL) { 605 LOGE("Can't find MediaPlayer.postEventFromNative"); 606 return -1; 607 } 608 609 fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;"); 610 if (fields.surface == NULL) { 611 LOGE("Can't find MediaPlayer.mSurface"); 612 return -1; 613 } 614 615 jclass surface = env->FindClass("android/view/Surface"); 616 if (surface == NULL) { 617 LOGE("Can't find android/view/Surface"); 618 return -1; 619 } 620 621 fields.surface_native = env->GetFieldID(surface, "mSurface", "I"); 622 if (fields.surface_native == NULL) { 623 LOGE("Can't find Surface fields"); 624 return -1; 625 } 626 627 return AndroidRuntime::registerNativeMethods(env, 628 "android/media/MediaPlayer", gMethods, NELEM(gMethods)); 629} 630 631extern int register_android_media_MediaRecorder(JNIEnv *env); 632extern int register_android_media_MediaScanner(JNIEnv *env); 633extern int register_android_media_MediaMetadataRetriever(JNIEnv *env); 634extern int register_android_media_AmrInputStream(JNIEnv *env); 635extern int register_android_media_ResampleInputStream(JNIEnv *env); 636 637jint JNI_OnLoad(JavaVM* vm, void* reserved) 638{ 639 JNIEnv* env = NULL; 640 jint result = -1; 641 642 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 643 LOGE("ERROR: GetEnv failed\n"); 644 goto bail; 645 } 646 assert(env != NULL); 647 648 if (register_android_media_MediaPlayer(env) < 0) { 649 LOGE("ERROR: MediaPlayer native registration failed\n"); 650 goto bail; 651 } 652 653 if (register_android_media_MediaRecorder(env) < 0) { 654 LOGE("ERROR: MediaRecorder native registration failed\n"); 655 goto bail; 656 } 657 658 if (register_android_media_MediaScanner(env) < 0) { 659 LOGE("ERROR: MediaScanner native registration failed\n"); 660 goto bail; 661 } 662 663 if (register_android_media_MediaMetadataRetriever(env) < 0) { 664 LOGE("ERROR: MediaMetadataRetriever native registration failed\n"); 665 goto bail; 666 } 667 668 if (register_android_media_AmrInputStream(env) < 0) { 669 LOGE("ERROR: AmrInputStream native registration failed\n"); 670 goto bail; 671 } 672 673 if (register_android_media_ResampleInputStream(env) < 0) { 674 LOGE("ERROR: ResampleInputStream native registration failed\n"); 675 goto bail; 676 } 677 678 /* success -- return valid version number */ 679 result = JNI_VERSION_1_4; 680 681bail: 682 return result; 683} 684 685// KTHXBYE 686