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