blob: 6d074e9a6e00adb6c4da6e2457a623e332837e09 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/libs/android_runtime/android_media_MediaPlayer.cpp
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>
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"
Nicolas Catania20cb94e2009-05-12 23:25:55 -070036#include "android_util_Binder.h"
37#include <binder/Parcel.h>
Glenn Kastencc562a32011-02-08 17:26:17 -080038#include <gui/SurfaceTexture.h>
39#include <gui/ISurfaceTexture.h>
Mathias Agopian000479f2010-02-09 17:46:37 -080040#include <surfaceflinger/Surface.h>
Gloria Wangd211f412011-02-19 18:37:57 -080041#include <binder/IPCThreadState.h>
42#include <binder/IServiceManager.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
44// ----------------------------------------------------------------------------
45
46using namespace android;
47
48// ----------------------------------------------------------------------------
49
50struct fields_t {
51 jfieldID context;
52 jfieldID surface;
Glenn Kastencc562a32011-02-08 17:26:17 -080053 jfieldID surfaceTexture;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 /* actually in android.view.Surface XXX */
55 jfieldID surface_native;
Glenn Kastencc562a32011-02-08 17:26:17 -080056 // actually in android.graphics.SurfaceTexture
57 jfieldID surfaceTexture_native;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
59 jmethodID post_event;
60};
61static fields_t fields;
62
63static Mutex sLock;
64
65// ----------------------------------------------------------------------------
66// ref-counted object for callbacks
67class JNIMediaPlayerListener: public MediaPlayerListener
68{
69public:
70 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
71 ~JNIMediaPlayerListener();
72 void notify(int msg, int ext1, int ext2);
73private:
74 JNIMediaPlayerListener();
75 jclass mClass; // Reference to MediaPlayer class
76 jobject mObject; // Weak ref to MediaPlayer Java object to call on
77};
78
79JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
80{
81
82 // Hold onto the MediaPlayer class for use in calling the static method
83 // that posts events to the application thread.
84 jclass clazz = env->GetObjectClass(thiz);
85 if (clazz == NULL) {
86 LOGE("Can't find android/media/MediaPlayer");
87 jniThrowException(env, "java/lang/Exception", NULL);
88 return;
89 }
90 mClass = (jclass)env->NewGlobalRef(clazz);
91
92 // We use a weak reference so the MediaPlayer object can be garbage collected.
93 // The reference is only used as a proxy for callbacks.
94 mObject = env->NewGlobalRef(weak_thiz);
95}
96
97JNIMediaPlayerListener::~JNIMediaPlayerListener()
98{
99 // remove global references
100 JNIEnv *env = AndroidRuntime::getJNIEnv();
101 env->DeleteGlobalRef(mObject);
102 env->DeleteGlobalRef(mClass);
103}
104
105void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2)
106{
107 JNIEnv *env = AndroidRuntime::getJNIEnv();
108 env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0);
109}
110
111// ----------------------------------------------------------------------------
112
Marco Nelissen0fc736f322009-07-10 09:34:59 -0700113static Surface* get_surface(JNIEnv* env, jobject clazz)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114{
Marco Nelissen0fc736f322009-07-10 09:34:59 -0700115 return (Surface*)env->GetIntField(clazz, fields.surface_native);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116}
117
Glenn Kastencc562a32011-02-08 17:26:17 -0800118sp<ISurfaceTexture> getSurfaceTexture(JNIEnv* env, jobject clazz)
119{
120 sp<ISurfaceTexture> surfaceTexture(
121 (ISurfaceTexture*)env->GetIntField(clazz, fields.surfaceTexture_native));
122 return surfaceTexture;
123}
124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
126{
127 Mutex::Autolock l(sLock);
128 MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);
129 return sp<MediaPlayer>(p);
130}
131
132static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
133{
134 Mutex::Autolock l(sLock);
135 sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
136 if (player.get()) {
137 player->incStrong(thiz);
138 }
139 if (old != 0) {
140 old->decStrong(thiz);
141 }
142 env->SetIntField(thiz, fields.context, (int)player.get());
143 return old;
144}
145
Nicolas Catania32f82772009-06-11 16:33:49 -0700146// If exception is NULL and opStatus is not OK, this method sends an error
147// event to the client application; otherwise, if exception is not NULL and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148// opStatus is not OK, this method throws the given exception to the client
149// application.
150static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
151{
152 if (exception == NULL) { // Don't throw exception. Instead, send an event.
153 if (opStatus != (status_t) OK) {
154 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
155 if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
156 }
157 } else { // Throw exception!
158 if ( opStatus == (status_t) INVALID_OPERATION ) {
159 jniThrowException(env, "java/lang/IllegalStateException", NULL);
160 } else if ( opStatus != (status_t) OK ) {
161 if (strlen(message) > 230) {
162 // if the message is too long, don't bother displaying the status code
163 jniThrowException( env, exception, message);
164 } else {
165 char msg[256];
166 // append the status code to the message
167 sprintf(msg, "%s: status=0x%X", message, opStatus);
168 jniThrowException( env, exception, msg);
169 }
170 }
171 }
172}
173
174static void
Andreas Huber25643002010-01-28 11:19:57 -0800175android_media_MediaPlayer_setDataSourceAndHeaders(
176 JNIEnv *env, jobject thiz, jstring path, jobject headers) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
178 if (mp == NULL ) {
179 jniThrowException(env, "java/lang/IllegalStateException", NULL);
180 return;
181 }
182
183 if (path == NULL) {
184 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
185 return;
186 }
187
188 const char *pathStr = env->GetStringUTFChars(path, NULL);
189 if (pathStr == NULL) { // Out of memory
190 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
191 return;
192 }
Andreas Huber25643002010-01-28 11:19:57 -0800193
194 // headers is a Map<String, String>.
195 // We build a similar KeyedVector out of it.
196 KeyedVector<String8, String8> headersVector;
197 if (headers) {
198 // Get the Map's entry Set.
199 jclass mapClass = env->FindClass("java/util/Map");
200
201 jmethodID entrySet =
202 env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
203
204 jobject set = env->CallObjectMethod(headers, entrySet);
205 // Obtain an iterator over the Set
206 jclass setClass = env->FindClass("java/util/Set");
207
208 jmethodID iterator =
209 env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
210
211 jobject iter = env->CallObjectMethod(set, iterator);
212 // Get the Iterator method IDs
213 jclass iteratorClass = env->FindClass("java/util/Iterator");
214 jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
215
216 jmethodID next =
217 env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
218
219 // Get the Entry class method IDs
220 jclass entryClass = env->FindClass("java/util/Map$Entry");
221
222 jmethodID getKey =
223 env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
224
225 jmethodID getValue =
226 env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
227
228 // Iterate over the entry Set
229 while (env->CallBooleanMethod(iter, hasNext)) {
230 jobject entry = env->CallObjectMethod(iter, next);
231 jstring key = (jstring) env->CallObjectMethod(entry, getKey);
232 jstring value = (jstring) env->CallObjectMethod(entry, getValue);
233
234 const char* keyStr = env->GetStringUTFChars(key, NULL);
235 if (!keyStr) { // Out of memory
236 jniThrowException(
237 env, "java/lang/RuntimeException", "Out of memory");
238 return;
239 }
240
241 const char* valueStr = env->GetStringUTFChars(value, NULL);
242 if (!valueStr) { // Out of memory
243 jniThrowException(
244 env, "java/lang/RuntimeException", "Out of memory");
245 return;
246 }
247
248 headersVector.add(String8(keyStr), String8(valueStr));
249
250 env->DeleteLocalRef(entry);
251 env->ReleaseStringUTFChars(key, keyStr);
252 env->DeleteLocalRef(key);
253 env->ReleaseStringUTFChars(value, valueStr);
254 env->DeleteLocalRef(value);
255 }
256
257 env->DeleteLocalRef(entryClass);
258 env->DeleteLocalRef(iteratorClass);
259 env->DeleteLocalRef(iter);
260 env->DeleteLocalRef(setClass);
261 env->DeleteLocalRef(set);
262 env->DeleteLocalRef(mapClass);
263 }
264
The Android Open Source Project4df24232009-03-05 14:34:35 -0800265 LOGV("setDataSource: path %s", pathStr);
Andreas Huber25643002010-01-28 11:19:57 -0800266 status_t opStatus =
267 mp->setDataSource(
268 String8(pathStr),
269 headers ? &headersVector : NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270
271 // Make sure that local ref is released before a potential exception
272 env->ReleaseStringUTFChars(path, pathStr);
Andreas Huber25643002010-01-28 11:19:57 -0800273
274 process_media_player_call(
275 env, thiz, opStatus, "java/io/IOException",
276 "setDataSource failed." );
277}
278
279static void
280android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
281{
282 android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283}
284
285static void
286android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
287{
288 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
289 if (mp == NULL ) {
290 jniThrowException(env, "java/lang/IllegalStateException", NULL);
291 return;
292 }
293
294 if (fileDescriptor == NULL) {
295 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
296 return;
297 }
298 int fd = getParcelFileDescriptorFD(env, fileDescriptor);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800299 LOGV("setDataSourceFD: fd %d", fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
301}
302
Glenn Kastencc562a32011-02-08 17:26:17 -0800303static void setVideoSurfaceOrSurfaceTexture(
304 const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz, const char *prefix)
Dave Sparks8b0b1742009-05-29 09:01:20 -0700305{
Glenn Kastencc562a32011-02-08 17:26:17 -0800306 // The Java MediaPlayer class makes sure that at most one of mSurface and
307 // mSurfaceTexture is non-null. But just in case, we give priority to
308 // mSurface over mSurfaceTexture.
Dave Sparks8b0b1742009-05-29 09:01:20 -0700309 jobject surface = env->GetObjectField(thiz, fields.surface);
310 if (surface != NULL) {
Glenn Kastencc562a32011-02-08 17:26:17 -0800311 sp<Surface> native_surface(get_surface(env, surface));
312 LOGV("%s: surface=%p (id=%d)", prefix,
Eric Laurent619346f2010-06-21 09:27:30 -0700313 native_surface.get(), native_surface->getIdentity());
Dave Sparks8b0b1742009-05-29 09:01:20 -0700314 mp->setVideoSurface(native_surface);
Glenn Kastencc562a32011-02-08 17:26:17 -0800315 } else {
316 jobject surfaceTexture = env->GetObjectField(thiz, fields.surfaceTexture);
317 if (surfaceTexture != NULL) {
318 sp<ISurfaceTexture> native_surfaceTexture(
319 getSurfaceTexture(env, surfaceTexture));
320 LOGV("%s: texture=%p (id=%d)", prefix,
321 native_surfaceTexture.get(), native_surfaceTexture->getIdentity());
322 mp->setVideoSurfaceTexture(native_surfaceTexture);
323 }
Dave Sparks8b0b1742009-05-29 09:01:20 -0700324 }
325}
326
327static void
Glenn Kastencc562a32011-02-08 17:26:17 -0800328android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture(JNIEnv *env, jobject thiz)
Dave Sparks8b0b1742009-05-29 09:01:20 -0700329{
330 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
331 if (mp == NULL ) {
332 jniThrowException(env, "java/lang/IllegalStateException", NULL);
333 return;
334 }
Glenn Kastencc562a32011-02-08 17:26:17 -0800335 setVideoSurfaceOrSurfaceTexture(mp, env, thiz,
336 "_setVideoSurfaceOrSurfaceTexture");
Dave Sparks8b0b1742009-05-29 09:01:20 -0700337}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338
339static void
340android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
341{
342 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
343 if (mp == NULL ) {
344 jniThrowException(env, "java/lang/IllegalStateException", NULL);
345 return;
346 }
Glenn Kastencc562a32011-02-08 17:26:17 -0800347 setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepare");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
349}
350
351static void
352android_media_MediaPlayer_prepareAsync(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;
358 }
Glenn Kastencc562a32011-02-08 17:26:17 -0800359 setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepareAsync");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
361}
362
363static void
364android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
365{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800366 LOGV("start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
368 if (mp == NULL ) {
369 jniThrowException(env, "java/lang/IllegalStateException", NULL);
370 return;
371 }
372 process_media_player_call( env, thiz, mp->start(), NULL, NULL );
373}
374
375static void
376android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
377{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800378 LOGV("stop");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
380 if (mp == NULL ) {
381 jniThrowException(env, "java/lang/IllegalStateException", NULL);
382 return;
383 }
Nicolas Catania32f82772009-06-11 16:33:49 -0700384 process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385}
386
387static void
388android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
389{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800390 LOGV("pause");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
392 if (mp == NULL ) {
393 jniThrowException(env, "java/lang/IllegalStateException", NULL);
394 return;
395 }
396 process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
397}
398
399static jboolean
400android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
401{
402 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
403 if (mp == NULL ) {
404 jniThrowException(env, "java/lang/IllegalStateException", NULL);
405 return false;
406 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800407 const jboolean is_playing = mp->isPlaying();
408
409 LOGV("isPlaying: %d", is_playing);
410 return is_playing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411}
412
413static void
414android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec)
415{
416 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
417 if (mp == NULL ) {
418 jniThrowException(env, "java/lang/IllegalStateException", NULL);
419 return;
420 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800421 LOGV("seekTo: %d(msec)", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
423}
424
425static int
426android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
427{
428 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
429 if (mp == NULL ) {
430 jniThrowException(env, "java/lang/IllegalStateException", NULL);
431 return 0;
432 }
433 int w;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800434 if (0 != mp->getVideoWidth(&w)) {
435 LOGE("getVideoWidth failed");
436 w = 0;
437 }
438 LOGV("getVideoWidth: %d", w);
439 return w;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440}
441
442static int
443android_media_MediaPlayer_getVideoHeight(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 h;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800451 if (0 != mp->getVideoHeight(&h)) {
452 LOGE("getVideoHeight failed");
453 h = 0;
454 }
455 LOGV("getVideoHeight: %d", h);
456 return h;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457}
458
459
460static int
461android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
462{
463 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
464 if (mp == NULL ) {
465 jniThrowException(env, "java/lang/IllegalStateException", NULL);
466 return 0;
467 }
468 int msec;
469 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
The Android Open Source Project4df24232009-03-05 14:34:35 -0800470 LOGV("getCurrentPosition: %d (msec)", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 return msec;
472}
473
474static int
475android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
476{
477 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
478 if (mp == NULL ) {
479 jniThrowException(env, "java/lang/IllegalStateException", NULL);
480 return 0;
481 }
482 int msec;
483 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
The Android Open Source Project4df24232009-03-05 14:34:35 -0800484 LOGV("getDuration: %d (msec)", msec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 return msec;
486}
487
488static void
489android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
490{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800491 LOGV("reset");
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->reset(), NULL, NULL );
498}
499
500static void
501android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype)
502{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800503 LOGV("setAudioStreamType: %d", streamtype);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
505 if (mp == NULL ) {
506 jniThrowException(env, "java/lang/IllegalStateException", NULL);
507 return;
508 }
509 process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL );
510}
511
512static void
513android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
514{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800515 LOGV("setLooping: %d", looping);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
517 if (mp == NULL ) {
518 jniThrowException(env, "java/lang/IllegalStateException", NULL);
519 return;
520 }
521 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
522}
523
524static jboolean
525android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
526{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800527 LOGV("isLooping");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
529 if (mp == NULL ) {
530 jniThrowException(env, "java/lang/IllegalStateException", NULL);
531 return false;
532 }
533 return mp->isLooping();
534}
535
536static void
537android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume)
538{
The Android Open Source Project4df24232009-03-05 14:34:35 -0800539 LOGV("setVolume: left %f right %f", leftVolume, rightVolume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
541 if (mp == NULL ) {
542 jniThrowException(env, "java/lang/IllegalStateException", NULL);
543 return;
544 }
545 process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL );
546}
547
548// FIXME: deprecated
549static jobject
550android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec)
551{
552 return NULL;
553}
554
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700555
556// Sends the request and reply parcels to the media player via the
557// binder interface.
558static jint
559android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
560 jobject java_request, jobject java_reply)
561{
562 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
563 if (media_player == NULL ) {
564 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700565 return UNKNOWN_ERROR;
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700566 }
567
568
569 Parcel *request = parcelForJavaObject(env, java_request);
570 Parcel *reply = parcelForJavaObject(env, java_reply);
571
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700572 // Don't use process_media_player_call which use the async loop to
573 // report errors, instead returns the status.
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700574 return media_player->invoke(*request, reply);
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700575}
576
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700577// Sends the new filter to the client.
578static jint
579android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
580{
581 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
582 if (media_player == NULL ) {
583 jniThrowException(env, "java/lang/IllegalStateException", NULL);
584 return UNKNOWN_ERROR;
585 }
586
587 Parcel *filter = parcelForJavaObject(env, request);
588
Nicolas Catania5d55c712009-07-09 09:21:33 -0700589 if (filter == NULL ) {
590 jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
591 return UNKNOWN_ERROR;
592 }
593
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700594 return media_player->setMetadataFilter(*filter);
595}
596
Nicolas Catania5d55c712009-07-09 09:21:33 -0700597static jboolean
598android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
599 jboolean apply_filter, jobject reply)
600{
601 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
602 if (media_player == NULL ) {
603 jniThrowException(env, "java/lang/IllegalStateException", NULL);
604 return false;
605 }
606
607 Parcel *metadata = parcelForJavaObject(env, reply);
608
609 if (metadata == NULL ) {
610 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
611 return false;
612 }
613
614 metadata->freeData();
615 // On return metadata is positioned at the beginning of the
616 // metadata. Note however that the parcel actually starts with the
617 // return code so you should not rewind the parcel using
618 // setDataPosition(0).
619 return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
620}
621
Marco Nelissen4935d052009-08-03 11:12:58 -0700622// This function gets some field IDs, which in turn causes class initialization.
623// It is called from a static block in MediaPlayer, which won't run until the
624// first time an instance of this class is used.
625static void
626android_media_MediaPlayer_native_init(JNIEnv *env)
627{
628 jclass clazz;
629
630 clazz = env->FindClass("android/media/MediaPlayer");
631 if (clazz == NULL) {
632 jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaPlayer");
633 return;
634 }
635
636 fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
637 if (fields.context == NULL) {
638 jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mNativeContext");
639 return;
640 }
641
642 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
643 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
644 if (fields.post_event == NULL) {
645 jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.postEventFromNative");
646 return;
647 }
648
649 fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
650 if (fields.surface == NULL) {
651 jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mSurface");
652 return;
653 }
654
655 jclass surface = env->FindClass("android/view/Surface");
656 if (surface == NULL) {
657 jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface");
658 return;
659 }
660
Mathias Agopian8b138322010-04-12 16:22:15 -0700661 fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I");
Marco Nelissen4935d052009-08-03 11:12:58 -0700662 if (fields.surface_native == NULL) {
Glenn Kastencc562a32011-02-08 17:26:17 -0800663 jniThrowException(env, "java/lang/RuntimeException",
664 "Can't find Surface." ANDROID_VIEW_SURFACE_JNI_ID);
Marco Nelissen4935d052009-08-03 11:12:58 -0700665 return;
666 }
Glenn Kastencc562a32011-02-08 17:26:17 -0800667
668 fields.surfaceTexture = env->GetFieldID(clazz, "mSurfaceTexture",
669 "Landroid/graphics/SurfaceTexture;");
670 if (fields.surfaceTexture == NULL) {
671 jniThrowException(env, "java/lang/RuntimeException",
672 "Can't find MediaPlayer.mSurfaceTexture");
673 return;
674 }
675
676 jclass surfaceTexture = env->FindClass("android/graphics/SurfaceTexture");
677 if (surfaceTexture == NULL) {
678 jniThrowException(env, "java/lang/RuntimeException",
679 "Can't find android/graphics/SurfaceTexture");
680 return;
681 }
682
683 fields.surfaceTexture_native = env->GetFieldID(surfaceTexture,
684 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I");
685 if (fields.surfaceTexture_native == NULL) {
686 jniThrowException(env, "java/lang/RuntimeException",
687 "Can't find SurfaceTexture." ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
688 return;
689 }
690
Marco Nelissen4935d052009-08-03 11:12:58 -0700691}
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693static void
694android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
695{
696 LOGV("native_setup");
697 sp<MediaPlayer> mp = new MediaPlayer();
698 if (mp == NULL) {
699 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
700 return;
701 }
702
703 // create new listener and give it to MediaPlayer
704 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
705 mp->setListener(listener);
706
707 // Stow our new C++ MediaPlayer in an opaque field in the Java object.
708 setMediaPlayer(env, thiz, mp);
709}
710
711static void
712android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
713{
714 LOGV("release");
715 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
716 if (mp != NULL) {
717 // this prevents native callbacks after the object is released
718 mp->setListener(0);
719 mp->disconnect();
720 }
721}
722
723static void
724android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
725{
726 LOGV("native_finalize");
727 android_media_MediaPlayer_release(env, thiz);
728}
729
Eric Laurent619346f2010-06-21 09:27:30 -0700730static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) {
731 LOGV("set_session_id(): %d", sessionId);
732 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
733 if (mp == NULL ) {
734 jniThrowException(env, "java/lang/IllegalStateException", NULL);
735 return;
736 }
737 process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );
738}
739
740static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) {
741 LOGV("get_session_id()");
742 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
743 if (mp == NULL ) {
744 jniThrowException(env, "java/lang/IllegalStateException", NULL);
745 return 0;
746 }
747
748 return mp->getAudioSessionId();
749}
750
Eric Laurent7070b362010-07-16 07:43:46 -0700751static void
752android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
753{
754 LOGV("setAuxEffectSendLevel: level %f", level);
755 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
756 if (mp == NULL ) {
757 jniThrowException(env, "java/lang/IllegalStateException", NULL);
758 return;
759 }
760 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
761}
762
763static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) {
Eric Laurentb3bdf3f2010-10-07 18:23:03 -0700764 LOGV("attachAuxEffect(): %d", effectId);
Eric Laurent7070b362010-07-16 07:43:46 -0700765 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
766 if (mp == NULL ) {
767 jniThrowException(env, "java/lang/IllegalStateException", NULL);
768 return;
769 }
770 process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
771}
772
Gloria Wangd211f412011-02-19 18:37:57 -0800773static jint
774android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply)
775{
776 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
777 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
778 if (service.get() == NULL) {
779 jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
780 return UNKNOWN_ERROR;
781 }
782
783 Parcel *reply = parcelForJavaObject(env, java_reply);
784
785 return service->pullBatteryData(reply);
786}
787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788// ----------------------------------------------------------------------------
789
790static JNINativeMethod gMethods[] = {
791 {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},
Andreas Huber25643002010-01-28 11:19:57 -0800792 {"setDataSource", "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
Glenn Kastencc562a32011-02-08 17:26:17 -0800794 {"_setVideoSurfaceOrSurfaceTexture", "()V", (void *)android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 {"prepare", "()V", (void *)android_media_MediaPlayer_prepare},
796 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
797 {"_start", "()V", (void *)android_media_MediaPlayer_start},
798 {"_stop", "()V", (void *)android_media_MediaPlayer_stop},
799 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
800 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
801 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
802 {"_pause", "()V", (void *)android_media_MediaPlayer_pause},
803 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
804 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
805 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
806 {"_release", "()V", (void *)android_media_MediaPlayer_release},
807 {"_reset", "()V", (void *)android_media_MediaPlayer_reset},
808 {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
809 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
810 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
811 {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
812 {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700813 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700814 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
Nicolas Catania5d55c712009-07-09 09:21:33 -0700815 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
Marco Nelissen4935d052009-08-03 11:12:58 -0700816 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
818 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
Eric Laurent619346f2010-06-21 09:27:30 -0700819 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
820 {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
Eric Laurent7070b362010-07-16 07:43:46 -0700821 {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
822 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
Gloria Wangd211f412011-02-19 18:37:57 -0800823 {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824};
825
826static const char* const kClassPathName = "android/media/MediaPlayer";
827
Marco Nelissen4935d052009-08-03 11:12:58 -0700828// This function only registers the native methods
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829static int register_android_media_MediaPlayer(JNIEnv *env)
830{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 return AndroidRuntime::registerNativeMethods(env,
832 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
833}
834
Andreas Huberbfb9fb12009-12-03 11:31:19 -0800835extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836extern int register_android_media_MediaRecorder(JNIEnv *env);
837extern int register_android_media_MediaScanner(JNIEnv *env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838extern int register_android_media_ResampleInputStream(JNIEnv *env);
James Dongc3711942010-01-19 17:45:38 -0800839extern int register_android_media_MediaProfiles(JNIEnv *env);
Andreas Huberbfb9fb12009-12-03 11:31:19 -0800840extern int register_android_media_AmrInputStream(JNIEnv *env);
Mike Lockwood0cd01362010-12-30 11:54:33 -0500841extern int register_android_mtp_MtpDatabase(JNIEnv *env);
Mike Lockwood8182e722010-12-30 15:38:45 -0500842extern int register_android_mtp_MtpDevice(JNIEnv *env);
Mike Lockwood0cd01362010-12-30 11:54:33 -0500843extern int register_android_mtp_MtpServer(JNIEnv *env);
Andreas Huberbfb9fb12009-12-03 11:31:19 -0800844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845jint JNI_OnLoad(JavaVM* vm, void* reserved)
846{
847 JNIEnv* env = NULL;
848 jint result = -1;
849
850 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
851 LOGE("ERROR: GetEnv failed\n");
852 goto bail;
853 }
854 assert(env != NULL);
855
856 if (register_android_media_MediaPlayer(env) < 0) {
857 LOGE("ERROR: MediaPlayer native registration failed\n");
858 goto bail;
859 }
860
861 if (register_android_media_MediaRecorder(env) < 0) {
862 LOGE("ERROR: MediaRecorder native registration failed\n");
863 goto bail;
864 }
865
866 if (register_android_media_MediaScanner(env) < 0) {
867 LOGE("ERROR: MediaScanner native registration failed\n");
868 goto bail;
869 }
870
871 if (register_android_media_MediaMetadataRetriever(env) < 0) {
872 LOGE("ERROR: MediaMetadataRetriever native registration failed\n");
873 goto bail;
874 }
875
876 if (register_android_media_AmrInputStream(env) < 0) {
877 LOGE("ERROR: AmrInputStream native registration failed\n");
878 goto bail;
879 }
880
881 if (register_android_media_ResampleInputStream(env) < 0) {
882 LOGE("ERROR: ResampleInputStream native registration failed\n");
883 goto bail;
884 }
885
James Dongc3711942010-01-19 17:45:38 -0800886 if (register_android_media_MediaProfiles(env) < 0) {
887 LOGE("ERROR: MediaProfiles native registration failed");
888 goto bail;
889 }
890
Mike Lockwood0cd01362010-12-30 11:54:33 -0500891 if (register_android_mtp_MtpDatabase(env) < 0) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400892 LOGE("ERROR: MtpDatabase native registration failed");
893 goto bail;
894 }
895
Mike Lockwood8182e722010-12-30 15:38:45 -0500896 if (register_android_mtp_MtpDevice(env) < 0) {
897 LOGE("ERROR: MtpDevice native registration failed");
898 goto bail;
899 }
900
Mike Lockwood0cd01362010-12-30 11:54:33 -0500901 if (register_android_mtp_MtpServer(env) < 0) {
Mike Lockwood81ea83d2010-06-30 17:49:41 -0400902 LOGE("ERROR: MtpServer native registration failed");
903 goto bail;
904 }
905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 /* success -- return valid version number */
907 result = JNI_VERSION_1_4;
908
909bail:
910 return result;
911}
912
913// KTHXBYE