OSDN Git Service

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