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