blob: b03aa38be87c768e4a346247e4bfc25768c35a32 [file] [log] [blame]
James Dongc371a022011-04-06 12:16:07 -07001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002**
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>
Nicolas Catania20cb94e2009-05-12 23:25:55 -070023#include <media/MediaPlayerInterface.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024#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"
The Android Open Source Project4df24232009-03-05 14:34:35 -080033#include "utils/Errors.h" // for status_t
Andreas Huber25643002010-01-28 11:19:57 -080034#include "utils/KeyedVector.h"
35#include "utils/String8.h"
James Dong79f407c2011-05-05 12:50:04 -070036#include "android_media_Utils.h"
37
Nicolas Catania20cb94e2009-05-12 23:25:55 -070038#include "android_util_Binder.h"
39#include <binder/Parcel.h>
Glenn Kastencc562a32011-02-08 17:26:17 -080040#include <gui/SurfaceTexture.h>
41#include <gui/ISurfaceTexture.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080042#include <surfaceflinger/Surface.h>
Gloria Wangd211f412011-02-19 18:37:57 -080043#include <binder/IPCThreadState.h>
44#include <binder/IServiceManager.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045
46// ----------------------------------------------------------------------------
47
48using namespace android;
49
50// ----------------------------------------------------------------------------
51
52struct fields_t {
53 jfieldID context;
54 jfieldID surface;
Glenn Kastencc562a32011-02-08 17:26:17 -080055 jfieldID surfaceTexture;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 /* actually in android.view.Surface XXX */
57 jfieldID surface_native;
Glenn Kastencc562a32011-02-08 17:26:17 -080058 // actually in android.graphics.SurfaceTexture
59 jfieldID surfaceTexture_native;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060
61 jmethodID post_event;
62};
63static fields_t fields;
64
65static Mutex sLock;
66
67// ----------------------------------------------------------------------------
68// ref-counted object for callbacks
69class JNIMediaPlayerListener: public MediaPlayerListener
70{
71public:
72 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
73 ~JNIMediaPlayerListener();
Gloria Wang162ee492011-04-11 17:23:27 -070074 virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075private:
76 JNIMediaPlayerListener();
77 jclass mClass; // Reference to MediaPlayer class
78 jobject mObject; // Weak ref to MediaPlayer Java object to call on
79};
80
81JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
82{
83
84 // Hold onto the MediaPlayer class for use in calling the static method
85 // that posts events to the application thread.
86 jclass clazz = env->GetObjectClass(thiz);
87 if (clazz == NULL) {
88 LOGE("Can't find android/media/MediaPlayer");
89 jniThrowException(env, "java/lang/Exception", NULL);
90 return;
91 }
92 mClass = (jclass)env->NewGlobalRef(clazz);
93
94 // We use a weak reference so the MediaPlayer object can be garbage collected.
95 // The reference is only used as a proxy for callbacks.
96 mObject = env->NewGlobalRef(weak_thiz);
97}
98
99JNIMediaPlayerListener::~JNIMediaPlayerListener()
100{
101 // remove global references
102 JNIEnv *env = AndroidRuntime::getJNIEnv();
103 env->DeleteGlobalRef(mObject);
104 env->DeleteGlobalRef(mClass);
105}
106
Gloria Wang162ee492011-04-11 17:23:27 -0700107void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108{
109 JNIEnv *env = AndroidRuntime::getJNIEnv();
Gloria Wang162ee492011-04-11 17:23:27 -0700110 if (obj && obj->dataSize() > 0) {
111 jbyteArray jArray = env->NewByteArray(obj->dataSize());
112 if (jArray != NULL) {
113 jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
114 memcpy(nArray, obj->data(), obj->dataSize());
115 env->ReleaseByteArrayElements(jArray, nArray, 0);
116 env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
117 msg, ext1, ext2, jArray);
118 env->DeleteLocalRef(jArray);
119 }
120 } else {
121 env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
122 msg, ext1, ext2, NULL);
123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124}
125
126// ----------------------------------------------------------------------------
127
Marco Nelissen0fc736f322009-07-10 09:34:59 -0700128static Surface* get_surface(JNIEnv* env, jobject clazz)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129{
Marco Nelissen0fc736f322009-07-10 09:34:59 -0700130 return (Surface*)env->GetIntField(clazz, fields.surface_native);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131}
132
Glenn Kastencc562a32011-02-08 17:26:17 -0800133sp<ISurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
134{
135 sp<ISurfaceTexture> surfaceTexture(
136 (ISurfaceTexture*)env->GetIntField(clazz, fields.surfaceTexture_native));
137 return surfaceTexture;
138}
139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
141{
142 Mutex::Autolock l(sLock);
143 MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);
144 return sp<MediaPlayer>(p);
145}
146
147static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
148{
149 Mutex::Autolock l(sLock);
150 sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
151 if (player.get()) {
152 player->incStrong(thiz);
153 }
154 if (old != 0) {
155 old->decStrong(thiz);
156 }
157 env->SetIntField(thiz, fields.context, (int)player.get());
158 return old;
159}
160
Nicolas Catania32f82772009-06-11 16:33:49 -0700161// If exception is NULL and opStatus is not OK, this method sends an error
162// event to the client application; otherwise, if exception is not NULL and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163// opStatus is not OK, this method throws the given exception to the client
164// application.
165static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
166{
167 if (exception == NULL) { // Don't throw exception. Instead, send an event.
168 if (opStatus != (status_t) OK) {
169 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
170 if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
171 }
172 } else { // Throw exception!
173 if ( opStatus == (status_t) INVALID_OPERATION ) {
174 jniThrowException(env, "java/lang/IllegalStateException", NULL);
175 } else if ( opStatus != (status_t) OK ) {
176 if (strlen(message) > 230) {
177 // if the message is too long, don't bother displaying the status code
178 jniThrowException( env, exception, message);
179 } else {
180 char msg[256];
181 // append the status code to the message
182 sprintf(msg, "%s: status=0x%X", message, opStatus);
183 jniThrowException( env, exception, msg);
184 }
185 }
186 }
187}
188
189static void
Andreas Huber25643002010-01-28 11:19:57 -0800190android_media_MediaPlayer_setDataSourceAndHeaders(
James Dong17524dc2011-05-04 13:41:58 -0700191 JNIEnv *env, jobject thiz, jstring path,
192 jobjectArray keys, jobjectArray values) {
193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
195 if (mp == NULL ) {
196 jniThrowException(env, "java/lang/IllegalStateException", NULL);
197 return;
198 }
199
200 if (path == NULL) {
201 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
202 return;
203 }
204
James Dongc371a022011-04-06 12:16:07 -0700205 const char *tmp = env->GetStringUTFChars(path, NULL);
206 if (tmp == NULL) { // Out of memory
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 return;
208 }
Andreas Huber25643002010-01-28 11:19:57 -0800209
James Dongc371a022011-04-06 12:16:07 -0700210 String8 pathStr(tmp);
211 env->ReleaseStringUTFChars(path, tmp);
212 tmp = NULL;
213
James Dong17524dc2011-05-04 13:41:58 -0700214 // We build a KeyedVector out of the key and val arrays
Andreas Huber25643002010-01-28 11:19:57 -0800215 KeyedVector<String8, String8> headersVector;
James Dong79f407c2011-05-05 12:50:04 -0700216 if (!ConvertKeyValueArraysToKeyedVector(
217 env, keys, values, &headersVector)) {
218 return;
Andreas Huber25643002010-01-28 11:19:57 -0800219 }
220
The Android Open Source Project4df24232009-03-05 14:34:35 -0800221 LOGV("setDataSource: path %s", pathStr);
Andreas Huber25643002010-01-28 11:19:57 -0800222 status_t opStatus =
223 mp->setDataSource(
James Dongc371a022011-04-06 12:16:07 -0700224 pathStr,
James Dong79f407c2011-05-05 12:50:04 -0700225 headersVector.size() > 0? &headersVector : NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226
Andreas Huber25643002010-01-28 11:19:57 -0800227 process_media_player_call(
228 env, thiz, opStatus, "java/io/IOException",
229 "setDataSource failed." );
230}
231
232static void
233android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
234{
James Dong17524dc2011-05-04 13:41:58 -0700235 android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, NULL, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236}
237
238static void
239android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
240{
241 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
242 if (mp == NULL ) {
243 jniThrowException(env, "java/lang/IllegalStateException", NULL);
244 return;
245 }
246
247 if (fileDescriptor == NULL) {
248 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
249 return;
250 }
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700251 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800252 LOGV("setDataSourceFD: fd %d", fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
254}
255
Glenn Kastencc562a32011-02-08 17:26:17 -0800256static void setVideoSurfaceOrSurfaceTexture(
257 const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz, const char *prefix)
Dave Sparks8b0b1742009-05-29 09:01:20 -0700258{
Glenn Kastencc562a32011-02-08 17:26:17 -0800259 // The Java MediaPlayer class makes sure that at most one of mSurface and
260 // mSurfaceTexture is non-null. But just in case, we give priority to
261 // mSurface over mSurfaceTexture.
Dave Sparks8b0b1742009-05-29 09:01:20 -0700262 jobject surface = env->GetObjectField(thiz, fields.surface);
263 if (surface != NULL) {
Glenn Kastencc562a32011-02-08 17:26:17 -0800264 sp<Surface> native_surface(get_surface(env, surface));
265 LOGV("%s: surface=%p (id=%d)", prefix,
Eric Laurent619346f2010-06-21 09:27:30 -0700266 native_surface.get(), native_surface->getIdentity());
Dave Sparks8b0b1742009-05-29 09:01:20 -0700267 mp->setVideoSurface(native_surface);
Glenn Kastencc562a32011-02-08 17:26:17 -0800268 } else {
269 jobject surfaceTexture = env->GetObjectField(thiz, fields.surfaceTexture);
270 if (surfaceTexture != NULL) {
271 sp<ISurfaceTexture> native_surfaceTexture(
272 getSurfaceTexture(env, surfaceTexture));
James Donga93f84e2011-04-01 13:29:27 -0700273 LOGV("%s: texture=%p", prefix, native_surfaceTexture.get());
Glenn Kastencc562a32011-02-08 17:26:17 -0800274 mp->setVideoSurfaceTexture(native_surfaceTexture);
275 }
Dave Sparks8b0b1742009-05-29 09:01:20 -0700276 }
277}
278
279static void
Glenn Kastencc562a32011-02-08 17:26:17 -0800280android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture(JNIEnv *env, jobject thiz)
Dave Sparks8b0b1742009-05-29 09:01:20 -0700281{
282 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
283 if (mp == NULL ) {
284 jniThrowException(env, "java/lang/IllegalStateException", NULL);
285 return;
286 }
Glenn Kastencc562a32011-02-08 17:26:17 -0800287 setVideoSurfaceOrSurfaceTexture(mp, env, thiz,
288 "_setVideoSurfaceOrSurfaceTexture");
Dave Sparks8b0b1742009-05-29 09:01:20 -0700289}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290
291static void
292android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
293{
294 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
295 if (mp == NULL ) {
296 jniThrowException(env, "java/lang/IllegalStateException", NULL);
297 return;
298 }
Glenn Kastencc562a32011-02-08 17:26:17 -0800299 setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepare");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
301}
302
303static void
304android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
305{
306 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
307 if (mp == NULL ) {
308 jniThrowException(env, "java/lang/IllegalStateException", NULL);
309 return;
310 }
Glenn Kastencc562a32011-02-08 17:26:17 -0800311 setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepareAsync");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
313}
314
315static void
316android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
317{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800318 LOGV("start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
320 if (mp == NULL ) {
321 jniThrowException(env, "java/lang/IllegalStateException", NULL);
322 return;
323 }
324 process_media_player_call( env, thiz, mp->start(), NULL, NULL );
325}
326
327static void
328android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
329{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800330 LOGV("stop");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
332 if (mp == NULL ) {
333 jniThrowException(env, "java/lang/IllegalStateException", NULL);
334 return;
335 }
Nicolas Catania32f82772009-06-11 16:33:49 -0700336 process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337}
338
339static void
340android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
341{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800342 LOGV("pause");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
344 if (mp == NULL ) {
345 jniThrowException(env, "java/lang/IllegalStateException", NULL);
346 return;
347 }
348 process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
349}
350
351static jboolean
352android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
353{
354 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
355 if (mp == NULL ) {
356 jniThrowException(env, "java/lang/IllegalStateException", NULL);
357 return false;
358 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800359 const jboolean is_playing = mp->isPlaying();
360
361 LOGV("isPlaying: %d", is_playing);
362 return is_playing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363}
364
365static void
366android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec)
367{
368 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
369 if (mp == NULL ) {
370 jniThrowException(env, "java/lang/IllegalStateException", NULL);
371 return;
372 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800373 LOGV("seekTo: %d(msec)", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
375}
376
377static int
378android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
379{
380 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
381 if (mp == NULL ) {
382 jniThrowException(env, "java/lang/IllegalStateException", NULL);
383 return 0;
384 }
385 int w;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800386 if (0 != mp->getVideoWidth(&w)) {
387 LOGE("getVideoWidth failed");
388 w = 0;
389 }
390 LOGV("getVideoWidth: %d", w);
391 return w;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392}
393
394static int
395android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
396{
397 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
398 if (mp == NULL ) {
399 jniThrowException(env, "java/lang/IllegalStateException", NULL);
400 return 0;
401 }
402 int h;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800403 if (0 != mp->getVideoHeight(&h)) {
404 LOGE("getVideoHeight failed");
405 h = 0;
406 }
407 LOGV("getVideoHeight: %d", h);
408 return h;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409}
410
411
412static int
413android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
414{
415 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
416 if (mp == NULL ) {
417 jniThrowException(env, "java/lang/IllegalStateException", NULL);
418 return 0;
419 }
420 int msec;
421 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
The Android Open Source Project4df24232009-03-05 14:34:35 -0800422 LOGV("getCurrentPosition: %d (msec)", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 return msec;
424}
425
426static int
427android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
428{
429 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
430 if (mp == NULL ) {
431 jniThrowException(env, "java/lang/IllegalStateException", NULL);
432 return 0;
433 }
434 int msec;
435 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
The Android Open Source Project4df24232009-03-05 14:34:35 -0800436 LOGV("getDuration: %d (msec)", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 return msec;
438}
439
440static void
441android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
442{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800443 LOGV("reset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
445 if (mp == NULL ) {
446 jniThrowException(env, "java/lang/IllegalStateException", NULL);
447 return;
448 }
449 process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
450}
451
452static void
453android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype)
454{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800455 LOGV("setAudioStreamType: %d", streamtype);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
457 if (mp == NULL ) {
458 jniThrowException(env, "java/lang/IllegalStateException", NULL);
459 return;
460 }
461 process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL );
462}
463
464static void
465android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
466{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800467 LOGV("setLooping: %d", looping);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
469 if (mp == NULL ) {
470 jniThrowException(env, "java/lang/IllegalStateException", NULL);
471 return;
472 }
473 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
474}
475
476static jboolean
477android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
478{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800479 LOGV("isLooping");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
481 if (mp == NULL ) {
482 jniThrowException(env, "java/lang/IllegalStateException", NULL);
483 return false;
484 }
485 return mp->isLooping();
486}
487
488static void
489android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume)
490{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800491 LOGV("setVolume: left %f right %f", leftVolume, rightVolume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
493 if (mp == NULL ) {
494 jniThrowException(env, "java/lang/IllegalStateException", NULL);
495 return;
496 }
497 process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL );
498}
499
500// FIXME: deprecated
501static jobject
502android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec)
503{
504 return NULL;
505}
506
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700507
508// Sends the request and reply parcels to the media player via the
509// binder interface.
510static jint
511android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
512 jobject java_request, jobject java_reply)
513{
514 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
515 if (media_player == NULL ) {
516 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700517 return UNKNOWN_ERROR;
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700518 }
519
520
521 Parcel *request = parcelForJavaObject(env, java_request);
522 Parcel *reply = parcelForJavaObject(env, java_reply);
523
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700524 // Don't use process_media_player_call which use the async loop to
525 // report errors, instead returns the status.
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700526 return media_player->invoke(*request, reply);
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700527}
528
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700529// Sends the new filter to the client.
530static jint
531android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
532{
533 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
534 if (media_player == NULL ) {
535 jniThrowException(env, "java/lang/IllegalStateException", NULL);
536 return UNKNOWN_ERROR;
537 }
538
539 Parcel *filter = parcelForJavaObject(env, request);
540
Nicolas Catania5d55c712009-07-09 09:21:33 -0700541 if (filter == NULL ) {
542 jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
543 return UNKNOWN_ERROR;
544 }
545
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700546 return media_player->setMetadataFilter(*filter);
547}
548
Nicolas Catania5d55c712009-07-09 09:21:33 -0700549static jboolean
550android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
551 jboolean apply_filter, jobject reply)
552{
553 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
554 if (media_player == NULL ) {
555 jniThrowException(env, "java/lang/IllegalStateException", NULL);
556 return false;
557 }
558
559 Parcel *metadata = parcelForJavaObject(env, reply);
560
561 if (metadata == NULL ) {
562 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
563 return false;
564 }
565
566 metadata->freeData();
567 // On return metadata is positioned at the beginning of the
568 // metadata. Note however that the parcel actually starts with the
569 // return code so you should not rewind the parcel using
570 // setDataPosition(0).
571 return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
572}
573
Marco Nelissen4935d052009-08-03 11:12:58 -0700574// This function gets some field IDs, which in turn causes class initialization.
575// It is called from a static block in MediaPlayer, which won't run until the
576// first time an instance of this class is used.
577static void
578android_media_MediaPlayer_native_init(JNIEnv *env)
579{
580 jclass clazz;
581
582 clazz = env->FindClass("android/media/MediaPlayer");
583 if (clazz == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700584 return;
585 }
586
587 fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
588 if (fields.context == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700589 return;
590 }
591
592 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
593 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
594 if (fields.post_event == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700595 return;
596 }
597
598 fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
599 if (fields.surface == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700600 return;
601 }
602
603 jclass surface = env->FindClass("android/view/Surface");
604 if (surface == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700605 return;
606 }
607
Mathias Agopian8b138322010-04-12 16:22:15 -0700608 fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I");
Marco Nelissen4935d052009-08-03 11:12:58 -0700609 if (fields.surface_native == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700610 return;
611 }
Glenn Kastencc562a32011-02-08 17:26:17 -0800612
613 fields.surfaceTexture = env->GetFieldID(clazz, "mSurfaceTexture",
614 "Landroid/graphics/SurfaceTexture;");
615 if (fields.surfaceTexture == NULL) {
Glenn Kastencc562a32011-02-08 17:26:17 -0800616 return;
617 }
618
619 jclass surfaceTexture = env->FindClass("android/graphics/SurfaceTexture");
620 if (surfaceTexture == NULL) {
Glenn Kastencc562a32011-02-08 17:26:17 -0800621 return;
622 }
623
624 fields.surfaceTexture_native = env->GetFieldID(surfaceTexture,
625 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
626 if (fields.surfaceTexture_native == NULL) {
Glenn Kastencc562a32011-02-08 17:26:17 -0800627 return;
628 }
629
Marco Nelissen4935d052009-08-03 11:12:58 -0700630}
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632static void
633android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
634{
635 LOGV("native_setup");
636 sp<MediaPlayer> mp = new MediaPlayer();
637 if (mp == NULL) {
638 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
639 return;
640 }
641
642 // create new listener and give it to MediaPlayer
643 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
644 mp->setListener(listener);
645
646 // Stow our new C++ MediaPlayer in an opaque field in the Java object.
647 setMediaPlayer(env, thiz, mp);
648}
649
650static void
651android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
652{
653 LOGV("release");
654 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
655 if (mp != NULL) {
656 // this prevents native callbacks after the object is released
657 mp->setListener(0);
658 mp->disconnect();
659 }
660}
661
662static void
663android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
664{
665 LOGV("native_finalize");
666 android_media_MediaPlayer_release(env, thiz);
667}
668
Eric Laurent619346f2010-06-21 09:27:30 -0700669static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) {
670 LOGV("set_session_id(): %d", sessionId);
671 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
672 if (mp == NULL ) {
673 jniThrowException(env, "java/lang/IllegalStateException", NULL);
674 return;
675 }
676 process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );
677}
678
679static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) {
680 LOGV("get_session_id()");
681 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
682 if (mp == NULL ) {
683 jniThrowException(env, "java/lang/IllegalStateException", NULL);
684 return 0;
685 }
686
687 return mp->getAudioSessionId();
688}
689
Eric Laurent7070b362010-07-16 07:43:46 -0700690static void
691android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
692{
693 LOGV("setAuxEffectSendLevel: level %f", level);
694 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
695 if (mp == NULL ) {
696 jniThrowException(env, "java/lang/IllegalStateException", NULL);
697 return;
698 }
699 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
700}
701
702static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) {
Eric Laurentb3bdf3f2010-10-07 18:23:03 -0700703 LOGV("attachAuxEffect(): %d", effectId);
Eric Laurent7070b362010-07-16 07:43:46 -0700704 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
705 if (mp == NULL ) {
706 jniThrowException(env, "java/lang/IllegalStateException", NULL);
707 return;
708 }
709 process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
710}
711
Gloria Wangd211f412011-02-19 18:37:57 -0800712static jint
713android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply)
714{
715 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
716 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
717 if (service.get() == NULL) {
718 jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
719 return UNKNOWN_ERROR;
720 }
721
722 Parcel *reply = parcelForJavaObject(env, java_reply);
723
724 return service->pullBatteryData(reply);
725}
726
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700727static jboolean
728android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
729{
730 LOGV("setParameter: key %d", key);
731 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
732 if (mp == NULL ) {
733 jniThrowException(env, "java/lang/IllegalStateException", NULL);
734 return false;
735 }
736
737 Parcel *request = parcelForJavaObject(env, java_request);
738 status_t err = mp->setParameter(key, *request);
739 if (err == OK) {
740 return true;
741 } else {
742 return false;
743 }
744}
745
746static void
747android_media_MediaPlayer_getParameter(JNIEnv *env, jobject thiz, jint key, jobject java_reply)
748{
749 LOGV("getParameter: key %d", key);
750 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
751 if (mp == NULL ) {
752 jniThrowException(env, "java/lang/IllegalStateException", NULL);
753 return;
754 }
755
756 Parcel *reply = parcelForJavaObject(env, java_reply);
757 process_media_player_call(env, thiz, mp->getParameter(key, reply), NULL, NULL );
758}
759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760// ----------------------------------------------------------------------------
761
762static JNINativeMethod gMethods[] = {
763 {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},
James Dong17524dc2011-05-04 13:41:58 -0700764
765 {
766 "_setDataSource",
767 "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
768 (void *)android_media_MediaPlayer_setDataSourceAndHeaders
769 },
770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
Glenn Kastencc562a32011-02-08 17:26:17 -0800772 {"_setVideoSurfaceOrSurfaceTexture", "()V", (void *)android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 {"prepare", "()V", (void *)android_media_MediaPlayer_prepare},
774 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
775 {"_start", "()V", (void *)android_media_MediaPlayer_start},
776 {"_stop", "()V", (void *)android_media_MediaPlayer_stop},
777 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
778 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
779 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
780 {"_pause", "()V", (void *)android_media_MediaPlayer_pause},
781 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
782 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
783 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
784 {"_release", "()V", (void *)android_media_MediaPlayer_release},
785 {"_reset", "()V", (void *)android_media_MediaPlayer_reset},
786 {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
787 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
788 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
789 {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
790 {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700791 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700792 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
Nicolas Catania5d55c712009-07-09 09:21:33 -0700793 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
Marco Nelissen4935d052009-08-03 11:12:58 -0700794 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
796 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
Eric Laurent619346f2010-06-21 09:27:30 -0700797 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
798 {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
Eric Laurent7070b362010-07-16 07:43:46 -0700799 {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
800 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
Gloria Wangd211f412011-02-19 18:37:57 -0800801 {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
Gloria Wangd01ec6e2011-04-25 17:28:22 -0700802 {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter},
803 {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804};
805
806static const char* const kClassPathName = "android/media/MediaPlayer";
807
Marco Nelissen4935d052009-08-03 11:12:58 -0700808// This function only registers the native methods
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809static int register_android_media_MediaPlayer(JNIEnv *env)
810{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 return AndroidRuntime::registerNativeMethods(env,
812 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
813}
814
Andreas Huberbfb9fb12009-12-03 11:31:19 -0800815extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816extern int register_android_media_MediaRecorder(JNIEnv *env);
817extern int register_android_media_MediaScanner(JNIEnv *env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818extern int register_android_media_ResampleInputStream(JNIEnv *env);
James Dongc3711942010-01-19 17:45:38 -0800819extern int register_android_media_MediaProfiles(JNIEnv *env);
Andreas Huberbfb9fb12009-12-03 11:31:19 -0800820extern int register_android_media_AmrInputStream(JNIEnv *env);
Mike Lockwood0cd01362010-12-30 11:54:33 -0500821extern int register_android_mtp_MtpDatabase(JNIEnv *env);
Mike Lockwood8182e722010-12-30 15:38:45 -0500822extern int register_android_mtp_MtpDevice(JNIEnv *env);
Mike Lockwood0cd01362010-12-30 11:54:33 -0500823extern int register_android_mtp_MtpServer(JNIEnv *env);
Andreas Huberbfb9fb12009-12-03 11:31:19 -0800824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825jint JNI_OnLoad(JavaVM* vm, void* reserved)
826{
827 JNIEnv* env = NULL;
828 jint result = -1;
829
830 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
831 LOGE("ERROR: GetEnv failed\n");
832 goto bail;
833 }
834 assert(env != NULL);
835
836 if (register_android_media_MediaPlayer(env) < 0) {
837 LOGE("ERROR: MediaPlayer native registration failed\n");
838 goto bail;
839 }
840
841 if (register_android_media_MediaRecorder(env) < 0) {
842 LOGE("ERROR: MediaRecorder native registration failed\n");
843 goto bail;
844 }
845
846 if (register_android_media_MediaScanner(env) < 0) {
847 LOGE("ERROR: MediaScanner native registration failed\n");
848 goto bail;
849 }
850
851 if (register_android_media_MediaMetadataRetriever(env) < 0) {
852 LOGE("ERROR: MediaMetadataRetriever native registration failed\n");
853 goto bail;
854 }
855
856 if (register_android_media_AmrInputStream(env) < 0) {
857 LOGE("ERROR: AmrInputStream native registration failed\n");
858 goto bail;
859 }
860
861 if (register_android_media_ResampleInputStream(env) < 0) {
862 LOGE("ERROR: ResampleInputStream native registration failed\n");
863 goto bail;
864 }
865
James Dongc3711942010-01-19 17:45:38 -0800866 if (register_android_media_MediaProfiles(env) < 0) {
867 LOGE("ERROR: MediaProfiles native registration failed");
868 goto bail;
869 }
870
Mike Lockwood0cd01362010-12-30 11:54:33 -0500871 if (register_android_mtp_MtpDatabase(env) < 0) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400872 LOGE("ERROR: MtpDatabase native registration failed");
873 goto bail;
874 }
875
Mike Lockwood8182e722010-12-30 15:38:45 -0500876 if (register_android_mtp_MtpDevice(env) < 0) {
877 LOGE("ERROR: MtpDevice native registration failed");
878 goto bail;
879 }
880
Mike Lockwood0cd01362010-12-30 11:54:33 -0500881 if (register_android_mtp_MtpServer(env) < 0) {
Mike Lockwood81ea83d2010-06-30 17:49:41 -0400882 LOGE("ERROR: MtpServer native registration failed");
883 goto bail;
884 }
885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 /* success -- return valid version number */
887 result = JNI_VERSION_1_4;
888
889bail:
890 return result;
891}
892
893// KTHXBYE