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