android_media_MediaPlayer.cpp revision 097922b9c1e0821beb107024bcd0dc14144c0920
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_view_Surface.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_os_Parcel.h"
40#include "android_util_Binder.h"
41#include <binder/Parcel.h>
42#include <gui/ISurfaceTexture.h>
43#include <gui/Surface.h>
44#include <binder/IPCThreadState.h>
45#include <binder/IServiceManager.h>
46
47// ----------------------------------------------------------------------------
48
49using namespace android;
50
51// ----------------------------------------------------------------------------
52
53struct fields_t {
54    jfieldID    context;
55    jfieldID    surface_texture;
56
57    jmethodID   post_event;
58};
59static fields_t fields;
60
61static Mutex sLock;
62
63// ----------------------------------------------------------------------------
64// ref-counted object for callbacks
65class JNIMediaPlayerListener: public MediaPlayerListener
66{
67public:
68    JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
69    ~JNIMediaPlayerListener();
70    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
71private:
72    JNIMediaPlayerListener();
73    jclass      mClass;     // Reference to MediaPlayer class
74    jobject     mObject;    // Weak ref to MediaPlayer Java object to call on
75};
76
77JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
78{
79
80    // Hold onto the MediaPlayer class for use in calling the static method
81    // that posts events to the application thread.
82    jclass clazz = env->GetObjectClass(thiz);
83    if (clazz == NULL) {
84        ALOGE("Can't find android/media/MediaPlayer");
85        jniThrowException(env, "java/lang/Exception", NULL);
86        return;
87    }
88    mClass = (jclass)env->NewGlobalRef(clazz);
89
90    // We use a weak reference so the MediaPlayer object can be garbage collected.
91    // The reference is only used as a proxy for callbacks.
92    mObject  = env->NewGlobalRef(weak_thiz);
93}
94
95JNIMediaPlayerListener::~JNIMediaPlayerListener()
96{
97    // remove global references
98    JNIEnv *env = AndroidRuntime::getJNIEnv();
99    env->DeleteGlobalRef(mObject);
100    env->DeleteGlobalRef(mClass);
101}
102
103void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
104{
105    JNIEnv *env = AndroidRuntime::getJNIEnv();
106    if (obj && obj->dataSize() > 0) {
107        jobject jParcel = createJavaParcelObject(env);
108        if (jParcel != NULL) {
109            Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
110            nativeParcel->setData(obj->data(), obj->dataSize());
111            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
112                    msg, ext1, ext2, jParcel);
113        }
114    } else {
115        env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
116                msg, ext1, ext2, NULL);
117    }
118    if (env->ExceptionCheck()) {
119        ALOGW("An exception occurred while notifying an event.");
120        LOGW_EX(env);
121        env->ExceptionClear();
122    }
123}
124
125// ----------------------------------------------------------------------------
126
127static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
128{
129    Mutex::Autolock l(sLock);
130    MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);
131    return sp<MediaPlayer>(p);
132}
133
134static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
135{
136    Mutex::Autolock l(sLock);
137    sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
138    if (player.get()) {
139        player->incStrong(thiz);
140    }
141    if (old != 0) {
142        old->decStrong(thiz);
143    }
144    env->SetIntField(thiz, fields.context, (int)player.get());
145    return old;
146}
147
148// If exception is NULL and opStatus is not OK, this method sends an error
149// event to the client application; otherwise, if exception is not NULL and
150// opStatus is not OK, this method throws the given exception to the client
151// application.
152static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
153{
154    if (exception == NULL) {  // Don't throw exception. Instead, send an event.
155        if (opStatus != (status_t) OK) {
156            sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
157            if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
158        }
159    } else {  // Throw exception!
160        if ( opStatus == (status_t) INVALID_OPERATION ) {
161            jniThrowException(env, "java/lang/IllegalStateException", NULL);
162        } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
163            jniThrowException(env, "java/lang/SecurityException", NULL);
164        } else if ( opStatus != (status_t) OK ) {
165            if (strlen(message) > 230) {
166               // if the message is too long, don't bother displaying the status code
167               jniThrowException( env, exception, message);
168            } else {
169               char msg[256];
170                // append the status code to the message
171               sprintf(msg, "%s: status=0x%X", message, opStatus);
172               jniThrowException( env, exception, msg);
173            }
174        }
175    }
176}
177
178static void
179android_media_MediaPlayer_setDataSourceAndHeaders(
180        JNIEnv *env, jobject thiz, jstring path,
181        jobjectArray keys, jobjectArray values) {
182
183    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
184    if (mp == NULL ) {
185        jniThrowException(env, "java/lang/IllegalStateException", NULL);
186        return;
187    }
188
189    if (path == NULL) {
190        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
191        return;
192    }
193
194    const char *tmp = env->GetStringUTFChars(path, NULL);
195    if (tmp == NULL) {  // Out of memory
196        return;
197    }
198    ALOGV("setDataSource: path %s", tmp);
199
200    String8 pathStr(tmp);
201    env->ReleaseStringUTFChars(path, tmp);
202    tmp = NULL;
203
204    // We build a KeyedVector out of the key and val arrays
205    KeyedVector<String8, String8> headersVector;
206    if (!ConvertKeyValueArraysToKeyedVector(
207            env, keys, values, &headersVector)) {
208        return;
209    }
210
211    status_t opStatus =
212        mp->setDataSource(
213                pathStr,
214                headersVector.size() > 0? &headersVector : NULL);
215
216    process_media_player_call(
217            env, thiz, opStatus, "java/io/IOException",
218            "setDataSource failed." );
219}
220
221static void
222android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
223{
224    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
225    if (mp == NULL ) {
226        jniThrowException(env, "java/lang/IllegalStateException", NULL);
227        return;
228    }
229
230    if (fileDescriptor == NULL) {
231        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
232        return;
233    }
234    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
235    ALOGV("setDataSourceFD: fd %d", fd);
236    process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
237}
238
239static sp<ISurfaceTexture>
240getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
241    ISurfaceTexture * const p = (ISurfaceTexture*)env->GetIntField(thiz, fields.surface_texture);
242    return sp<ISurfaceTexture>(p);
243}
244
245static void
246decVideoSurfaceRef(JNIEnv *env, jobject thiz)
247{
248    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
249    if (mp == NULL) {
250        return;
251    }
252
253    sp<ISurfaceTexture> old_st = getVideoSurfaceTexture(env, thiz);
254    if (old_st != NULL) {
255        old_st->decStrong(thiz);
256    }
257}
258
259static void
260setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
261{
262    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
263    if (mp == NULL) {
264        if (mediaPlayerMustBeAlive) {
265            jniThrowException(env, "java/lang/IllegalStateException", NULL);
266        }
267        return;
268    }
269
270    decVideoSurfaceRef(env, thiz);
271
272    sp<ISurfaceTexture> new_st;
273    if (jsurface) {
274        sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
275        if (surface != NULL) {
276            new_st = surface->getSurfaceTexture();
277            if (new_st == NULL) {
278                jniThrowException(env, "java/lang/IllegalArgumentException",
279                    "The surface does not have a binding SurfaceTexture!");
280                return;
281            }
282            new_st->incStrong(thiz);
283        } else {
284            jniThrowException(env, "java/lang/IllegalArgumentException",
285                    "The surface has been released");
286            return;
287        }
288    }
289
290    env->SetIntField(thiz, fields.surface_texture, (int)new_st.get());
291
292    // This will fail if the media player has not been initialized yet. This
293    // can be the case if setDisplay() on MediaPlayer.java has been called
294    // before setDataSource(). The redundant call to setVideoSurfaceTexture()
295    // in prepare/prepareAsync covers for this case.
296    mp->setVideoSurfaceTexture(new_st);
297}
298
299static void
300android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
301{
302    setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
303}
304
305static void
306android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
307{
308    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
309    if (mp == NULL ) {
310        jniThrowException(env, "java/lang/IllegalStateException", NULL);
311        return;
312    }
313
314    // Handle the case where the display surface was set before the mp was
315    // initialized. We try again to make it stick.
316    sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz);
317    mp->setVideoSurfaceTexture(st);
318
319    process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
320}
321
322static void
323android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
324{
325    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
326    if (mp == NULL ) {
327        jniThrowException(env, "java/lang/IllegalStateException", NULL);
328        return;
329    }
330
331    // Handle the case where the display surface was set before the mp was
332    // initialized. We try again to make it stick.
333    sp<ISurfaceTexture> st = getVideoSurfaceTexture(env, thiz);
334    mp->setVideoSurfaceTexture(st);
335
336    process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
337}
338
339static void
340android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
341{
342    ALOGV("start");
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->start(), NULL, NULL );
349}
350
351static void
352android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
353{
354    ALOGV("stop");
355    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
356    if (mp == NULL ) {
357        jniThrowException(env, "java/lang/IllegalStateException", NULL);
358        return;
359    }
360    process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
361}
362
363static void
364android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
365{
366    ALOGV("pause");
367    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
368    if (mp == NULL ) {
369        jniThrowException(env, "java/lang/IllegalStateException", NULL);
370        return;
371    }
372    process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
373}
374
375static jboolean
376android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
377{
378    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
379    if (mp == NULL ) {
380        jniThrowException(env, "java/lang/IllegalStateException", NULL);
381        return false;
382    }
383    const jboolean is_playing = mp->isPlaying();
384
385    ALOGV("isPlaying: %d", is_playing);
386    return is_playing;
387}
388
389static void
390android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec)
391{
392    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
393    if (mp == NULL ) {
394        jniThrowException(env, "java/lang/IllegalStateException", NULL);
395        return;
396    }
397    ALOGV("seekTo: %d(msec)", msec);
398    process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
399}
400
401static int
402android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
403{
404    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
405    if (mp == NULL ) {
406        jniThrowException(env, "java/lang/IllegalStateException", NULL);
407        return 0;
408    }
409    int w;
410    if (0 != mp->getVideoWidth(&w)) {
411        ALOGE("getVideoWidth failed");
412        w = 0;
413    }
414    ALOGV("getVideoWidth: %d", w);
415    return w;
416}
417
418static int
419android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
420{
421    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
422    if (mp == NULL ) {
423        jniThrowException(env, "java/lang/IllegalStateException", NULL);
424        return 0;
425    }
426    int h;
427    if (0 != mp->getVideoHeight(&h)) {
428        ALOGE("getVideoHeight failed");
429        h = 0;
430    }
431    ALOGV("getVideoHeight: %d", h);
432    return h;
433}
434
435
436static int
437android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
438{
439    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
440    if (mp == NULL ) {
441        jniThrowException(env, "java/lang/IllegalStateException", NULL);
442        return 0;
443    }
444    int msec;
445    process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
446    ALOGV("getCurrentPosition: %d (msec)", msec);
447    return msec;
448}
449
450static int
451android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
452{
453    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
454    if (mp == NULL ) {
455        jniThrowException(env, "java/lang/IllegalStateException", NULL);
456        return 0;
457    }
458    int msec;
459    process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
460    ALOGV("getDuration: %d (msec)", msec);
461    return msec;
462}
463
464static void
465android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
466{
467    ALOGV("reset");
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->reset(), NULL, NULL );
474}
475
476static void
477android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype)
478{
479    ALOGV("setAudioStreamType: %d", streamtype);
480    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
481    if (mp == NULL ) {
482        jniThrowException(env, "java/lang/IllegalStateException", NULL);
483        return;
484    }
485    process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL );
486}
487
488static void
489android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
490{
491    ALOGV("setLooping: %d", looping);
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->setLooping(looping), NULL, NULL );
498}
499
500static jboolean
501android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
502{
503    ALOGV("isLooping");
504    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
505    if (mp == NULL ) {
506        jniThrowException(env, "java/lang/IllegalStateException", NULL);
507        return false;
508    }
509    return mp->isLooping();
510}
511
512static void
513android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume)
514{
515    ALOGV("setVolume: left %f  right %f", leftVolume, rightVolume);
516    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
517    if (mp == NULL ) {
518        jniThrowException(env, "java/lang/IllegalStateException", NULL);
519        return;
520    }
521    process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL );
522}
523
524// FIXME: deprecated
525static jobject
526android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec)
527{
528    return NULL;
529}
530
531
532// Sends the request and reply parcels to the media player via the
533// binder interface.
534static jint
535android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
536                                 jobject java_request, jobject java_reply)
537{
538    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
539    if (media_player == NULL ) {
540        jniThrowException(env, "java/lang/IllegalStateException", NULL);
541        return UNKNOWN_ERROR;
542    }
543
544    Parcel *request = parcelForJavaObject(env, java_request);
545    Parcel *reply = parcelForJavaObject(env, java_reply);
546
547    // Don't use process_media_player_call which use the async loop to
548    // report errors, instead returns the status.
549    return media_player->invoke(*request, reply);
550}
551
552// Sends the new filter to the client.
553static jint
554android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
555{
556    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
557    if (media_player == NULL ) {
558        jniThrowException(env, "java/lang/IllegalStateException", NULL);
559        return UNKNOWN_ERROR;
560    }
561
562    Parcel *filter = parcelForJavaObject(env, request);
563
564    if (filter == NULL ) {
565        jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
566        return UNKNOWN_ERROR;
567    }
568
569    return media_player->setMetadataFilter(*filter);
570}
571
572static jboolean
573android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
574                                      jboolean apply_filter, jobject reply)
575{
576    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
577    if (media_player == NULL ) {
578        jniThrowException(env, "java/lang/IllegalStateException", NULL);
579        return false;
580    }
581
582    Parcel *metadata = parcelForJavaObject(env, reply);
583
584    if (metadata == NULL ) {
585        jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
586        return false;
587    }
588
589    metadata->freeData();
590    // On return metadata is positioned at the beginning of the
591    // metadata. Note however that the parcel actually starts with the
592    // return code so you should not rewind the parcel using
593    // setDataPosition(0).
594    return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
595}
596
597// This function gets some field IDs, which in turn causes class initialization.
598// It is called from a static block in MediaPlayer, which won't run until the
599// first time an instance of this class is used.
600static void
601android_media_MediaPlayer_native_init(JNIEnv *env)
602{
603    jclass clazz;
604
605    clazz = env->FindClass("android/media/MediaPlayer");
606    if (clazz == NULL) {
607        return;
608    }
609
610    fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
611    if (fields.context == NULL) {
612        return;
613    }
614
615    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
616                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
617    if (fields.post_event == NULL) {
618        return;
619    }
620
621    fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "I");
622    if (fields.surface_texture == NULL) {
623        return;
624    }
625}
626
627static void
628android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
629{
630    ALOGV("native_setup");
631    sp<MediaPlayer> mp = new MediaPlayer();
632    if (mp == NULL) {
633        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
634        return;
635    }
636
637    // create new listener and give it to MediaPlayer
638    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
639    mp->setListener(listener);
640
641    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
642    setMediaPlayer(env, thiz, mp);
643}
644
645static void
646android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
647{
648    ALOGV("release");
649    decVideoSurfaceRef(env, thiz);
650    sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
651    if (mp != NULL) {
652        // this prevents native callbacks after the object is released
653        mp->setListener(0);
654        mp->disconnect();
655    }
656}
657
658static void
659android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
660{
661    ALOGV("native_finalize");
662    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
663    if (mp != NULL) {
664        ALOGW("MediaPlayer finalized without being released");
665    }
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    ALOGV("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    ALOGV("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    ALOGV("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    ALOGV("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 jint
728android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz,
729                                                jstring addrString, jint port) {
730    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
731    if (mp == NULL ) {
732        jniThrowException(env, "java/lang/IllegalStateException", NULL);
733        return INVALID_OPERATION;
734    }
735
736    const char *cAddrString = NULL;
737
738    if (NULL != addrString) {
739        cAddrString = env->GetStringUTFChars(addrString, NULL);
740        if (cAddrString == NULL) {  // Out of memory
741            return NO_MEMORY;
742        }
743    }
744    ALOGV("setRetransmitEndpoint: %s:%d",
745            cAddrString ? cAddrString : "(null)", port);
746
747    status_t ret;
748    if (cAddrString && (port > 0xFFFF)) {
749        ret = BAD_VALUE;
750    } else {
751        ret = mp->setRetransmitEndpoint(cAddrString,
752                static_cast<uint16_t>(port));
753    }
754
755    if (NULL != addrString) {
756        env->ReleaseStringUTFChars(addrString, cAddrString);
757    }
758
759    if (ret == INVALID_OPERATION ) {
760        jniThrowException(env, "java/lang/IllegalStateException", NULL);
761    }
762
763    return ret;
764}
765
766static jboolean
767android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
768{
769    ALOGV("setParameter: key %d", key);
770    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
771    if (mp == NULL ) {
772        jniThrowException(env, "java/lang/IllegalStateException", NULL);
773        return false;
774    }
775
776    Parcel *request = parcelForJavaObject(env, java_request);
777    status_t err = mp->setParameter(key, *request);
778    if (err == OK) {
779        return true;
780    } else {
781        return false;
782    }
783}
784
785static void
786android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply)
787{
788    ALOGV("getParameter: key %d", key);
789    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
790    if (mp == NULL ) {
791        jniThrowException(env, "java/lang/IllegalStateException", NULL);
792        return;
793    }
794
795    Parcel *reply = parcelForJavaObject(env, java_reply);
796    process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL );
797}
798
799static void
800android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
801{
802    ALOGV("setNextMediaPlayer");
803    sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz);
804    if (thisplayer == NULL) {
805        jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized");
806        return;
807    }
808    sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player);
809    if (nextplayer == NULL && java_player != NULL) {
810        jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized");
811        return;
812    }
813
814    if (nextplayer == thisplayer) {
815        jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self");
816        return;
817    }
818    // tie the two players together
819    process_media_player_call(
820            env, thiz, thisplayer->setNextMediaPlayer(nextplayer),
821            "java/lang/IllegalArgumentException",
822            "setNextMediaPlayer failed." );
823    ;
824}
825
826// ----------------------------------------------------------------------------
827
828static JNINativeMethod gMethods[] = {
829    {
830        "_setDataSource",
831        "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
832        (void *)android_media_MediaPlayer_setDataSourceAndHeaders
833    },
834
835    {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
836    {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
837    {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},
838    {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
839    {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
840    {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
841    {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},
842    {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},
843    {"seekTo",              "(I)V",                             (void *)android_media_MediaPlayer_seekTo},
844    {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},
845    {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},
846    {"getCurrentPosition",  "()I",                              (void *)android_media_MediaPlayer_getCurrentPosition},
847    {"getDuration",         "()I",                              (void *)android_media_MediaPlayer_getDuration},
848    {"_release",            "()V",                              (void *)android_media_MediaPlayer_release},
849    {"_reset",              "()V",                              (void *)android_media_MediaPlayer_reset},
850    {"setAudioStreamType",  "(I)V",                             (void *)android_media_MediaPlayer_setAudioStreamType},
851    {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},
852    {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},
853    {"setVolume",           "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},
854    {"getFrameAt",          "(I)Landroid/graphics/Bitmap;",     (void *)android_media_MediaPlayer_getFrameAt},
855    {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
856    {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},
857    {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},
858    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
859    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
860    {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
861    {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},
862    {"setAudioSessionId",   "(I)V",                             (void *)android_media_MediaPlayer_set_audio_session_id},
863    {"setAuxEffectSendLevel", "(F)V",                           (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
864    {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},
865    {"native_pullBatteryData", "(Landroid/os/Parcel;)I",        (void *)android_media_MediaPlayer_pullBatteryData},
866    {"setParameter",        "(ILandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_setParameter},
867    {"getParameter",        "(ILandroid/os/Parcel;)V",          (void *)android_media_MediaPlayer_getParameter},
868    {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer_setRetransmitEndpoint},
869    {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer;)V",   (void *)android_media_MediaPlayer_setNextMediaPlayer},
870};
871
872static const char* const kClassPathName = "android/media/MediaPlayer";
873
874// This function only registers the native methods
875static int register_android_media_MediaPlayer(JNIEnv *env)
876{
877    return AndroidRuntime::registerNativeMethods(env,
878                "android/media/MediaPlayer", gMethods, NELEM(gMethods));
879}
880
881extern int register_android_media_Crypto(JNIEnv *env);
882extern int register_android_media_MediaCodec(JNIEnv *env);
883extern int register_android_media_MediaExtractor(JNIEnv *env);
884extern int register_android_media_MediaCodecList(JNIEnv *env);
885extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
886extern int register_android_media_MediaRecorder(JNIEnv *env);
887extern int register_android_media_MediaScanner(JNIEnv *env);
888extern int register_android_media_ResampleInputStream(JNIEnv *env);
889extern int register_android_media_MediaProfiles(JNIEnv *env);
890extern int register_android_media_AmrInputStream(JNIEnv *env);
891extern int register_android_mtp_MtpDatabase(JNIEnv *env);
892extern int register_android_mtp_MtpDevice(JNIEnv *env);
893extern int register_android_mtp_MtpServer(JNIEnv *env);
894
895jint JNI_OnLoad(JavaVM* vm, void* reserved)
896{
897    JNIEnv* env = NULL;
898    jint result = -1;
899
900    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
901        ALOGE("ERROR: GetEnv failed\n");
902        goto bail;
903    }
904    assert(env != NULL);
905
906    if (register_android_media_MediaPlayer(env) < 0) {
907        ALOGE("ERROR: MediaPlayer native registration failed\n");
908        goto bail;
909    }
910
911    if (register_android_media_MediaRecorder(env) < 0) {
912        ALOGE("ERROR: MediaRecorder native registration failed\n");
913        goto bail;
914    }
915
916    if (register_android_media_MediaScanner(env) < 0) {
917        ALOGE("ERROR: MediaScanner native registration failed\n");
918        goto bail;
919    }
920
921    if (register_android_media_MediaMetadataRetriever(env) < 0) {
922        ALOGE("ERROR: MediaMetadataRetriever native registration failed\n");
923        goto bail;
924    }
925
926    if (register_android_media_AmrInputStream(env) < 0) {
927        ALOGE("ERROR: AmrInputStream native registration failed\n");
928        goto bail;
929    }
930
931    if (register_android_media_ResampleInputStream(env) < 0) {
932        ALOGE("ERROR: ResampleInputStream native registration failed\n");
933        goto bail;
934    }
935
936    if (register_android_media_MediaProfiles(env) < 0) {
937        ALOGE("ERROR: MediaProfiles native registration failed");
938        goto bail;
939    }
940
941    if (register_android_mtp_MtpDatabase(env) < 0) {
942        ALOGE("ERROR: MtpDatabase native registration failed");
943        goto bail;
944    }
945
946    if (register_android_mtp_MtpDevice(env) < 0) {
947        ALOGE("ERROR: MtpDevice native registration failed");
948        goto bail;
949    }
950
951    if (register_android_mtp_MtpServer(env) < 0) {
952        ALOGE("ERROR: MtpServer native registration failed");
953        goto bail;
954    }
955
956    if (register_android_media_MediaCodec(env) < 0) {
957        ALOGE("ERROR: MediaCodec native registration failed");
958        goto bail;
959    }
960
961    if (register_android_media_MediaExtractor(env) < 0) {
962        ALOGE("ERROR: MediaCodec native registration failed");
963        goto bail;
964    }
965
966    if (register_android_media_MediaCodecList(env) < 0) {
967        ALOGE("ERROR: MediaCodec native registration failed");
968        goto bail;
969    }
970
971    if (register_android_media_Crypto(env) < 0) {
972        ALOGE("ERROR: MediaCodec native registration failed");
973        goto bail;
974    }
975
976    /* success -- return valid version number */
977    result = JNI_VERSION_1_4;
978
979bail:
980    return result;
981}
982
983// KTHXBYE
984