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