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