android_media_MediaPlayer.cpp revision 79f407cc6c5ae34fc6f04d52fd034b49d1f002c4
1/*
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaPlayer-JNI"
20#include "utils/Log.h"
21
22#include <media/mediaplayer.h>
23#include <media/MediaPlayerInterface.h>
24#include <stdio.h>
25#include <assert.h>
26#include <limits.h>
27#include <unistd.h>
28#include <fcntl.h>
29#include <utils/threads.h>
30#include "jni.h"
31#include "JNIHelp.h"
32#include "android_runtime/AndroidRuntime.h"
33#include "utils/Errors.h"  // for status_t
34#include "utils/KeyedVector.h"
35#include "utils/String8.h"
36#include "android_media_Utils.h"
37
38#include "android_util_Binder.h"
39#include <binder/Parcel.h>
40#include <gui/SurfaceTexture.h>
41#include <gui/ISurfaceTexture.h>
42#include <surfaceflinger/Surface.h>
43#include <binder/IPCThreadState.h>
44#include <binder/IServiceManager.h>
45
46// ----------------------------------------------------------------------------
47
48using namespace android;
49
50// ----------------------------------------------------------------------------
51
52struct fields_t {
53    jfieldID    context;
54    jfieldID    surface;
55    jfieldID    surfaceTexture;
56    /* actually in android.view.Surface XXX */
57    jfieldID    surface_native;
58    // actually in android.graphics.SurfaceTexture
59    jfieldID    surfaceTexture_native;
60
61    jmethodID   post_event;
62};
63static fields_t fields;
64
65static Mutex sLock;
66
67// ----------------------------------------------------------------------------
68// ref-counted object for callbacks
69class JNIMediaPlayerListener: public MediaPlayerListener
70{
71public:
72    JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
73    ~JNIMediaPlayerListener();
74    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
75private:
76    JNIMediaPlayerListener();
77    jclass      mClass;     // Reference to MediaPlayer class
78    jobject     mObject;    // Weak ref to MediaPlayer Java object to call on
79};
80
81JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
82{
83
84    // Hold onto the MediaPlayer class for use in calling the static method
85    // that posts events to the application thread.
86    jclass clazz = env->GetObjectClass(thiz);
87    if (clazz == NULL) {
88        LOGE("Can't find android/media/MediaPlayer");
89        jniThrowException(env, "java/lang/Exception", NULL);
90        return;
91    }
92    mClass = (jclass)env->NewGlobalRef(clazz);
93
94    // We use a weak reference so the MediaPlayer object can be garbage collected.
95    // The reference is only used as a proxy for callbacks.
96    mObject  = env->NewGlobalRef(weak_thiz);
97}
98
99JNIMediaPlayerListener::~JNIMediaPlayerListener()
100{
101    // remove global references
102    JNIEnv *env = AndroidRuntime::getJNIEnv();
103    env->DeleteGlobalRef(mObject);
104    env->DeleteGlobalRef(mClass);
105}
106
107void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
108{
109    JNIEnv *env = AndroidRuntime::getJNIEnv();
110    if (obj && obj->dataSize() > 0) {
111        jbyteArray jArray = env->NewByteArray(obj->dataSize());
112        if (jArray != NULL) {
113            jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
114            memcpy(nArray, obj->data(), obj->dataSize());
115            env->ReleaseByteArrayElements(jArray, nArray, 0);
116            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
117                    msg, ext1, ext2, jArray);
118            env->DeleteLocalRef(jArray);
119        }
120    } else {
121        env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
122                msg, ext1, ext2, NULL);
123    }
124}
125
126// ----------------------------------------------------------------------------
127
128static Surface* get_surface(JNIEnv* env, jobject clazz)
129{
130    return (Surface*)env->GetIntField(clazz, fields.surface_native);
131}
132
133sp<ISurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
134{
135    sp<ISurfaceTexture> surfaceTexture(
136        (ISurfaceTexture*)env->GetIntField(clazz, fields.surfaceTexture_native));
137    return surfaceTexture;
138}
139
140static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
141{
142    Mutex::Autolock l(sLock);
143    MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);
144    return sp<MediaPlayer>(p);
145}
146
147static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
148{
149    Mutex::Autolock l(sLock);
150    sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
151    if (player.get()) {
152        player->incStrong(thiz);
153    }
154    if (old != 0) {
155        old->decStrong(thiz);
156    }
157    env->SetIntField(thiz, fields.context, (int)player.get());
158    return old;
159}
160
161// If exception is NULL and opStatus is not OK, this method sends an error
162// event to the client application; otherwise, if exception is not NULL and
163// opStatus is not OK, this method throws the given exception to the client
164// application.
165static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
166{
167    if (exception == NULL) {  // Don't throw exception. Instead, send an event.
168        if (opStatus != (status_t) OK) {
169            sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
170            if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
171        }
172    } else {  // Throw exception!
173        if ( opStatus == (status_t) INVALID_OPERATION ) {
174            jniThrowException(env, "java/lang/IllegalStateException", NULL);
175        } else if ( opStatus != (status_t) OK ) {
176            if (strlen(message) > 230) {
177               // if the message is too long, don't bother displaying the status code
178               jniThrowException( env, exception, message);
179            } else {
180               char msg[256];
181                // append the status code to the message
182               sprintf(msg, "%s: status=0x%X", message, opStatus);
183               jniThrowException( env, exception, msg);
184            }
185        }
186    }
187}
188
189static void
190android_media_MediaPlayer_setDataSourceAndHeaders(
191        JNIEnv *env, jobject thiz, jstring path,
192        jobjectArray keys, jobjectArray values) {
193
194    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
195    if (mp == NULL ) {
196        jniThrowException(env, "java/lang/IllegalStateException", NULL);
197        return;
198    }
199
200    if (path == NULL) {
201        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
202        return;
203    }
204
205    const char *tmp = env->GetStringUTFChars(path, NULL);
206    if (tmp == NULL) {  // Out of memory
207        return;
208    }
209
210    String8 pathStr(tmp);
211    env->ReleaseStringUTFChars(path, tmp);
212    tmp = NULL;
213
214    // We build a KeyedVector out of the key and val arrays
215    KeyedVector<String8, String8> headersVector;
216    if (!ConvertKeyValueArraysToKeyedVector(
217            env, keys, values, &headersVector)) {
218        return;
219    }
220
221    LOGV("setDataSource: path %s", pathStr);
222    status_t opStatus =
223        mp->setDataSource(
224                pathStr,
225                headersVector.size() > 0? &headersVector : NULL);
226
227    process_media_player_call(
228            env, thiz, opStatus, "java/io/IOException",
229            "setDataSource failed." );
230}
231
232static void
233android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
234{
235    android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, NULL, NULL);
236}
237
238static void
239android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
240{
241    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
242    if (mp == NULL ) {
243        jniThrowException(env, "java/lang/IllegalStateException", NULL);
244        return;
245    }
246
247    if (fileDescriptor == NULL) {
248        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
249        return;
250    }
251    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
252    LOGV("setDataSourceFD: fd %d", fd);
253    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
254}
255
256static void setVideoSurfaceOrSurfaceTexture(
257        const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz, const char *prefix)
258{
259    // The Java MediaPlayer class makes sure that at most one of mSurface and
260    // mSurfaceTexture is non-null.  But just in case, we give priority to
261    // mSurface over mSurfaceTexture.
262    jobject surface = env->GetObjectField(thiz, fields.surface);
263    if (surface != NULL) {
264        sp<Surface> native_surface(get_surface(env, surface));
265        LOGV("%s: surface=%p (id=%d)", prefix,
266             native_surface.get(), native_surface->getIdentity());
267        mp->setVideoSurface(native_surface);
268    } else {
269        jobject surfaceTexture = env->GetObjectField(thiz, fields.surfaceTexture);
270        if (surfaceTexture != NULL) {
271            sp<ISurfaceTexture> native_surfaceTexture(
272                    getSurfaceTexture(env, surfaceTexture));
273            LOGV("%s: texture=%p", prefix, native_surfaceTexture.get());
274            mp->setVideoSurfaceTexture(native_surfaceTexture);
275        }
276    }
277}
278
279static void
280android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture(JNIEnv *env, jobject thiz)
281{
282    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
283    if (mp == NULL ) {
284        jniThrowException(env, "java/lang/IllegalStateException", NULL);
285        return;
286    }
287    setVideoSurfaceOrSurfaceTexture(mp, env, thiz,
288            "_setVideoSurfaceOrSurfaceTexture");
289}
290
291static void
292android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
293{
294    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
295    if (mp == NULL ) {
296        jniThrowException(env, "java/lang/IllegalStateException", NULL);
297        return;
298    }
299    setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepare");
300    process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
301}
302
303static void
304android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
305{
306    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
307    if (mp == NULL ) {
308        jniThrowException(env, "java/lang/IllegalStateException", NULL);
309        return;
310    }
311    setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepareAsync");
312    process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
313}
314
315static void
316android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
317{
318    LOGV("start");
319    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
320    if (mp == NULL ) {
321        jniThrowException(env, "java/lang/IllegalStateException", NULL);
322        return;
323    }
324    process_media_player_call( env, thiz, mp->start(), NULL, NULL );
325}
326
327static void
328android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
329{
330    LOGV("stop");
331    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
332    if (mp == NULL ) {
333        jniThrowException(env, "java/lang/IllegalStateException", NULL);
334        return;
335    }
336    process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
337}
338
339static void
340android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
341{
342    LOGV("pause");
343    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
344    if (mp == NULL ) {
345        jniThrowException(env, "java/lang/IllegalStateException", NULL);
346        return;
347    }
348    process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
349}
350
351static jboolean
352android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
353{
354    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
355    if (mp == NULL ) {
356        jniThrowException(env, "java/lang/IllegalStateException", NULL);
357        return false;
358    }
359    const jboolean is_playing = mp->isPlaying();
360
361    LOGV("isPlaying: %d", is_playing);
362    return is_playing;
363}
364
365static void
366android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec)
367{
368    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
369    if (mp == NULL ) {
370        jniThrowException(env, "java/lang/IllegalStateException", NULL);
371        return;
372    }
373    LOGV("seekTo: %d(msec)", msec);
374    process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
375}
376
377static int
378android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
379{
380    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
381    if (mp == NULL ) {
382        jniThrowException(env, "java/lang/IllegalStateException", NULL);
383        return 0;
384    }
385    int w;
386    if (0 != mp->getVideoWidth(&w)) {
387        LOGE("getVideoWidth failed");
388        w = 0;
389    }
390    LOGV("getVideoWidth: %d", w);
391    return w;
392}
393
394static int
395android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
396{
397    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
398    if (mp == NULL ) {
399        jniThrowException(env, "java/lang/IllegalStateException", NULL);
400        return 0;
401    }
402    int h;
403    if (0 != mp->getVideoHeight(&h)) {
404        LOGE("getVideoHeight failed");
405        h = 0;
406    }
407    LOGV("getVideoHeight: %d", h);
408    return h;
409}
410
411
412static int
413android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
414{
415    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
416    if (mp == NULL ) {
417        jniThrowException(env, "java/lang/IllegalStateException", NULL);
418        return 0;
419    }
420    int msec;
421    process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
422    LOGV("getCurrentPosition: %d (msec)", msec);
423    return msec;
424}
425
426static int
427android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
428{
429    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
430    if (mp == NULL ) {
431        jniThrowException(env, "java/lang/IllegalStateException", NULL);
432        return 0;
433    }
434    int msec;
435    process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
436    LOGV("getDuration: %d (msec)", msec);
437    return msec;
438}
439
440static void
441android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
442{
443    LOGV("reset");
444    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
445    if (mp == NULL ) {
446        jniThrowException(env, "java/lang/IllegalStateException", NULL);
447        return;
448    }
449    process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
450}
451
452static void
453android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype)
454{
455    LOGV("setAudioStreamType: %d", streamtype);
456    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
457    if (mp == NULL ) {
458        jniThrowException(env, "java/lang/IllegalStateException", NULL);
459        return;
460    }
461    process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL );
462}
463
464static void
465android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
466{
467    LOGV("setLooping: %d", looping);
468    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
469    if (mp == NULL ) {
470        jniThrowException(env, "java/lang/IllegalStateException", NULL);
471        return;
472    }
473    process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
474}
475
476static jboolean
477android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
478{
479    LOGV("isLooping");
480    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
481    if (mp == NULL ) {
482        jniThrowException(env, "java/lang/IllegalStateException", NULL);
483        return false;
484    }
485    return mp->isLooping();
486}
487
488static void
489android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume)
490{
491    LOGV("setVolume: left %f  right %f", leftVolume, rightVolume);
492    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
493    if (mp == NULL ) {
494        jniThrowException(env, "java/lang/IllegalStateException", NULL);
495        return;
496    }
497    process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL );
498}
499
500// FIXME: deprecated
501static jobject
502android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec)
503{
504    return NULL;
505}
506
507
508// Sends the request and reply parcels to the media player via the
509// binder interface.
510static jint
511android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
512                                 jobject java_request, jobject java_reply)
513{
514    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
515    if (media_player == NULL ) {
516        jniThrowException(env, "java/lang/IllegalStateException", NULL);
517        return UNKNOWN_ERROR;
518    }
519
520
521    Parcel *request = parcelForJavaObject(env, java_request);
522    Parcel *reply = parcelForJavaObject(env, java_reply);
523
524    // Don't use process_media_player_call which use the async loop to
525    // report errors, instead returns the status.
526    return media_player->invoke(*request, reply);
527}
528
529// Sends the new filter to the client.
530static jint
531android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
532{
533    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
534    if (media_player == NULL ) {
535        jniThrowException(env, "java/lang/IllegalStateException", NULL);
536        return UNKNOWN_ERROR;
537    }
538
539    Parcel *filter = parcelForJavaObject(env, request);
540
541    if (filter == NULL ) {
542        jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
543        return UNKNOWN_ERROR;
544    }
545
546    return media_player->setMetadataFilter(*filter);
547}
548
549static jboolean
550android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
551                                      jboolean apply_filter, jobject reply)
552{
553    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
554    if (media_player == NULL ) {
555        jniThrowException(env, "java/lang/IllegalStateException", NULL);
556        return false;
557    }
558
559    Parcel *metadata = parcelForJavaObject(env, reply);
560
561    if (metadata == NULL ) {
562        jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
563        return false;
564    }
565
566    metadata->freeData();
567    // On return metadata is positioned at the beginning of the
568    // metadata. Note however that the parcel actually starts with the
569    // return code so you should not rewind the parcel using
570    // setDataPosition(0).
571    return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
572}
573
574// This function gets some field IDs, which in turn causes class initialization.
575// It is called from a static block in MediaPlayer, which won't run until the
576// first time an instance of this class is used.
577static void
578android_media_MediaPlayer_native_init(JNIEnv *env)
579{
580    jclass clazz;
581
582    clazz = env->FindClass("android/media/MediaPlayer");
583    if (clazz == NULL) {
584        return;
585    }
586
587    fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
588    if (fields.context == NULL) {
589        return;
590    }
591
592    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
593                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
594    if (fields.post_event == NULL) {
595        return;
596    }
597
598    fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
599    if (fields.surface == NULL) {
600        return;
601    }
602
603    jclass surface = env->FindClass("android/view/Surface");
604    if (surface == NULL) {
605        return;
606    }
607
608    fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I");
609    if (fields.surface_native == NULL) {
610        return;
611    }
612
613    fields.surfaceTexture = env->GetFieldID(clazz, "mSurfaceTexture",
614            "Landroid/graphics/SurfaceTexture;");
615    if (fields.surfaceTexture == NULL) {
616        return;
617    }
618
619    jclass surfaceTexture = env->FindClass("android/graphics/SurfaceTexture");
620    if (surfaceTexture == NULL) {
621        return;
622    }
623
624    fields.surfaceTexture_native = env->GetFieldID(surfaceTexture,
625            ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
626    if (fields.surfaceTexture_native == NULL) {
627        return;
628    }
629
630}
631
632static void
633android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
634{
635    LOGV("native_setup");
636    sp<MediaPlayer> mp = new MediaPlayer();
637    if (mp == NULL) {
638        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
639        return;
640    }
641
642    // create new listener and give it to MediaPlayer
643    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
644    mp->setListener(listener);
645
646    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
647    setMediaPlayer(env, thiz, mp);
648}
649
650static void
651android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
652{
653    LOGV("release");
654    sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
655    if (mp != NULL) {
656        // this prevents native callbacks after the object is released
657        mp->setListener(0);
658        mp->disconnect();
659    }
660}
661
662static void
663android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
664{
665    LOGV("native_finalize");
666    android_media_MediaPlayer_release(env, thiz);
667}
668
669static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env,  jobject thiz, jint sessionId) {
670    LOGV("set_session_id(): %d", sessionId);
671    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
672    if (mp == NULL ) {
673        jniThrowException(env, "java/lang/IllegalStateException", NULL);
674        return;
675    }
676    process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );
677}
678
679static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env,  jobject thiz) {
680    LOGV("get_session_id()");
681    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
682    if (mp == NULL ) {
683        jniThrowException(env, "java/lang/IllegalStateException", NULL);
684        return 0;
685    }
686
687    return mp->getAudioSessionId();
688}
689
690static void
691android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
692{
693    LOGV("setAuxEffectSendLevel: level %f", level);
694    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
695    if (mp == NULL ) {
696        jniThrowException(env, "java/lang/IllegalStateException", NULL);
697        return;
698    }
699    process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
700}
701
702static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env,  jobject thiz, jint effectId) {
703    LOGV("attachAuxEffect(): %d", effectId);
704    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
705    if (mp == NULL ) {
706        jniThrowException(env, "java/lang/IllegalStateException", NULL);
707        return;
708    }
709    process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
710}
711
712static jint
713android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply)
714{
715    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
716    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
717    if (service.get() == NULL) {
718        jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
719        return UNKNOWN_ERROR;
720    }
721
722    Parcel *reply = parcelForJavaObject(env, java_reply);
723
724    return service->pullBatteryData(reply);
725}
726
727static jboolean
728android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
729{
730    LOGV("setParameter: key %d", key);
731    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
732    if (mp == NULL ) {
733        jniThrowException(env, "java/lang/IllegalStateException", NULL);
734        return false;
735    }
736
737    Parcel *request = parcelForJavaObject(env, java_request);
738    status_t err = mp->setParameter(key, *request);
739    if (err == OK) {
740        return true;
741    } else {
742        return false;
743    }
744}
745
746static void
747android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply)
748{
749    LOGV("getParameter: key %d", key);
750    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
751    if (mp == NULL ) {
752        jniThrowException(env, "java/lang/IllegalStateException", NULL);
753        return;
754    }
755
756    Parcel *reply = parcelForJavaObject(env, java_reply);
757    process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL );
758}
759
760// ----------------------------------------------------------------------------
761
762static JNINativeMethod gMethods[] = {
763    {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},
764
765    {
766        "_setDataSource",
767        "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
768        (void *)android_media_MediaPlayer_setDataSourceAndHeaders
769    },
770
771    {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
772    {"_setVideoSurfaceOrSurfaceTexture", "()V",                 (void *)android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture},
773    {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},
774    {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
775    {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
776    {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
777    {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},
778    {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},
779    {"seekTo",              "(I)V",                             (void *)android_media_MediaPlayer_seekTo},
780    {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},
781    {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},
782    {"getCurrentPosition",  "()I",                              (void *)android_media_MediaPlayer_getCurrentPosition},
783    {"getDuration",         "()I",                              (void *)android_media_MediaPlayer_getDuration},
784    {"_release",            "()V",                              (void *)android_media_MediaPlayer_release},
785    {"_reset",              "()V",                              (void *)android_media_MediaPlayer_reset},
786    {"setAudioStreamType",  "(I)V",                             (void *)android_media_MediaPlayer_setAudioStreamType},
787    {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},
788    {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},
789    {"setVolume",           "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},
790    {"getFrameAt",          "(I)Landroid/graphics/Bitmap;",     (void *)android_media_MediaPlayer_getFrameAt},
791    {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
792    {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},
793    {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},
794    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
795    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
796    {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
797    {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},
798    {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},
799    {"setAuxEffectSendLevel", "(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
800    {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},
801    {"native_pullBatteryData", "(Landroid/os/Parcel;)I",        (void *)android_media_MediaPlayer_pullBatteryData},
802    {"setParameter",        "(ILandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_setParameter},
803    {"getParameter",        "(ILandroid/os/Parcel;)V",          (void *)android_media_MediaPlayer_getParameter},
804};
805
806static const char* const kClassPathName = "android/media/MediaPlayer";
807
808// This function only registers the native methods
809static int register_android_media_MediaPlayer(JNIEnv *env)
810{
811    return AndroidRuntime::registerNativeMethods(env,
812                "android/media/MediaPlayer", gMethods, NELEM(gMethods));
813}
814
815extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
816extern int register_android_media_MediaRecorder(JNIEnv *env);
817extern int register_android_media_MediaScanner(JNIEnv *env);
818extern int register_android_media_ResampleInputStream(JNIEnv *env);
819extern int register_android_media_MediaProfiles(JNIEnv *env);
820extern int register_android_media_AmrInputStream(JNIEnv *env);
821extern int register_android_mtp_MtpDatabase(JNIEnv *env);
822extern int register_android_mtp_MtpDevice(JNIEnv *env);
823extern int register_android_mtp_MtpServer(JNIEnv *env);
824
825jint JNI_OnLoad(JavaVM* vm, void* reserved)
826{
827    JNIEnv* env = NULL;
828    jint result = -1;
829
830    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
831        LOGE("ERROR: GetEnv failed\n");
832        goto bail;
833    }
834    assert(env != NULL);
835
836    if (register_android_media_MediaPlayer(env) < 0) {
837        LOGE("ERROR: MediaPlayer native registration failed\n");
838        goto bail;
839    }
840
841    if (register_android_media_MediaRecorder(env) < 0) {
842        LOGE("ERROR: MediaRecorder native registration failed\n");
843        goto bail;
844    }
845
846    if (register_android_media_MediaScanner(env) < 0) {
847        LOGE("ERROR: MediaScanner native registration failed\n");
848        goto bail;
849    }
850
851    if (register_android_media_MediaMetadataRetriever(env) < 0) {
852        LOGE("ERROR: MediaMetadataRetriever native registration failed\n");
853        goto bail;
854    }
855
856    if (register_android_media_AmrInputStream(env) < 0) {
857        LOGE("ERROR: AmrInputStream native registration failed\n");
858        goto bail;
859    }
860
861    if (register_android_media_ResampleInputStream(env) < 0) {
862        LOGE("ERROR: ResampleInputStream native registration failed\n");
863        goto bail;
864    }
865
866    if (register_android_media_MediaProfiles(env) < 0) {
867        LOGE("ERROR: MediaProfiles native registration failed");
868        goto bail;
869    }
870
871    if (register_android_mtp_MtpDatabase(env) < 0) {
872        LOGE("ERROR: MtpDatabase native registration failed");
873        goto bail;
874    }
875
876    if (register_android_mtp_MtpDevice(env) < 0) {
877        LOGE("ERROR: MtpDevice native registration failed");
878        goto bail;
879    }
880
881    if (register_android_mtp_MtpServer(env) < 0) {
882        LOGE("ERROR: MtpServer native registration failed");
883        goto bail;
884    }
885
886    /* success -- return valid version number */
887    result = JNI_VERSION_1_4;
888
889bail:
890    return result;
891}
892
893// KTHXBYE
894