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