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/AudioResamplerPublic.h>
     24 #include <media/IMediaHTTPService.h>
     25 #include <media/MediaPlayerInterface.h>
     26 #include <media/MediaAnalyticsItem.h>
     27 #include <media/stagefright/foundation/ByteUtils.h>  // for FOURCC definition
     28 #include <stdio.h>
     29 #include <assert.h>
     30 #include <limits.h>
     31 #include <unistd.h>
     32 #include <fcntl.h>
     33 #include <utils/threads.h>
     34 #include "jni.h"
     35 #include <nativehelper/JNIHelp.h>
     36 #include "android_runtime/AndroidRuntime.h"
     37 #include "android_runtime/android_view_Surface.h"
     38 #include "android_runtime/Log.h"
     39 #include "utils/Errors.h"  // for status_t
     40 #include "utils/KeyedVector.h"
     41 #include "utils/String8.h"
     42 #include "android_media_MediaDataSource.h"
     43 #include "android_media_MediaMetricsJNI.h"
     44 #include "android_media_PlaybackParams.h"
     45 #include "android_media_SyncParams.h"
     46 #include "android_media_VolumeShaper.h"
     47 #include "android_media_Streams.h"
     48 
     49 #include "android_os_Parcel.h"
     50 #include "android_util_Binder.h"
     51 #include <binder/Parcel.h>
     52 #include <gui/IGraphicBufferProducer.h>
     53 #include <gui/Surface.h>
     54 #include <binder/IPCThreadState.h>
     55 #include <binder/IServiceManager.h>
     56 
     57 #include "android_util_Binder.h"
     58 
     59 // Modular DRM begin
     60 #define FIND_CLASS(var, className) \
     61 var = env->FindClass(className); \
     62 LOG_FATAL_IF(! (var), "Unable to find class " className);
     63 
     64 #define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
     65 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
     66 LOG_FATAL_IF(! (var), "Unable to find method " fieldName);
     67 
     68 struct StateExceptionFields {
     69     jmethodID init;
     70     jclass classId;
     71 };
     72 
     73 static StateExceptionFields gStateExceptionFields;
     74 // Modular DRM end
     75 
     76 // ----------------------------------------------------------------------------
     77 
     78 using namespace android;
     79 
     80 using media::VolumeShaper;
     81 
     82 // ----------------------------------------------------------------------------
     83 
     84 struct fields_t {
     85     jfieldID    context;
     86     jfieldID    surface_texture;
     87 
     88     jmethodID   post_event;
     89 
     90     jmethodID   proxyConfigGetHost;
     91     jmethodID   proxyConfigGetPort;
     92     jmethodID   proxyConfigGetExclusionList;
     93 };
     94 static fields_t fields;
     95 
     96 static PlaybackParams::fields_t gPlaybackParamsFields;
     97 static SyncParams::fields_t gSyncParamsFields;
     98 static VolumeShaperHelper::fields_t gVolumeShaperFields;
     99 
    100 static Mutex sLock;
    101 
    102 // ----------------------------------------------------------------------------
    103 // ref-counted object for callbacks
    104 class JNIMediaPlayerListener: public MediaPlayerListener
    105 {
    106 public:
    107     JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
    108     ~JNIMediaPlayerListener();
    109     virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
    110 private:
    111     JNIMediaPlayerListener();
    112     jclass      mClass;     // Reference to MediaPlayer class
    113     jobject     mObject;    // Weak ref to MediaPlayer Java object to call on
    114 };
    115 
    116 JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
    117 {
    118 
    119     // Hold onto the MediaPlayer class for use in calling the static method
    120     // that posts events to the application thread.
    121     jclass clazz = env->GetObjectClass(thiz);
    122     if (clazz == NULL) {
    123         ALOGE("Can't find android/media/MediaPlayer");
    124         jniThrowException(env, "java/lang/Exception", NULL);
    125         return;
    126     }
    127     mClass = (jclass)env->NewGlobalRef(clazz);
    128 
    129     // We use a weak reference so the MediaPlayer object can be garbage collected.
    130     // The reference is only used as a proxy for callbacks.
    131     mObject  = env->NewGlobalRef(weak_thiz);
    132 }
    133 
    134 JNIMediaPlayerListener::~JNIMediaPlayerListener()
    135 {
    136     // remove global references
    137     JNIEnv *env = AndroidRuntime::getJNIEnv();
    138     env->DeleteGlobalRef(mObject);
    139     env->DeleteGlobalRef(mClass);
    140 }
    141 
    142 void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
    143 {
    144     JNIEnv *env = AndroidRuntime::getJNIEnv();
    145     if (obj && obj->dataSize() > 0) {
    146         jobject jParcel = createJavaParcelObject(env);
    147         if (jParcel != NULL) {
    148             Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
    149             nativeParcel->setData(obj->data(), obj->dataSize());
    150             env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
    151                     msg, ext1, ext2, jParcel);
    152             env->DeleteLocalRef(jParcel);
    153         }
    154     } else {
    155         env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
    156                 msg, ext1, ext2, NULL);
    157     }
    158     if (env->ExceptionCheck()) {
    159         ALOGW("An exception occurred while notifying an event.");
    160         LOGW_EX(env);
    161         env->ExceptionClear();
    162     }
    163 }
    164 
    165 // ----------------------------------------------------------------------------
    166 
    167 static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
    168 {
    169     Mutex::Autolock l(sLock);
    170     MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
    171     return sp<MediaPlayer>(p);
    172 }
    173 
    174 static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
    175 {
    176     Mutex::Autolock l(sLock);
    177     sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
    178     if (player.get()) {
    179         player->incStrong((void*)setMediaPlayer);
    180     }
    181     if (old != 0) {
    182         old->decStrong((void*)setMediaPlayer);
    183     }
    184     env->SetLongField(thiz, fields.context, (jlong)player.get());
    185     return old;
    186 }
    187 
    188 // If exception is NULL and opStatus is not OK, this method sends an error
    189 // event to the client application; otherwise, if exception is not NULL and
    190 // opStatus is not OK, this method throws the given exception to the client
    191 // application.
    192 static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
    193 {
    194     if (exception == NULL) {  // Don't throw exception. Instead, send an event.
    195         if (opStatus != (status_t) OK) {
    196             sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    197             if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
    198         }
    199     } else {  // Throw exception!
    200         if ( opStatus == (status_t) INVALID_OPERATION ) {
    201             jniThrowException(env, "java/lang/IllegalStateException", NULL);
    202         } else if ( opStatus == (status_t) BAD_VALUE ) {
    203             jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    204         } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
    205             jniThrowException(env, "java/lang/SecurityException", NULL);
    206         } else if ( opStatus != (status_t) OK ) {
    207             if (strlen(message) > 230) {
    208                // if the message is too long, don't bother displaying the status code
    209                jniThrowException( env, exception, message);
    210             } else {
    211                char msg[256];
    212                 // append the status code to the message
    213                sprintf(msg, "%s: status=0x%X", message, opStatus);
    214                jniThrowException( env, exception, msg);
    215             }
    216         }
    217     }
    218 }
    219 
    220 static void
    221 android_media_MediaPlayer_setDataSourceAndHeaders(
    222         JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
    223         jobjectArray keys, jobjectArray values) {
    224 
    225     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    226     if (mp == NULL ) {
    227         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    228         return;
    229     }
    230 
    231     if (path == NULL) {
    232         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    233         return;
    234     }
    235 
    236     const char *tmp = env->GetStringUTFChars(path, NULL);
    237     if (tmp == NULL) {  // Out of memory
    238         return;
    239     }
    240     ALOGV("setDataSource: path %s", tmp);
    241 
    242     String8 pathStr(tmp);
    243     env->ReleaseStringUTFChars(path, tmp);
    244     tmp = NULL;
    245 
    246     // We build a KeyedVector out of the key and val arrays
    247     KeyedVector<String8, String8> headersVector;
    248     if (!ConvertKeyValueArraysToKeyedVector(
    249             env, keys, values, &headersVector)) {
    250         return;
    251     }
    252 
    253     sp<IMediaHTTPService> httpService;
    254     if (httpServiceBinderObj != NULL) {
    255         sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
    256         httpService = interface_cast<IMediaHTTPService>(binder);
    257     }
    258 
    259     status_t opStatus =
    260         mp->setDataSource(
    261                 httpService,
    262                 pathStr,
    263                 headersVector.size() > 0? &headersVector : NULL);
    264 
    265     process_media_player_call(
    266             env, thiz, opStatus, "java/io/IOException",
    267             "setDataSource failed." );
    268 }
    269 
    270 static void
    271 android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
    272 {
    273     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    274     if (mp == NULL ) {
    275         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    276         return;
    277     }
    278 
    279     if (fileDescriptor == NULL) {
    280         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    281         return;
    282     }
    283     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    284     ALOGV("setDataSourceFD: fd %d", fd);
    285     process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
    286 }
    287 
    288 static void
    289 android_media_MediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
    290 {
    291     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    292     if (mp == NULL ) {
    293         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    294         return;
    295     }
    296 
    297     if (dataSource == NULL) {
    298         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    299         return;
    300     }
    301     sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource);
    302     process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." );
    303 }
    304 
    305 static sp<IGraphicBufferProducer>
    306 getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
    307     IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetLongField(thiz, fields.surface_texture);
    308     return sp<IGraphicBufferProducer>(p);
    309 }
    310 
    311 static void
    312 decVideoSurfaceRef(JNIEnv *env, jobject thiz)
    313 {
    314     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    315     if (mp == NULL) {
    316         return;
    317     }
    318 
    319     sp<IGraphicBufferProducer> old_st = getVideoSurfaceTexture(env, thiz);
    320     if (old_st != NULL) {
    321         old_st->decStrong((void*)decVideoSurfaceRef);
    322     }
    323 }
    324 
    325 static void
    326 setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
    327 {
    328     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    329     if (mp == NULL) {
    330         if (mediaPlayerMustBeAlive) {
    331             jniThrowException(env, "java/lang/IllegalStateException", NULL);
    332         }
    333         return;
    334     }
    335 
    336     decVideoSurfaceRef(env, thiz);
    337 
    338     sp<IGraphicBufferProducer> new_st;
    339     if (jsurface) {
    340         sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
    341         if (surface != NULL) {
    342             new_st = surface->getIGraphicBufferProducer();
    343             if (new_st == NULL) {
    344                 jniThrowException(env, "java/lang/IllegalArgumentException",
    345                     "The surface does not have a binding SurfaceTexture!");
    346                 return;
    347             }
    348             new_st->incStrong((void*)decVideoSurfaceRef);
    349         } else {
    350             jniThrowException(env, "java/lang/IllegalArgumentException",
    351                     "The surface has been released");
    352             return;
    353         }
    354     }
    355 
    356     env->SetLongField(thiz, fields.surface_texture, (jlong)new_st.get());
    357 
    358     // This will fail if the media player has not been initialized yet. This
    359     // can be the case if setDisplay() on MediaPlayer.java has been called
    360     // before setDataSource(). The redundant call to setVideoSurfaceTexture()
    361     // in prepare/prepareAsync covers for this case.
    362     mp->setVideoSurfaceTexture(new_st);
    363 }
    364 
    365 static void
    366 android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
    367 {
    368     setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
    369 }
    370 
    371 static void
    372 android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
    373 {
    374     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    375     if (mp == NULL ) {
    376         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    377         return;
    378     }
    379 
    380     // Handle the case where the display surface was set before the mp was
    381     // initialized. We try again to make it stick.
    382     sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
    383     mp->setVideoSurfaceTexture(st);
    384 
    385     process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
    386 }
    387 
    388 static void
    389 android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
    390 {
    391     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    392     if (mp == NULL ) {
    393         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    394         return;
    395     }
    396 
    397     // Handle the case where the display surface was set before the mp was
    398     // initialized. We try again to make it stick.
    399     sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
    400     mp->setVideoSurfaceTexture(st);
    401 
    402     process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
    403 }
    404 
    405 static void
    406 android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
    407 {
    408     ALOGV("start");
    409     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    410     if (mp == NULL ) {
    411         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    412         return;
    413     }
    414     process_media_player_call( env, thiz, mp->start(), NULL, NULL );
    415 }
    416 
    417 static void
    418 android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
    419 {
    420     ALOGV("stop");
    421     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    422     if (mp == NULL ) {
    423         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    424         return;
    425     }
    426     process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
    427 }
    428 
    429 static void
    430 android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
    431 {
    432     ALOGV("pause");
    433     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    434     if (mp == NULL ) {
    435         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    436         return;
    437     }
    438     process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
    439 }
    440 
    441 static jboolean
    442 android_media_MediaPlayer_isPlaying(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 JNI_FALSE;
    448     }
    449     const jboolean is_playing = mp->isPlaying();
    450 
    451     ALOGV("isPlaying: %d", is_playing);
    452     return is_playing;
    453 }
    454 
    455 static void
    456 android_media_MediaPlayer_setPlaybackParams(JNIEnv *env, jobject thiz, jobject params)
    457 {
    458     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    459     if (mp == NULL) {
    460         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    461         return;
    462     }
    463 
    464     PlaybackParams pbp;
    465     pbp.fillFromJobject(env, gPlaybackParamsFields, params);
    466     ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
    467             pbp.speedSet, pbp.audioRate.mSpeed,
    468             pbp.pitchSet, pbp.audioRate.mPitch,
    469             pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
    470             pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
    471 
    472     AudioPlaybackRate rate;
    473     status_t err = mp->getPlaybackSettings(&rate);
    474     if (err == OK) {
    475         bool updatedRate = false;
    476         if (pbp.speedSet) {
    477             rate.mSpeed = pbp.audioRate.mSpeed;
    478             updatedRate = true;
    479         }
    480         if (pbp.pitchSet) {
    481             rate.mPitch = pbp.audioRate.mPitch;
    482             updatedRate = true;
    483         }
    484         if (pbp.audioFallbackModeSet) {
    485             rate.mFallbackMode = pbp.audioRate.mFallbackMode;
    486             updatedRate = true;
    487         }
    488         if (pbp.audioStretchModeSet) {
    489             rate.mStretchMode = pbp.audioRate.mStretchMode;
    490             updatedRate = true;
    491         }
    492         if (updatedRate) {
    493             err = mp->setPlaybackSettings(rate);
    494         }
    495     }
    496     process_media_player_call(
    497             env, thiz, err,
    498             "java/lang/IllegalStateException", "unexpected error");
    499 }
    500 
    501 static jobject
    502 android_media_MediaPlayer_getPlaybackParams(JNIEnv *env, jobject thiz)
    503 {
    504     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    505     if (mp == NULL) {
    506         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    507         return NULL;
    508     }
    509 
    510     PlaybackParams pbp;
    511     AudioPlaybackRate &audioRate = pbp.audioRate;
    512     process_media_player_call(
    513             env, thiz, mp->getPlaybackSettings(&audioRate),
    514             "java/lang/IllegalStateException", "unexpected error");
    515     if (env->ExceptionCheck()) {
    516         return nullptr;
    517     }
    518     ALOGV("getPlaybackSettings: %f %f %d %d",
    519             audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
    520 
    521     pbp.speedSet = true;
    522     pbp.pitchSet = true;
    523     pbp.audioFallbackModeSet = true;
    524     pbp.audioStretchModeSet = true;
    525 
    526     return pbp.asJobject(env, gPlaybackParamsFields);
    527 }
    528 
    529 static void
    530 android_media_MediaPlayer_setSyncParams(JNIEnv *env, jobject thiz, jobject params)
    531 {
    532     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    533     if (mp == NULL) {
    534         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    535         return;
    536     }
    537 
    538     SyncParams scp;
    539     scp.fillFromJobject(env, gSyncParamsFields, params);
    540     ALOGV("setSyncParams: %d:%d %d:%d %d:%f %d:%f",
    541           scp.syncSourceSet, scp.sync.mSource,
    542           scp.audioAdjustModeSet, scp.sync.mAudioAdjustMode,
    543           scp.toleranceSet, scp.sync.mTolerance,
    544           scp.frameRateSet, scp.frameRate);
    545 
    546     AVSyncSettings avsync;
    547     float videoFrameRate;
    548     status_t err = mp->getSyncSettings(&avsync, &videoFrameRate);
    549     if (err == OK) {
    550         bool updatedSync = scp.frameRateSet;
    551         if (scp.syncSourceSet) {
    552             avsync.mSource = scp.sync.mSource;
    553             updatedSync = true;
    554         }
    555         if (scp.audioAdjustModeSet) {
    556             avsync.mAudioAdjustMode = scp.sync.mAudioAdjustMode;
    557             updatedSync = true;
    558         }
    559         if (scp.toleranceSet) {
    560             avsync.mTolerance = scp.sync.mTolerance;
    561             updatedSync = true;
    562         }
    563         if (updatedSync) {
    564             err = mp->setSyncSettings(avsync, scp.frameRateSet ? scp.frameRate : -1.f);
    565         }
    566     }
    567     process_media_player_call(
    568             env, thiz, err,
    569             "java/lang/IllegalStateException", "unexpected error");
    570 }
    571 
    572 static jobject
    573 android_media_MediaPlayer_getSyncParams(JNIEnv *env, jobject thiz)
    574 {
    575     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    576     if (mp == NULL) {
    577         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    578         return NULL;
    579     }
    580 
    581     SyncParams scp;
    582     scp.frameRate = -1.f;
    583     process_media_player_call(
    584             env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate),
    585             "java/lang/IllegalStateException", "unexpected error");
    586     if (env->ExceptionCheck()) {
    587         return nullptr;
    588     }
    589 
    590     ALOGV("getSyncSettings: %d %d %f %f",
    591             scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
    592 
    593     // sanity check params
    594     if (scp.sync.mSource >= AVSYNC_SOURCE_MAX
    595             || scp.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
    596             || scp.sync.mTolerance < 0.f
    597             || scp.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) {
    598         jniThrowException(env,  "java/lang/IllegalStateException", NULL);
    599         return NULL;
    600     }
    601 
    602     scp.syncSourceSet = true;
    603     scp.audioAdjustModeSet = true;
    604     scp.toleranceSet = true;
    605     scp.frameRateSet = scp.frameRate >= 0.f;
    606 
    607     return scp.asJobject(env, gSyncParamsFields);
    608 }
    609 
    610 static void
    611 android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jlong msec, jint mode)
    612 {
    613     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    614     if (mp == NULL ) {
    615         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    616         return;
    617     }
    618     ALOGV("seekTo: %lld(msec), mode=%d", (long long)msec, mode);
    619     process_media_player_call( env, thiz, mp->seekTo((int)msec, (MediaPlayerSeekMode)mode), NULL, NULL );
    620 }
    621 
    622 static void
    623 android_media_MediaPlayer_notifyAt(JNIEnv *env, jobject thiz, jlong mediaTimeUs)
    624 {
    625     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    626     if (mp == NULL) {
    627         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    628         return;
    629     }
    630     ALOGV("notifyAt: %lld", (long long)mediaTimeUs);
    631     process_media_player_call( env, thiz, mp->notifyAt((int64_t)mediaTimeUs), NULL, NULL );
    632 }
    633 
    634 static jint
    635 android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
    636 {
    637     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    638     if (mp == NULL ) {
    639         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    640         return 0;
    641     }
    642     int w;
    643     if (0 != mp->getVideoWidth(&w)) {
    644         ALOGE("getVideoWidth failed");
    645         w = 0;
    646     }
    647     ALOGV("getVideoWidth: %d", w);
    648     return (jint) w;
    649 }
    650 
    651 static jint
    652 android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
    653 {
    654     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    655     if (mp == NULL ) {
    656         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    657         return 0;
    658     }
    659     int h;
    660     if (0 != mp->getVideoHeight(&h)) {
    661         ALOGE("getVideoHeight failed");
    662         h = 0;
    663     }
    664     ALOGV("getVideoHeight: %d", h);
    665     return (jint) h;
    666 }
    667 
    668 static jobject
    669 android_media_MediaPlayer_native_getMetrics(JNIEnv *env, jobject thiz)
    670 {
    671     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    672     if (mp == NULL ) {
    673         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    674         return 0;
    675     }
    676 
    677     Parcel p;
    678     int key = FOURCC('m','t','r','X');
    679     status_t status = mp->getParameter(key, &p);
    680     if (status != OK) {
    681         ALOGD("getMetrics() failed: %d", status);
    682         return (jobject) NULL;
    683     }
    684 
    685     std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create());
    686     item->readFromParcel(p);
    687     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item.get(), NULL);
    688 
    689     return mybundle;
    690 }
    691 
    692 static jint
    693 android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
    694 {
    695     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    696     if (mp == NULL ) {
    697         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    698         return 0;
    699     }
    700     int msec;
    701     process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
    702     ALOGV("getCurrentPosition: %d (msec)", msec);
    703     return (jint) msec;
    704 }
    705 
    706 static jint
    707 android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
    708 {
    709     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    710     if (mp == NULL ) {
    711         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    712         return 0;
    713     }
    714     int msec;
    715     process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
    716     ALOGV("getDuration: %d (msec)", msec);
    717     return (jint) msec;
    718 }
    719 
    720 static void
    721 android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
    722 {
    723     ALOGV("reset");
    724     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    725     if (mp == NULL ) {
    726         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    727         return;
    728     }
    729     process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
    730 }
    731 
    732 static void
    733 android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, jint streamtype)
    734 {
    735     ALOGV("setAudioStreamType: %d", streamtype);
    736     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    737     if (mp == NULL ) {
    738         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    739         return;
    740     }
    741     process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL );
    742 }
    743 
    744 static jint
    745 android_media_MediaPlayer_getAudioStreamType(JNIEnv *env, jobject thiz)
    746 {
    747     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    748     if (mp == NULL ) {
    749         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    750         return 0;
    751     }
    752     audio_stream_type_t streamtype;
    753     process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL );
    754     ALOGV("getAudioStreamType: %d (streamtype)", streamtype);
    755     return (jint) streamtype;
    756 }
    757 
    758 static jboolean
    759 android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
    760 {
    761     ALOGV("setParameter: key %d", key);
    762     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    763     if (mp == NULL ) {
    764         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    765         return false;
    766     }
    767 
    768     Parcel *request = parcelForJavaObject(env, java_request);
    769     status_t err = mp->setParameter(key, *request);
    770     if (err == OK) {
    771         return true;
    772     } else {
    773         return false;
    774     }
    775 }
    776 
    777 static void
    778 android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
    779 {
    780     ALOGV("setLooping: %d", looping);
    781     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    782     if (mp == NULL ) {
    783         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    784         return;
    785     }
    786     process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
    787 }
    788 
    789 static jboolean
    790 android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
    791 {
    792     ALOGV("isLooping");
    793     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    794     if (mp == NULL ) {
    795         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    796         return JNI_FALSE;
    797     }
    798     return mp->isLooping() ? JNI_TRUE : JNI_FALSE;
    799 }
    800 
    801 static void
    802 android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolume, jfloat rightVolume)
    803 {
    804     ALOGV("setVolume: left %f  right %f", (float) leftVolume, (float) rightVolume);
    805     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    806     if (mp == NULL ) {
    807         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    808         return;
    809     }
    810     process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL );
    811 }
    812 
    813 // Sends the request and reply parcels to the media player via the
    814 // binder interface.
    815 static jint
    816 android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
    817                                  jobject java_request, jobject java_reply)
    818 {
    819     sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
    820     if (media_player == NULL ) {
    821         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    822         return UNKNOWN_ERROR;
    823     }
    824 
    825     Parcel *request = parcelForJavaObject(env, java_request);
    826     Parcel *reply = parcelForJavaObject(env, java_reply);
    827 
    828     // Don't use process_media_player_call which use the async loop to
    829     // report errors, instead returns the status.
    830     return (jint) media_player->invoke(*request, reply);
    831 }
    832 
    833 // Sends the new filter to the client.
    834 static jint
    835 android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
    836 {
    837     sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
    838     if (media_player == NULL ) {
    839         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    840         return UNKNOWN_ERROR;
    841     }
    842 
    843     Parcel *filter = parcelForJavaObject(env, request);
    844 
    845     if (filter == NULL ) {
    846         jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
    847         return UNKNOWN_ERROR;
    848     }
    849 
    850     return (jint) media_player->setMetadataFilter(*filter);
    851 }
    852 
    853 static jboolean
    854 android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
    855                                       jboolean apply_filter, jobject reply)
    856 {
    857     sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
    858     if (media_player == NULL ) {
    859         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    860         return JNI_FALSE;
    861     }
    862 
    863     Parcel *metadata = parcelForJavaObject(env, reply);
    864 
    865     if (metadata == NULL ) {
    866         jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
    867         return JNI_FALSE;
    868     }
    869 
    870     metadata->freeData();
    871     // On return metadata is positioned at the beginning of the
    872     // metadata. Note however that the parcel actually starts with the
    873     // return code so you should not rewind the parcel using
    874     // setDataPosition(0).
    875     if (media_player->getMetadata(update_only, apply_filter, metadata) == OK) {
    876         return JNI_TRUE;
    877     } else {
    878         return JNI_FALSE;
    879     }
    880 }
    881 
    882 // This function gets some field IDs, which in turn causes class initialization.
    883 // It is called from a static block in MediaPlayer, which won't run until the
    884 // first time an instance of this class is used.
    885 static void
    886 android_media_MediaPlayer_native_init(JNIEnv *env)
    887 {
    888     jclass clazz;
    889 
    890     clazz = env->FindClass("android/media/MediaPlayer");
    891     if (clazz == NULL) {
    892         return;
    893     }
    894 
    895     fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
    896     if (fields.context == NULL) {
    897         return;
    898     }
    899 
    900     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
    901                                                "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    902     if (fields.post_event == NULL) {
    903         return;
    904     }
    905 
    906     fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
    907     if (fields.surface_texture == NULL) {
    908         return;
    909     }
    910 
    911     env->DeleteLocalRef(clazz);
    912 
    913     clazz = env->FindClass("android/net/ProxyInfo");
    914     if (clazz == NULL) {
    915         return;
    916     }
    917 
    918     fields.proxyConfigGetHost =
    919         env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;");
    920 
    921     fields.proxyConfigGetPort =
    922         env->GetMethodID(clazz, "getPort", "()I");
    923 
    924     fields.proxyConfigGetExclusionList =
    925         env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
    926 
    927     env->DeleteLocalRef(clazz);
    928 
    929     // Modular DRM
    930     FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
    931     if (clazz) {
    932         GET_METHOD_ID(gStateExceptionFields.init, clazz, "<init>", "(ILjava/lang/String;)V");
    933         gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
    934 
    935         env->DeleteLocalRef(clazz);
    936     } else {
    937         ALOGE("JNI android_media_MediaPlayer_native_init couldn't "
    938               "get clazz android/media/MediaDrm$MediaDrmStateException");
    939     }
    940 
    941     gPlaybackParamsFields.init(env);
    942     gSyncParamsFields.init(env);
    943     gVolumeShaperFields.init(env);
    944 }
    945 
    946 static void
    947 android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
    948 {
    949     ALOGV("native_setup");
    950     sp<MediaPlayer> mp = new MediaPlayer();
    951     if (mp == NULL) {
    952         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
    953         return;
    954     }
    955 
    956     // create new listener and give it to MediaPlayer
    957     sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    958     mp->setListener(listener);
    959 
    960     // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    961     setMediaPlayer(env, thiz, mp);
    962 }
    963 
    964 static void
    965 android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
    966 {
    967     ALOGV("release");
    968     decVideoSurfaceRef(env, thiz);
    969     sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
    970     if (mp != NULL) {
    971         // this prevents native callbacks after the object is released
    972         mp->setListener(0);
    973         mp->disconnect();
    974     }
    975 }
    976 
    977 static void
    978 android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
    979 {
    980     ALOGV("native_finalize");
    981     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    982     if (mp != NULL) {
    983         ALOGW("MediaPlayer finalized without being released");
    984     }
    985     android_media_MediaPlayer_release(env, thiz);
    986 }
    987 
    988 static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env,  jobject thiz,
    989         jint sessionId) {
    990     ALOGV("set_session_id(): %d", sessionId);
    991     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    992     if (mp == NULL ) {
    993         jniThrowException(env, "java/lang/IllegalStateException", NULL);
    994         return;
    995     }
    996     process_media_player_call( env, thiz, mp->setAudioSessionId((audio_session_t) sessionId), NULL,
    997             NULL);
    998 }
    999 
   1000 static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env,  jobject thiz) {
   1001     ALOGV("get_session_id()");
   1002     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1003     if (mp == NULL ) {
   1004         jniThrowException(env, "java/lang/IllegalStateException", NULL);
   1005         return 0;
   1006     }
   1007 
   1008     return (jint) mp->getAudioSessionId();
   1009 }
   1010 
   1011 static void
   1012 android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
   1013 {
   1014     ALOGV("setAuxEffectSendLevel: level %f", level);
   1015     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1016     if (mp == NULL ) {
   1017         jniThrowException(env, "java/lang/IllegalStateException", NULL);
   1018         return;
   1019     }
   1020     process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
   1021 }
   1022 
   1023 static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env,  jobject thiz, jint effectId) {
   1024     ALOGV("attachAuxEffect(): %d", effectId);
   1025     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1026     if (mp == NULL ) {
   1027         jniThrowException(env, "java/lang/IllegalStateException", NULL);
   1028         return;
   1029     }
   1030     process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
   1031 }
   1032 
   1033 static jint
   1034 android_media_MediaPlayer_pullBatteryData(
   1035         JNIEnv *env, jobject /* thiz */, jobject java_reply)
   1036 {
   1037     sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
   1038     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
   1039     if (service.get() == NULL) {
   1040         jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
   1041         return UNKNOWN_ERROR;
   1042     }
   1043 
   1044     Parcel *reply = parcelForJavaObject(env, java_reply);
   1045 
   1046     return (jint) service->pullBatteryData(reply);
   1047 }
   1048 
   1049 static jint
   1050 android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz,
   1051                                                 jstring addrString, jint port) {
   1052     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1053     if (mp == NULL ) {
   1054         jniThrowException(env, "java/lang/IllegalStateException", NULL);
   1055         return INVALID_OPERATION;
   1056     }
   1057 
   1058     const char *cAddrString = NULL;
   1059 
   1060     if (NULL != addrString) {
   1061         cAddrString = env->GetStringUTFChars(addrString, NULL);
   1062         if (cAddrString == NULL) {  // Out of memory
   1063             return NO_MEMORY;
   1064         }
   1065     }
   1066     ALOGV("setRetransmitEndpoint: %s:%d",
   1067             cAddrString ? cAddrString : "(null)", port);
   1068 
   1069     status_t ret;
   1070     if (cAddrString && (port > 0xFFFF)) {
   1071         ret = BAD_VALUE;
   1072     } else {
   1073         ret = mp->setRetransmitEndpoint(cAddrString,
   1074                 static_cast<uint16_t>(port));
   1075     }
   1076 
   1077     if (NULL != addrString) {
   1078         env->ReleaseStringUTFChars(addrString, cAddrString);
   1079     }
   1080 
   1081     if (ret == INVALID_OPERATION ) {
   1082         jniThrowException(env, "java/lang/IllegalStateException", NULL);
   1083     }
   1084 
   1085     return (jint) ret;
   1086 }
   1087 
   1088 static void
   1089 android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
   1090 {
   1091     ALOGV("setNextMediaPlayer");
   1092     sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz);
   1093     if (thisplayer == NULL) {
   1094         jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized");
   1095         return;
   1096     }
   1097     sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player);
   1098     if (nextplayer == NULL && java_player != NULL) {
   1099         jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized");
   1100         return;
   1101     }
   1102 
   1103     if (nextplayer == thisplayer) {
   1104         jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self");
   1105         return;
   1106     }
   1107     // tie the two players together
   1108     process_media_player_call(
   1109             env, thiz, thisplayer->setNextMediaPlayer(nextplayer),
   1110             "java/lang/IllegalArgumentException",
   1111             "setNextMediaPlayer failed." );
   1112     ;
   1113 }
   1114 
   1115 // Pass through the arguments to the MediaServer player implementation.
   1116 static jint android_media_MediaPlayer_applyVolumeShaper(JNIEnv *env, jobject thiz,
   1117         jobject jconfig, jobject joperation) {
   1118     // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
   1119     const int VOLUME_SHAPER_INVALID_OPERATION = -38;
   1120 
   1121     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1122     if (mp == nullptr) {
   1123         return (jint)VOLUME_SHAPER_INVALID_OPERATION;
   1124     }
   1125 
   1126     sp<VolumeShaper::Configuration> configuration;
   1127     sp<VolumeShaper::Operation> operation;
   1128     if (jconfig != nullptr) {
   1129         configuration = VolumeShaperHelper::convertJobjectToConfiguration(
   1130                 env, gVolumeShaperFields, jconfig);
   1131         ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
   1132     }
   1133     if (joperation != nullptr) {
   1134         operation = VolumeShaperHelper::convertJobjectToOperation(
   1135                 env, gVolumeShaperFields, joperation);
   1136         ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
   1137     }
   1138     VolumeShaper::Status status = mp->applyVolumeShaper(configuration, operation);
   1139     if (status == INVALID_OPERATION) {
   1140         status = VOLUME_SHAPER_INVALID_OPERATION;
   1141     }
   1142     return (jint)status; // if status < 0 an error, else a VolumeShaper id
   1143 }
   1144 
   1145 // Pass through the arguments to the MediaServer player implementation.
   1146 static jobject android_media_MediaPlayer_getVolumeShaperState(JNIEnv *env, jobject thiz,
   1147         jint id) {
   1148     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1149     if (mp == nullptr) {
   1150         return (jobject)nullptr;
   1151     }
   1152 
   1153     sp<VolumeShaper::State> state = mp->getVolumeShaperState((int)id);
   1154     if (state.get() == nullptr) {
   1155         return (jobject)nullptr;
   1156     }
   1157     return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
   1158 }
   1159 
   1160 /////////////////////////////////////////////////////////////////////////////////////
   1161 // Modular DRM begin
   1162 
   1163 // TODO: investigate if these can be shared with their MediaDrm counterparts
   1164 static void throwDrmStateException(JNIEnv *env, const char *msg, status_t err)
   1165 {
   1166     ALOGE("Illegal DRM state exception: %s (%d)", msg, err);
   1167 
   1168     jobject exception = env->NewObject(gStateExceptionFields.classId,
   1169             gStateExceptionFields.init, static_cast<int>(err),
   1170             env->NewStringUTF(msg));
   1171     env->Throw(static_cast<jthrowable>(exception));
   1172 }
   1173 
   1174 // TODO: investigate if these can be shared with their MediaDrm counterparts
   1175 static bool throwDrmExceptionAsNecessary(JNIEnv *env, status_t err, const char *msg = NULL)
   1176 {
   1177     const char *drmMessage = "Unknown DRM Msg";
   1178 
   1179     switch (err) {
   1180     case ERROR_DRM_UNKNOWN:
   1181         drmMessage = "General DRM error";
   1182         break;
   1183     case ERROR_DRM_NO_LICENSE:
   1184         drmMessage = "No license";
   1185         break;
   1186     case ERROR_DRM_LICENSE_EXPIRED:
   1187         drmMessage = "License expired";
   1188         break;
   1189     case ERROR_DRM_SESSION_NOT_OPENED:
   1190         drmMessage = "Session not opened";
   1191         break;
   1192     case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
   1193         drmMessage = "Not initialized";
   1194         break;
   1195     case ERROR_DRM_DECRYPT:
   1196         drmMessage = "Decrypt error";
   1197         break;
   1198     case ERROR_DRM_CANNOT_HANDLE:
   1199         drmMessage = "Unsupported scheme or data format";
   1200         break;
   1201     case ERROR_DRM_TAMPER_DETECTED:
   1202         drmMessage = "Invalid state";
   1203         break;
   1204     default:
   1205         break;
   1206     }
   1207 
   1208     String8 vendorMessage;
   1209     if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
   1210         vendorMessage = String8::format("DRM vendor-defined error: %d", err);
   1211         drmMessage = vendorMessage.string();
   1212     }
   1213 
   1214     if (err == BAD_VALUE) {
   1215         jniThrowException(env, "java/lang/IllegalArgumentException", msg);
   1216         return true;
   1217     } else if (err == ERROR_DRM_NOT_PROVISIONED) {
   1218         jniThrowException(env, "android/media/NotProvisionedException", msg);
   1219         return true;
   1220     } else if (err == ERROR_DRM_RESOURCE_BUSY) {
   1221         jniThrowException(env, "android/media/ResourceBusyException", msg);
   1222         return true;
   1223     } else if (err == ERROR_DRM_DEVICE_REVOKED) {
   1224         jniThrowException(env, "android/media/DeniedByServerException", msg);
   1225         return true;
   1226     } else if (err == DEAD_OBJECT) {
   1227         jniThrowException(env, "android/media/MediaDrmResetException",
   1228                           "mediaserver died");
   1229         return true;
   1230     } else if (err != OK) {
   1231         String8 errbuf;
   1232         if (drmMessage != NULL) {
   1233             if (msg == NULL) {
   1234                 msg = drmMessage;
   1235             } else {
   1236                 errbuf = String8::format("%s: %s", msg, drmMessage);
   1237                 msg = errbuf.string();
   1238             }
   1239         }
   1240         throwDrmStateException(env, msg, err);
   1241         return true;
   1242     }
   1243     return false;
   1244 }
   1245 
   1246 static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray)
   1247 {
   1248     Vector<uint8_t> vector;
   1249     size_t length = env->GetArrayLength(byteArray);
   1250     vector.insertAt((size_t)0, length);
   1251     env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
   1252     return vector;
   1253 }
   1254 
   1255 static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz,
   1256                     jbyteArray uuidObj, jbyteArray drmSessionIdObj)
   1257 {
   1258     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1259     if (mp == NULL) {
   1260         jniThrowException(env, "java/lang/IllegalStateException", NULL);
   1261         return;
   1262     }
   1263 
   1264     if (uuidObj == NULL) {
   1265         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
   1266         return;
   1267     }
   1268 
   1269     Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
   1270 
   1271     if (uuid.size() != 16) {
   1272         jniThrowException(
   1273                           env,
   1274                           "java/lang/IllegalArgumentException",
   1275                           "invalid UUID size, expected 16 bytes");
   1276         return;
   1277     }
   1278 
   1279     Vector<uint8_t> drmSessionId = JByteArrayToVector(env, drmSessionIdObj);
   1280 
   1281     if (drmSessionId.size() == 0) {
   1282         jniThrowException(
   1283                           env,
   1284                           "java/lang/IllegalArgumentException",
   1285                           "empty drmSessionId");
   1286         return;
   1287     }
   1288 
   1289     status_t err = mp->prepareDrm(uuid.array(), drmSessionId);
   1290     if (err != OK) {
   1291         if (err == INVALID_OPERATION) {
   1292             jniThrowException(
   1293                               env,
   1294                               "java/lang/IllegalStateException",
   1295                               "The player must be in prepared state.");
   1296         } else if (err == ERROR_DRM_CANNOT_HANDLE) {
   1297             jniThrowException(
   1298                               env,
   1299                               "android/media/UnsupportedSchemeException",
   1300                               "Failed to instantiate drm object.");
   1301         } else {
   1302             throwDrmExceptionAsNecessary(env, err, "Failed to prepare DRM scheme");
   1303         }
   1304     }
   1305 }
   1306 
   1307 static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz)
   1308 {
   1309     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1310     if (mp == NULL ) {
   1311         jniThrowException(env, "java/lang/IllegalStateException", NULL);
   1312         return;
   1313     }
   1314 
   1315     status_t err = mp->releaseDrm();
   1316     if (err != OK) {
   1317         if (err == INVALID_OPERATION) {
   1318             jniThrowException(
   1319                               env,
   1320                               "java/lang/IllegalStateException",
   1321                               "Can not release DRM in an active player state.");
   1322         }
   1323     }
   1324 }
   1325 // Modular DRM end
   1326 // ----------------------------------------------------------------------------
   1327 
   1328 /////////////////////////////////////////////////////////////////////////////////////
   1329 // AudioRouting begin
   1330 static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject thiz, jint device_id)
   1331 {
   1332     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1333     if (mp == NULL) {
   1334         return false;
   1335     }
   1336     return mp->setOutputDevice(device_id) == NO_ERROR;
   1337 }
   1338 
   1339 static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz)
   1340 {
   1341     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1342     if (mp == NULL) {
   1343         return AUDIO_PORT_HANDLE_NONE;
   1344     }
   1345     return mp->getRoutedDeviceId();
   1346 }
   1347 
   1348 static void android_media_MediaPlayer_enableDeviceCallback(
   1349         JNIEnv* env, jobject thiz, jboolean enabled)
   1350 {
   1351     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
   1352     if (mp == NULL) {
   1353         return;
   1354     }
   1355 
   1356     status_t status = mp->enableAudioDeviceCallback(enabled);
   1357     if (status != NO_ERROR) {
   1358         jniThrowException(env, "java/lang/IllegalStateException", NULL);
   1359         ALOGE("enable device callback failed: %d", status);
   1360     }
   1361 }
   1362 
   1363 // AudioRouting end
   1364 // ----------------------------------------------------------------------------
   1365 
   1366 static const JNINativeMethod gMethods[] = {
   1367     {
   1368         "nativeSetDataSource",
   1369         "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
   1370         "[Ljava/lang/String;)V",
   1371         (void *)android_media_MediaPlayer_setDataSourceAndHeaders
   1372     },
   1373 
   1374     {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
   1375     {"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
   1376     {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
   1377     {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
   1378     {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
   1379     {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
   1380     {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
   1381     {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},
   1382     {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},
   1383     {"native_getMetrics",   "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer_native_getMetrics},
   1384     {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams},
   1385     {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
   1386     {"setSyncParams",     "(Landroid/media/SyncParams;)V",  (void *)android_media_MediaPlayer_setSyncParams},
   1387     {"getSyncParams",     "()Landroid/media/SyncParams;",   (void *)android_media_MediaPlayer_getSyncParams},
   1388     {"_seekTo",             "(JI)V",                            (void *)android_media_MediaPlayer_seekTo},
   1389     {"_notifyAt",           "(J)V",                             (void *)android_media_MediaPlayer_notifyAt},
   1390     {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},
   1391     {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},
   1392     {"getCurrentPosition",  "()I",                              (void *)android_media_MediaPlayer_getCurrentPosition},
   1393     {"getDuration",         "()I",                              (void *)android_media_MediaPlayer_getDuration},
   1394     {"_release",            "()V",                              (void *)android_media_MediaPlayer_release},
   1395     {"_reset",              "()V",                              (void *)android_media_MediaPlayer_reset},
   1396     {"_setAudioStreamType", "(I)V",                             (void *)android_media_MediaPlayer_setAudioStreamType},
   1397     {"_getAudioStreamType", "()I",                              (void *)android_media_MediaPlayer_getAudioStreamType},
   1398     {"setParameter",        "(ILandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_setParameter},
   1399     {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},
   1400     {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},
   1401     {"_setVolume",          "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},
   1402     {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
   1403     {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},
   1404     {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},
   1405     {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
   1406     {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
   1407     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
   1408     {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},
   1409     {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},
   1410     {"_setAuxEffectSendLevel", "(F)V",                          (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
   1411     {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},
   1412     {"native_pullBatteryData", "(Landroid/os/Parcel;)I",        (void *)android_media_MediaPlayer_pullBatteryData},
   1413     {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer_setRetransmitEndpoint},
   1414     {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer;)V",   (void *)android_media_MediaPlayer_setNextMediaPlayer},
   1415     {"native_applyVolumeShaper",
   1416                             "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
   1417                                                                 (void *)android_media_MediaPlayer_applyVolumeShaper},
   1418     {"native_getVolumeShaperState",
   1419                             "(I)Landroid/media/VolumeShaper$State;",
   1420                                                                 (void *)android_media_MediaPlayer_getVolumeShaperState},
   1421     // Modular DRM
   1422     { "_prepareDrm", "([B[B)V",                                 (void *)android_media_MediaPlayer_prepareDrm },
   1423     { "_releaseDrm", "()V",                                     (void *)android_media_MediaPlayer_releaseDrm },
   1424 
   1425     // AudioRouting
   1426     {"native_setOutputDevice", "(I)Z",                          (void *)android_media_MediaPlayer_setOutputDevice},
   1427     {"native_getRoutedDeviceId", "()I",                         (void *)android_media_MediaPlayer_getRoutedDeviceId},
   1428     {"native_enableDeviceCallback", "(Z)V",                     (void *)android_media_MediaPlayer_enableDeviceCallback},
   1429 };
   1430 
   1431 // This function only registers the native methods
   1432 static int register_android_media_MediaPlayer(JNIEnv *env)
   1433 {
   1434     return AndroidRuntime::registerNativeMethods(env,
   1435                 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
   1436 }
   1437 extern int register_android_media_ImageReader(JNIEnv *env);
   1438 extern int register_android_media_ImageWriter(JNIEnv *env);
   1439 extern int register_android_media_Crypto(JNIEnv *env);
   1440 extern int register_android_media_Drm(JNIEnv *env);
   1441 extern int register_android_media_Descrambler(JNIEnv *env);
   1442 extern int register_android_media_MediaCodec(JNIEnv *env);
   1443 extern int register_android_media_MediaExtractor(JNIEnv *env);
   1444 extern int register_android_media_MediaCodecList(JNIEnv *env);
   1445 extern int register_android_media_MediaHTTPConnection(JNIEnv *env);
   1446 extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
   1447 extern int register_android_media_MediaMuxer(JNIEnv *env);
   1448 extern int register_android_media_MediaRecorder(JNIEnv *env);
   1449 extern int register_android_media_MediaScanner(JNIEnv *env);
   1450 extern int register_android_media_MediaSync(JNIEnv *env);
   1451 extern int register_android_media_ResampleInputStream(JNIEnv *env);
   1452 extern int register_android_media_MediaProfiles(JNIEnv *env);
   1453 extern int register_android_mtp_MtpDatabase(JNIEnv *env);
   1454 extern int register_android_mtp_MtpDevice(JNIEnv *env);
   1455 extern int register_android_mtp_MtpServer(JNIEnv *env);
   1456 
   1457 jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
   1458 {
   1459     JNIEnv* env = NULL;
   1460     jint result = -1;
   1461 
   1462     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
   1463         ALOGE("ERROR: GetEnv failed\n");
   1464         goto bail;
   1465     }
   1466     assert(env != NULL);
   1467 
   1468     if (register_android_media_ImageWriter(env) != JNI_OK) {
   1469         ALOGE("ERROR: ImageWriter native registration failed");
   1470         goto bail;
   1471     }
   1472 
   1473     if (register_android_media_ImageReader(env) < 0) {
   1474         ALOGE("ERROR: ImageReader native registration failed");
   1475         goto bail;
   1476     }
   1477 
   1478     if (register_android_media_MediaPlayer(env) < 0) {
   1479         ALOGE("ERROR: MediaPlayer native registration failed\n");
   1480         goto bail;
   1481     }
   1482 
   1483     if (register_android_media_MediaRecorder(env) < 0) {
   1484         ALOGE("ERROR: MediaRecorder native registration failed\n");
   1485         goto bail;
   1486     }
   1487 
   1488     if (register_android_media_MediaScanner(env) < 0) {
   1489         ALOGE("ERROR: MediaScanner native registration failed\n");
   1490         goto bail;
   1491     }
   1492 
   1493     if (register_android_media_MediaMetadataRetriever(env) < 0) {
   1494         ALOGE("ERROR: MediaMetadataRetriever native registration failed\n");
   1495         goto bail;
   1496     }
   1497 
   1498     if (register_android_media_ResampleInputStream(env) < 0) {
   1499         ALOGE("ERROR: ResampleInputStream native registration failed\n");
   1500         goto bail;
   1501     }
   1502 
   1503     if (register_android_media_MediaProfiles(env) < 0) {
   1504         ALOGE("ERROR: MediaProfiles native registration failed");
   1505         goto bail;
   1506     }
   1507 
   1508     if (register_android_mtp_MtpDatabase(env) < 0) {
   1509         ALOGE("ERROR: MtpDatabase native registration failed");
   1510         goto bail;
   1511     }
   1512 
   1513     if (register_android_mtp_MtpDevice(env) < 0) {
   1514         ALOGE("ERROR: MtpDevice native registration failed");
   1515         goto bail;
   1516     }
   1517 
   1518     if (register_android_mtp_MtpServer(env) < 0) {
   1519         ALOGE("ERROR: MtpServer native registration failed");
   1520         goto bail;
   1521     }
   1522 
   1523     if (register_android_media_MediaCodec(env) < 0) {
   1524         ALOGE("ERROR: MediaCodec native registration failed");
   1525         goto bail;
   1526     }
   1527 
   1528     if (register_android_media_MediaSync(env) < 0) {
   1529         ALOGE("ERROR: MediaSync native registration failed");
   1530         goto bail;
   1531     }
   1532 
   1533     if (register_android_media_MediaExtractor(env) < 0) {
   1534         ALOGE("ERROR: MediaCodec native registration failed");
   1535         goto bail;
   1536     }
   1537 
   1538     if (register_android_media_MediaMuxer(env) < 0) {
   1539         ALOGE("ERROR: MediaMuxer native registration failed");
   1540         goto bail;
   1541     }
   1542 
   1543     if (register_android_media_MediaCodecList(env) < 0) {
   1544         ALOGE("ERROR: MediaCodec native registration failed");
   1545         goto bail;
   1546     }
   1547 
   1548     if (register_android_media_Crypto(env) < 0) {
   1549         ALOGE("ERROR: MediaCodec native registration failed");
   1550         goto bail;
   1551     }
   1552 
   1553     if (register_android_media_Drm(env) < 0) {
   1554         ALOGE("ERROR: MediaDrm native registration failed");
   1555         goto bail;
   1556     }
   1557 
   1558     if (register_android_media_Descrambler(env) < 0) {
   1559         ALOGE("ERROR: MediaDescrambler native registration failed");
   1560         goto bail;
   1561     }
   1562 
   1563     if (register_android_media_MediaHTTPConnection(env) < 0) {
   1564         ALOGE("ERROR: MediaHTTPConnection native registration failed");
   1565         goto bail;
   1566     }
   1567 
   1568     /* success -- return valid version number */
   1569     result = JNI_VERSION_1_4;
   1570 
   1571 bail:
   1572     return result;
   1573 }
   1574 
   1575 // KTHXBYE
   1576