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