OSDN Git Service

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