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