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/AudioResamplerPublic.h> 24#include <media/IMediaHTTPService.h> 25#include <media/MediaPlayerInterface.h> 26#include <stdio.h> 27#include <assert.h> 28#include <limits.h> 29#include <unistd.h> 30#include <fcntl.h> 31#include <utils/threads.h> 32#include "jni.h" 33#include "JNIHelp.h" 34#include "android_runtime/AndroidRuntime.h" 35#include "android_runtime/android_view_Surface.h" 36#include "android_runtime/Log.h" 37#include "utils/Errors.h" // for status_t 38#include "utils/KeyedVector.h" 39#include "utils/String8.h" 40#include "android_media_MediaDataSource.h" 41#include "android_media_PlaybackParams.h" 42#include "android_media_SyncParams.h" 43#include "android_media_Utils.h" 44 45#include "android_os_Parcel.h" 46#include "android_util_Binder.h" 47#include <binder/Parcel.h> 48#include <gui/IGraphicBufferProducer.h> 49#include <gui/Surface.h> 50#include <binder/IPCThreadState.h> 51#include <binder/IServiceManager.h> 52 53#include "android_util_Binder.h" 54// ---------------------------------------------------------------------------- 55 56using namespace android; 57 58// ---------------------------------------------------------------------------- 59 60struct fields_t { 61 jfieldID context; 62 jfieldID surface_texture; 63 64 jmethodID post_event; 65 66 jmethodID proxyConfigGetHost; 67 jmethodID proxyConfigGetPort; 68 jmethodID proxyConfigGetExclusionList; 69}; 70static fields_t fields; 71 72static PlaybackParams::fields_t gPlaybackParamsFields; 73static SyncParams::fields_t gSyncParamsFields; 74 75static Mutex sLock; 76 77// ---------------------------------------------------------------------------- 78// ref-counted object for callbacks 79class JNIMediaPlayerListener: public MediaPlayerListener 80{ 81public: 82 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz); 83 ~JNIMediaPlayerListener(); 84 virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL); 85private: 86 JNIMediaPlayerListener(); 87 jclass mClass; // Reference to MediaPlayer class 88 jobject mObject; // Weak ref to MediaPlayer Java object to call on 89}; 90 91JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz) 92{ 93 94 // Hold onto the MediaPlayer class for use in calling the static method 95 // that posts events to the application thread. 96 jclass clazz = env->GetObjectClass(thiz); 97 if (clazz == NULL) { 98 ALOGE("Can't find android/media/MediaPlayer"); 99 jniThrowException(env, "java/lang/Exception", NULL); 100 return; 101 } 102 mClass = (jclass)env->NewGlobalRef(clazz); 103 104 // We use a weak reference so the MediaPlayer object can be garbage collected. 105 // The reference is only used as a proxy for callbacks. 106 mObject = env->NewGlobalRef(weak_thiz); 107} 108 109JNIMediaPlayerListener::~JNIMediaPlayerListener() 110{ 111 // remove global references 112 JNIEnv *env = AndroidRuntime::getJNIEnv(); 113 env->DeleteGlobalRef(mObject); 114 env->DeleteGlobalRef(mClass); 115} 116 117void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj) 118{ 119 JNIEnv *env = AndroidRuntime::getJNIEnv(); 120 if (obj && obj->dataSize() > 0) { 121 jobject jParcel = createJavaParcelObject(env); 122 if (jParcel != NULL) { 123 Parcel* nativeParcel = parcelForJavaObject(env, jParcel); 124 nativeParcel->setData(obj->data(), obj->dataSize()); 125 env->CallStaticVoidMethod(mClass, fields.post_event, mObject, 126 msg, ext1, ext2, jParcel); 127 env->DeleteLocalRef(jParcel); 128 } 129 } else { 130 env->CallStaticVoidMethod(mClass, fields.post_event, mObject, 131 msg, ext1, ext2, NULL); 132 } 133 if (env->ExceptionCheck()) { 134 ALOGW("An exception occurred while notifying an event."); 135 LOGW_EX(env); 136 env->ExceptionClear(); 137 } 138} 139 140// ---------------------------------------------------------------------------- 141 142static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz) 143{ 144 Mutex::Autolock l(sLock); 145 MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context); 146 return sp<MediaPlayer>(p); 147} 148 149static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player) 150{ 151 Mutex::Autolock l(sLock); 152 sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context); 153 if (player.get()) { 154 player->incStrong((void*)setMediaPlayer); 155 } 156 if (old != 0) { 157 old->decStrong((void*)setMediaPlayer); 158 } 159 env->SetLongField(thiz, fields.context, (jlong)player.get()); 160 return old; 161} 162 163// If exception is NULL and opStatus is not OK, this method sends an error 164// event to the client application; otherwise, if exception is not NULL and 165// opStatus is not OK, this method throws the given exception to the client 166// application. 167static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message) 168{ 169 if (exception == NULL) { // Don't throw exception. Instead, send an event. 170 if (opStatus != (status_t) OK) { 171 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 172 if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0); 173 } 174 } else { // Throw exception! 175 if ( opStatus == (status_t) INVALID_OPERATION ) { 176 jniThrowException(env, "java/lang/IllegalStateException", NULL); 177 } else if ( opStatus == (status_t) BAD_VALUE ) { 178 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 179 } else if ( opStatus == (status_t) PERMISSION_DENIED ) { 180 jniThrowException(env, "java/lang/SecurityException", NULL); 181 } else if ( opStatus != (status_t) OK ) { 182 if (strlen(message) > 230) { 183 // if the message is too long, don't bother displaying the status code 184 jniThrowException( env, exception, message); 185 } else { 186 char msg[256]; 187 // append the status code to the message 188 sprintf(msg, "%s: status=0x%X", message, opStatus); 189 jniThrowException( env, exception, msg); 190 } 191 } 192 } 193} 194 195static void 196android_media_MediaPlayer_setDataSourceAndHeaders( 197 JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path, 198 jobjectArray keys, jobjectArray values) { 199 200 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 201 if (mp == NULL ) { 202 jniThrowException(env, "java/lang/IllegalStateException", NULL); 203 return; 204 } 205 206 if (path == NULL) { 207 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 208 return; 209 } 210 211 const char *tmp = env->GetStringUTFChars(path, NULL); 212 if (tmp == NULL) { // Out of memory 213 return; 214 } 215 ALOGV("setDataSource: path %s", tmp); 216 217 String8 pathStr(tmp); 218 env->ReleaseStringUTFChars(path, tmp); 219 tmp = NULL; 220 221 // We build a KeyedVector out of the key and val arrays 222 KeyedVector<String8, String8> headersVector; 223 if (!ConvertKeyValueArraysToKeyedVector( 224 env, keys, values, &headersVector)) { 225 return; 226 } 227 228 sp<IMediaHTTPService> httpService; 229 if (httpServiceBinderObj != NULL) { 230 sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj); 231 httpService = interface_cast<IMediaHTTPService>(binder); 232 } 233 234 status_t opStatus = 235 mp->setDataSource( 236 httpService, 237 pathStr, 238 headersVector.size() > 0? &headersVector : NULL); 239 240 process_media_player_call( 241 env, thiz, opStatus, "java/io/IOException", 242 "setDataSource failed." ); 243} 244 245static void 246android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) 247{ 248 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 249 if (mp == NULL ) { 250 jniThrowException(env, "java/lang/IllegalStateException", NULL); 251 return; 252 } 253 254 if (fileDescriptor == NULL) { 255 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 256 return; 257 } 258 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); 259 ALOGV("setDataSourceFD: fd %d", fd); 260 process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." ); 261} 262 263static void 264android_media_MediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource) 265{ 266 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 267 if (mp == NULL ) { 268 jniThrowException(env, "java/lang/IllegalStateException", NULL); 269 return; 270 } 271 272 if (dataSource == NULL) { 273 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 274 return; 275 } 276 sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource); 277 process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." ); 278} 279 280static sp<IGraphicBufferProducer> 281getVideoSurfaceTexture(JNIEnv* env, jobject thiz) { 282 IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetLongField(thiz, fields.surface_texture); 283 return sp<IGraphicBufferProducer>(p); 284} 285 286static void 287decVideoSurfaceRef(JNIEnv *env, jobject thiz) 288{ 289 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 290 if (mp == NULL) { 291 return; 292 } 293 294 sp<IGraphicBufferProducer> old_st = getVideoSurfaceTexture(env, thiz); 295 if (old_st != NULL) { 296 old_st->decStrong((void*)decVideoSurfaceRef); 297 } 298} 299 300static void 301setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive) 302{ 303 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 304 if (mp == NULL) { 305 if (mediaPlayerMustBeAlive) { 306 jniThrowException(env, "java/lang/IllegalStateException", NULL); 307 } 308 return; 309 } 310 311 decVideoSurfaceRef(env, thiz); 312 313 sp<IGraphicBufferProducer> new_st; 314 if (jsurface) { 315 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 316 if (surface != NULL) { 317 new_st = surface->getIGraphicBufferProducer(); 318 if (new_st == NULL) { 319 jniThrowException(env, "java/lang/IllegalArgumentException", 320 "The surface does not have a binding SurfaceTexture!"); 321 return; 322 } 323 new_st->incStrong((void*)decVideoSurfaceRef); 324 } else { 325 jniThrowException(env, "java/lang/IllegalArgumentException", 326 "The surface has been released"); 327 return; 328 } 329 } 330 331 env->SetLongField(thiz, fields.surface_texture, (jlong)new_st.get()); 332 333 // This will fail if the media player has not been initialized yet. This 334 // can be the case if setDisplay() on MediaPlayer.java has been called 335 // before setDataSource(). The redundant call to setVideoSurfaceTexture() 336 // in prepare/prepareAsync covers for this case. 337 mp->setVideoSurfaceTexture(new_st); 338} 339 340static void 341android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface) 342{ 343 setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */); 344} 345 346static void 347android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz) 348{ 349 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 350 if (mp == NULL ) { 351 jniThrowException(env, "java/lang/IllegalStateException", NULL); 352 return; 353 } 354 355 // Handle the case where the display surface was set before the mp was 356 // initialized. We try again to make it stick. 357 sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz); 358 mp->setVideoSurfaceTexture(st); 359 360 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." ); 361} 362 363static void 364android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz) 365{ 366 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 367 if (mp == NULL ) { 368 jniThrowException(env, "java/lang/IllegalStateException", NULL); 369 return; 370 } 371 372 // Handle the case where the display surface was set before the mp was 373 // initialized. We try again to make it stick. 374 sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz); 375 mp->setVideoSurfaceTexture(st); 376 377 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." ); 378} 379 380static void 381android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) 382{ 383 ALOGV("start"); 384 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 385 if (mp == NULL ) { 386 jniThrowException(env, "java/lang/IllegalStateException", NULL); 387 return; 388 } 389 process_media_player_call( env, thiz, mp->start(), NULL, NULL ); 390} 391 392static void 393android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz) 394{ 395 ALOGV("stop"); 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->stop(), NULL, NULL ); 402} 403 404static void 405android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz) 406{ 407 ALOGV("pause"); 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->pause(), NULL, NULL ); 414} 415 416static jboolean 417android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz) 418{ 419 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 420 if (mp == NULL ) { 421 jniThrowException(env, "java/lang/IllegalStateException", NULL); 422 return JNI_FALSE; 423 } 424 const jboolean is_playing = mp->isPlaying(); 425 426 ALOGV("isPlaying: %d", is_playing); 427 return is_playing; 428} 429 430static void 431android_media_MediaPlayer_setPlaybackParams(JNIEnv *env, jobject thiz, jobject params) 432{ 433 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 434 if (mp == NULL) { 435 jniThrowException(env, "java/lang/IllegalStateException", NULL); 436 return; 437 } 438 439 PlaybackParams pbp; 440 pbp.fillFromJobject(env, gPlaybackParamsFields, params); 441 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u", 442 pbp.speedSet, pbp.audioRate.mSpeed, 443 pbp.pitchSet, pbp.audioRate.mPitch, 444 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode, 445 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode); 446 447 AudioPlaybackRate rate; 448 status_t err = mp->getPlaybackSettings(&rate); 449 if (err == OK) { 450 bool updatedRate = false; 451 if (pbp.speedSet) { 452 rate.mSpeed = pbp.audioRate.mSpeed; 453 updatedRate = true; 454 } 455 if (pbp.pitchSet) { 456 rate.mPitch = pbp.audioRate.mPitch; 457 updatedRate = true; 458 } 459 if (pbp.audioFallbackModeSet) { 460 rate.mFallbackMode = pbp.audioRate.mFallbackMode; 461 updatedRate = true; 462 } 463 if (pbp.audioStretchModeSet) { 464 rate.mStretchMode = pbp.audioRate.mStretchMode; 465 updatedRate = true; 466 } 467 if (updatedRate) { 468 err = mp->setPlaybackSettings(rate); 469 } 470 } 471 process_media_player_call( 472 env, thiz, err, 473 "java/lang/IllegalStateException", "unexpected error"); 474} 475 476static jobject 477android_media_MediaPlayer_getPlaybackParams(JNIEnv *env, jobject thiz) 478{ 479 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 480 if (mp == NULL) { 481 jniThrowException(env, "java/lang/IllegalStateException", NULL); 482 return NULL; 483 } 484 485 PlaybackParams pbp; 486 AudioPlaybackRate &audioRate = pbp.audioRate; 487 process_media_player_call( 488 env, thiz, mp->getPlaybackSettings(&audioRate), 489 "java/lang/IllegalStateException", "unexpected error"); 490 ALOGV("getPlaybackSettings: %f %f %d %d", 491 audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode); 492 493 pbp.speedSet = true; 494 pbp.pitchSet = true; 495 pbp.audioFallbackModeSet = true; 496 pbp.audioStretchModeSet = true; 497 498 return pbp.asJobject(env, gPlaybackParamsFields); 499} 500 501static void 502android_media_MediaPlayer_setSyncParams(JNIEnv *env, jobject thiz, jobject params) 503{ 504 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 505 if (mp == NULL) { 506 jniThrowException(env, "java/lang/IllegalStateException", NULL); 507 return; 508 } 509 510 SyncParams scp; 511 scp.fillFromJobject(env, gSyncParamsFields, params); 512 ALOGV("setSyncParams: %d:%d %d:%d %d:%f %d:%f", 513 scp.syncSourceSet, scp.sync.mSource, 514 scp.audioAdjustModeSet, scp.sync.mAudioAdjustMode, 515 scp.toleranceSet, scp.sync.mTolerance, 516 scp.frameRateSet, scp.frameRate); 517 518 AVSyncSettings avsync; 519 float videoFrameRate; 520 status_t err = mp->getSyncSettings(&avsync, &videoFrameRate); 521 if (err == OK) { 522 bool updatedSync = scp.frameRateSet; 523 if (scp.syncSourceSet) { 524 avsync.mSource = scp.sync.mSource; 525 updatedSync = true; 526 } 527 if (scp.audioAdjustModeSet) { 528 avsync.mAudioAdjustMode = scp.sync.mAudioAdjustMode; 529 updatedSync = true; 530 } 531 if (scp.toleranceSet) { 532 avsync.mTolerance = scp.sync.mTolerance; 533 updatedSync = true; 534 } 535 if (updatedSync) { 536 err = mp->setSyncSettings(avsync, scp.frameRateSet ? scp.frameRate : -1.f); 537 } 538 } 539 process_media_player_call( 540 env, thiz, err, 541 "java/lang/IllegalStateException", "unexpected error"); 542} 543 544static jobject 545android_media_MediaPlayer_getSyncParams(JNIEnv *env, jobject thiz) 546{ 547 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 548 if (mp == NULL) { 549 jniThrowException(env, "java/lang/IllegalStateException", NULL); 550 return NULL; 551 } 552 553 SyncParams scp; 554 scp.frameRate = -1.f; 555 process_media_player_call( 556 env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate), 557 "java/lang/IllegalStateException", "unexpected error"); 558 559 ALOGV("getSyncSettings: %d %d %f %f", 560 scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate); 561 562 // sanity check params 563 if (scp.sync.mSource >= AVSYNC_SOURCE_MAX 564 || scp.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX 565 || scp.sync.mTolerance < 0.f 566 || scp.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) { 567 jniThrowException(env, "java/lang/IllegalStateException", NULL); 568 return NULL; 569 } 570 571 scp.syncSourceSet = true; 572 scp.audioAdjustModeSet = true; 573 scp.toleranceSet = true; 574 scp.frameRateSet = scp.frameRate >= 0.f; 575 576 return scp.asJobject(env, gSyncParamsFields); 577} 578 579static void 580android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec) 581{ 582 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 583 if (mp == NULL ) { 584 jniThrowException(env, "java/lang/IllegalStateException", NULL); 585 return; 586 } 587 ALOGV("seekTo: %d(msec)", msec); 588 process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL ); 589} 590 591static jint 592android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz) 593{ 594 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 595 if (mp == NULL ) { 596 jniThrowException(env, "java/lang/IllegalStateException", NULL); 597 return 0; 598 } 599 int w; 600 if (0 != mp->getVideoWidth(&w)) { 601 ALOGE("getVideoWidth failed"); 602 w = 0; 603 } 604 ALOGV("getVideoWidth: %d", w); 605 return (jint) w; 606} 607 608static jint 609android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz) 610{ 611 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 612 if (mp == NULL ) { 613 jniThrowException(env, "java/lang/IllegalStateException", NULL); 614 return 0; 615 } 616 int h; 617 if (0 != mp->getVideoHeight(&h)) { 618 ALOGE("getVideoHeight failed"); 619 h = 0; 620 } 621 ALOGV("getVideoHeight: %d", h); 622 return (jint) h; 623} 624 625 626static jint 627android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz) 628{ 629 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 630 if (mp == NULL ) { 631 jniThrowException(env, "java/lang/IllegalStateException", NULL); 632 return 0; 633 } 634 int msec; 635 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL ); 636 ALOGV("getCurrentPosition: %d (msec)", msec); 637 return (jint) msec; 638} 639 640static jint 641android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz) 642{ 643 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 644 if (mp == NULL ) { 645 jniThrowException(env, "java/lang/IllegalStateException", NULL); 646 return 0; 647 } 648 int msec; 649 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL ); 650 ALOGV("getDuration: %d (msec)", msec); 651 return (jint) msec; 652} 653 654static void 655android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz) 656{ 657 ALOGV("reset"); 658 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 659 if (mp == NULL ) { 660 jniThrowException(env, "java/lang/IllegalStateException", NULL); 661 return; 662 } 663 process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); 664} 665 666static void 667android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, jint streamtype) 668{ 669 ALOGV("setAudioStreamType: %d", streamtype); 670 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 671 if (mp == NULL ) { 672 jniThrowException(env, "java/lang/IllegalStateException", NULL); 673 return; 674 } 675 process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL ); 676} 677 678static jint 679android_media_MediaPlayer_getAudioStreamType(JNIEnv *env, jobject thiz) 680{ 681 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 682 if (mp == NULL ) { 683 jniThrowException(env, "java/lang/IllegalStateException", NULL); 684 return 0; 685 } 686 audio_stream_type_t streamtype; 687 process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL ); 688 ALOGV("getAudioStreamType: %d (streamtype)", streamtype); 689 return (jint) streamtype; 690} 691 692static jboolean 693android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request) 694{ 695 ALOGV("setParameter: key %d", key); 696 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 697 if (mp == NULL ) { 698 jniThrowException(env, "java/lang/IllegalStateException", NULL); 699 return false; 700 } 701 702 Parcel *request = parcelForJavaObject(env, java_request); 703 status_t err = mp->setParameter(key, *request); 704 if (err == OK) { 705 return true; 706 } else { 707 return false; 708 } 709} 710 711static void 712android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping) 713{ 714 ALOGV("setLooping: %d", looping); 715 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 716 if (mp == NULL ) { 717 jniThrowException(env, "java/lang/IllegalStateException", NULL); 718 return; 719 } 720 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL ); 721} 722 723static jboolean 724android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz) 725{ 726 ALOGV("isLooping"); 727 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 728 if (mp == NULL ) { 729 jniThrowException(env, "java/lang/IllegalStateException", NULL); 730 return JNI_FALSE; 731 } 732 return mp->isLooping() ? JNI_TRUE : JNI_FALSE; 733} 734 735static void 736android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolume, jfloat rightVolume) 737{ 738 ALOGV("setVolume: left %f right %f", (float) leftVolume, (float) rightVolume); 739 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 740 if (mp == NULL ) { 741 jniThrowException(env, "java/lang/IllegalStateException", NULL); 742 return; 743 } 744 process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL ); 745} 746 747// Sends the request and reply parcels to the media player via the 748// binder interface. 749static jint 750android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz, 751 jobject java_request, jobject java_reply) 752{ 753 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 754 if (media_player == NULL ) { 755 jniThrowException(env, "java/lang/IllegalStateException", NULL); 756 return UNKNOWN_ERROR; 757 } 758 759 Parcel *request = parcelForJavaObject(env, java_request); 760 Parcel *reply = parcelForJavaObject(env, java_reply); 761 762 // Don't use process_media_player_call which use the async loop to 763 // report errors, instead returns the status. 764 return (jint) media_player->invoke(*request, reply); 765} 766 767// Sends the new filter to the client. 768static jint 769android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request) 770{ 771 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 772 if (media_player == NULL ) { 773 jniThrowException(env, "java/lang/IllegalStateException", NULL); 774 return UNKNOWN_ERROR; 775 } 776 777 Parcel *filter = parcelForJavaObject(env, request); 778 779 if (filter == NULL ) { 780 jniThrowException(env, "java/lang/RuntimeException", "Filter is null"); 781 return UNKNOWN_ERROR; 782 } 783 784 return (jint) media_player->setMetadataFilter(*filter); 785} 786 787static jboolean 788android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, 789 jboolean apply_filter, jobject reply) 790{ 791 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz); 792 if (media_player == NULL ) { 793 jniThrowException(env, "java/lang/IllegalStateException", NULL); 794 return JNI_FALSE; 795 } 796 797 Parcel *metadata = parcelForJavaObject(env, reply); 798 799 if (metadata == NULL ) { 800 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null"); 801 return JNI_FALSE; 802 } 803 804 metadata->freeData(); 805 // On return metadata is positioned at the beginning of the 806 // metadata. Note however that the parcel actually starts with the 807 // return code so you should not rewind the parcel using 808 // setDataPosition(0). 809 if (media_player->getMetadata(update_only, apply_filter, metadata) == OK) { 810 return JNI_TRUE; 811 } else { 812 return JNI_FALSE; 813 } 814} 815 816// This function gets some field IDs, which in turn causes class initialization. 817// It is called from a static block in MediaPlayer, which won't run until the 818// first time an instance of this class is used. 819static void 820android_media_MediaPlayer_native_init(JNIEnv *env) 821{ 822 jclass clazz; 823 824 clazz = env->FindClass("android/media/MediaPlayer"); 825 if (clazz == NULL) { 826 return; 827 } 828 829 fields.context = env->GetFieldID(clazz, "mNativeContext", "J"); 830 if (fields.context == NULL) { 831 return; 832 } 833 834 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", 835 "(Ljava/lang/Object;IIILjava/lang/Object;)V"); 836 if (fields.post_event == NULL) { 837 return; 838 } 839 840 fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J"); 841 if (fields.surface_texture == NULL) { 842 return; 843 } 844 845 env->DeleteLocalRef(clazz); 846 847 clazz = env->FindClass("android/net/ProxyInfo"); 848 if (clazz == NULL) { 849 return; 850 } 851 852 fields.proxyConfigGetHost = 853 env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;"); 854 855 fields.proxyConfigGetPort = 856 env->GetMethodID(clazz, "getPort", "()I"); 857 858 fields.proxyConfigGetExclusionList = 859 env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;"); 860 861 env->DeleteLocalRef(clazz); 862 863 gPlaybackParamsFields.init(env); 864 gSyncParamsFields.init(env); 865} 866 867static void 868android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) 869{ 870 ALOGV("native_setup"); 871 sp<MediaPlayer> mp = new MediaPlayer(); 872 if (mp == NULL) { 873 jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); 874 return; 875 } 876 877 // create new listener and give it to MediaPlayer 878 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); 879 mp->setListener(listener); 880 881 // Stow our new C++ MediaPlayer in an opaque field in the Java object. 882 setMediaPlayer(env, thiz, mp); 883} 884 885static void 886android_media_MediaPlayer_release(JNIEnv *env, jobject thiz) 887{ 888 ALOGV("release"); 889 decVideoSurfaceRef(env, thiz); 890 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0); 891 if (mp != NULL) { 892 // this prevents native callbacks after the object is released 893 mp->setListener(0); 894 mp->disconnect(); 895 } 896} 897 898static void 899android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz) 900{ 901 ALOGV("native_finalize"); 902 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 903 if (mp != NULL) { 904 ALOGW("MediaPlayer finalized without being released"); 905 } 906 android_media_MediaPlayer_release(env, thiz); 907} 908 909static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, 910 jint sessionId) { 911 ALOGV("set_session_id(): %d", sessionId); 912 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 913 if (mp == NULL ) { 914 jniThrowException(env, "java/lang/IllegalStateException", NULL); 915 return; 916 } 917 process_media_player_call( env, thiz, mp->setAudioSessionId((audio_session_t) sessionId), NULL, 918 NULL); 919} 920 921static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) { 922 ALOGV("get_session_id()"); 923 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 924 if (mp == NULL ) { 925 jniThrowException(env, "java/lang/IllegalStateException", NULL); 926 return 0; 927 } 928 929 return (jint) mp->getAudioSessionId(); 930} 931 932static void 933android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level) 934{ 935 ALOGV("setAuxEffectSendLevel: level %f", level); 936 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 937 if (mp == NULL ) { 938 jniThrowException(env, "java/lang/IllegalStateException", NULL); 939 return; 940 } 941 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL ); 942} 943 944static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) { 945 ALOGV("attachAuxEffect(): %d", effectId); 946 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 947 if (mp == NULL ) { 948 jniThrowException(env, "java/lang/IllegalStateException", NULL); 949 return; 950 } 951 process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL ); 952} 953 954static jint 955android_media_MediaPlayer_pullBatteryData( 956 JNIEnv *env, jobject /* thiz */, jobject java_reply) 957{ 958 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player")); 959 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 960 if (service.get() == NULL) { 961 jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService"); 962 return UNKNOWN_ERROR; 963 } 964 965 Parcel *reply = parcelForJavaObject(env, java_reply); 966 967 return (jint) service->pullBatteryData(reply); 968} 969 970static jint 971android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz, 972 jstring addrString, jint port) { 973 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 974 if (mp == NULL ) { 975 jniThrowException(env, "java/lang/IllegalStateException", NULL); 976 return INVALID_OPERATION; 977 } 978 979 const char *cAddrString = NULL; 980 981 if (NULL != addrString) { 982 cAddrString = env->GetStringUTFChars(addrString, NULL); 983 if (cAddrString == NULL) { // Out of memory 984 return NO_MEMORY; 985 } 986 } 987 ALOGV("setRetransmitEndpoint: %s:%d", 988 cAddrString ? cAddrString : "(null)", port); 989 990 status_t ret; 991 if (cAddrString && (port > 0xFFFF)) { 992 ret = BAD_VALUE; 993 } else { 994 ret = mp->setRetransmitEndpoint(cAddrString, 995 static_cast<uint16_t>(port)); 996 } 997 998 if (NULL != addrString) { 999 env->ReleaseStringUTFChars(addrString, cAddrString); 1000 } 1001 1002 if (ret == INVALID_OPERATION ) { 1003 jniThrowException(env, "java/lang/IllegalStateException", NULL); 1004 } 1005 1006 return (jint) ret; 1007} 1008 1009static void 1010android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player) 1011{ 1012 ALOGV("setNextMediaPlayer"); 1013 sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz); 1014 if (thisplayer == NULL) { 1015 jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized"); 1016 return; 1017 } 1018 sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player); 1019 if (nextplayer == NULL && java_player != NULL) { 1020 jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized"); 1021 return; 1022 } 1023 1024 if (nextplayer == thisplayer) { 1025 jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self"); 1026 return; 1027 } 1028 // tie the two players together 1029 process_media_player_call( 1030 env, thiz, thisplayer->setNextMediaPlayer(nextplayer), 1031 "java/lang/IllegalArgumentException", 1032 "setNextMediaPlayer failed." ); 1033 ; 1034} 1035 1036// ---------------------------------------------------------------------------- 1037 1038static const JNINativeMethod gMethods[] = { 1039 { 1040 "nativeSetDataSource", 1041 "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;" 1042 "[Ljava/lang/String;)V", 1043 (void *)android_media_MediaPlayer_setDataSourceAndHeaders 1044 }, 1045 1046 {"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, 1047 {"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback }, 1048 {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface}, 1049 {"_prepare", "()V", (void *)android_media_MediaPlayer_prepare}, 1050 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, 1051 {"_start", "()V", (void *)android_media_MediaPlayer_start}, 1052 {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, 1053 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, 1054 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, 1055 {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams}, 1056 {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams}, 1057 {"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams}, 1058 {"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer_getSyncParams}, 1059 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, 1060 {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, 1061 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, 1062 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, 1063 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, 1064 {"_release", "()V", (void *)android_media_MediaPlayer_release}, 1065 {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, 1066 {"_setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, 1067 {"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer_getAudioStreamType}, 1068 {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter}, 1069 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, 1070 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, 1071 {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, 1072 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, 1073 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, 1074 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, 1075 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, 1076 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, 1077 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, 1078 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, 1079 {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, 1080 {"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, 1081 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, 1082 {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, 1083 {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, 1084 {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer}, 1085}; 1086 1087// This function only registers the native methods 1088static int register_android_media_MediaPlayer(JNIEnv *env) 1089{ 1090 return AndroidRuntime::registerNativeMethods(env, 1091 "android/media/MediaPlayer", gMethods, NELEM(gMethods)); 1092} 1093extern int register_android_media_ExifInterface(JNIEnv *env); 1094extern int register_android_media_ImageReader(JNIEnv *env); 1095extern int register_android_media_ImageWriter(JNIEnv *env); 1096extern int register_android_media_Crypto(JNIEnv *env); 1097extern int register_android_media_Drm(JNIEnv *env); 1098extern int register_android_media_MediaCodec(JNIEnv *env); 1099extern int register_android_media_MediaExtractor(JNIEnv *env); 1100extern int register_android_media_MediaCodecList(JNIEnv *env); 1101extern int register_android_media_MediaHTTPConnection(JNIEnv *env); 1102extern int register_android_media_MediaMetadataRetriever(JNIEnv *env); 1103extern int register_android_media_MediaMuxer(JNIEnv *env); 1104extern int register_android_media_MediaRecorder(JNIEnv *env); 1105extern int register_android_media_MediaScanner(JNIEnv *env); 1106extern int register_android_media_MediaSync(JNIEnv *env); 1107extern int register_android_media_ResampleInputStream(JNIEnv *env); 1108extern int register_android_media_MediaProfiles(JNIEnv *env); 1109extern int register_android_media_AmrInputStream(JNIEnv *env); 1110extern int register_android_mtp_MtpDatabase(JNIEnv *env); 1111extern int register_android_mtp_MtpDevice(JNIEnv *env); 1112extern int register_android_mtp_MtpServer(JNIEnv *env); 1113 1114jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) 1115{ 1116 JNIEnv* env = NULL; 1117 jint result = -1; 1118 1119 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 1120 ALOGE("ERROR: GetEnv failed\n"); 1121 goto bail; 1122 } 1123 assert(env != NULL); 1124 1125 if (register_android_media_ImageWriter(env) != JNI_OK) { 1126 ALOGE("ERROR: ImageWriter native registration failed"); 1127 goto bail; 1128 } 1129 1130 if (register_android_media_ImageReader(env) < 0) { 1131 ALOGE("ERROR: ImageReader native registration failed"); 1132 goto bail; 1133 } 1134 1135 if (register_android_media_MediaPlayer(env) < 0) { 1136 ALOGE("ERROR: MediaPlayer native registration failed\n"); 1137 goto bail; 1138 } 1139 1140 if (register_android_media_MediaRecorder(env) < 0) { 1141 ALOGE("ERROR: MediaRecorder native registration failed\n"); 1142 goto bail; 1143 } 1144 1145 if (register_android_media_MediaScanner(env) < 0) { 1146 ALOGE("ERROR: MediaScanner native registration failed\n"); 1147 goto bail; 1148 } 1149 1150 if (register_android_media_MediaMetadataRetriever(env) < 0) { 1151 ALOGE("ERROR: MediaMetadataRetriever native registration failed\n"); 1152 goto bail; 1153 } 1154 1155 if (register_android_media_AmrInputStream(env) < 0) { 1156 ALOGE("ERROR: AmrInputStream native registration failed\n"); 1157 goto bail; 1158 } 1159 1160 if (register_android_media_ResampleInputStream(env) < 0) { 1161 ALOGE("ERROR: ResampleInputStream native registration failed\n"); 1162 goto bail; 1163 } 1164 1165 if (register_android_media_MediaProfiles(env) < 0) { 1166 ALOGE("ERROR: MediaProfiles native registration failed"); 1167 goto bail; 1168 } 1169 1170 if (register_android_mtp_MtpDatabase(env) < 0) { 1171 ALOGE("ERROR: MtpDatabase native registration failed"); 1172 goto bail; 1173 } 1174 1175 if (register_android_mtp_MtpDevice(env) < 0) { 1176 ALOGE("ERROR: MtpDevice native registration failed"); 1177 goto bail; 1178 } 1179 1180 if (register_android_mtp_MtpServer(env) < 0) { 1181 ALOGE("ERROR: MtpServer native registration failed"); 1182 goto bail; 1183 } 1184 1185 if (register_android_media_MediaCodec(env) < 0) { 1186 ALOGE("ERROR: MediaCodec native registration failed"); 1187 goto bail; 1188 } 1189 1190 if (register_android_media_MediaSync(env) < 0) { 1191 ALOGE("ERROR: MediaSync native registration failed"); 1192 goto bail; 1193 } 1194 1195 if (register_android_media_MediaExtractor(env) < 0) { 1196 ALOGE("ERROR: MediaCodec native registration failed"); 1197 goto bail; 1198 } 1199 1200 if (register_android_media_MediaMuxer(env) < 0) { 1201 ALOGE("ERROR: MediaMuxer native registration failed"); 1202 goto bail; 1203 } 1204 1205 if (register_android_media_MediaCodecList(env) < 0) { 1206 ALOGE("ERROR: MediaCodec native registration failed"); 1207 goto bail; 1208 } 1209 1210 if (register_android_media_Crypto(env) < 0) { 1211 ALOGE("ERROR: MediaCodec native registration failed"); 1212 goto bail; 1213 } 1214 1215 if (register_android_media_Drm(env) < 0) { 1216 ALOGE("ERROR: MediaDrm native registration failed"); 1217 goto bail; 1218 } 1219 1220 if (register_android_media_MediaHTTPConnection(env) < 0) { 1221 ALOGE("ERROR: MediaHTTPConnection native registration failed"); 1222 goto bail; 1223 } 1224 1225 if (register_android_media_ExifInterface(env) < 0) { 1226 ALOGE("ERROR: ExifInterface native registration failed"); 1227 goto bail; 1228 } 1229 1230 /* success -- return valid version number */ 1231 result = JNI_VERSION_1_4; 1232 1233bail: 1234 return result; 1235} 1236 1237// KTHXBYE 1238