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