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