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