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