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