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