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