/* //device/libs/android_runtime/android_media_MediaPlayer.cpp ** ** Copyright 2007, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaPlayer-JNI" #include "utils/Log.h" #include #include #include #include #include #include #include #include #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include "utils/Errors.h" // for status_t #include "utils/KeyedVector.h" #include "utils/String8.h" #include "android_util_Binder.h" #include #include #include #include #include #include // ---------------------------------------------------------------------------- using namespace android; // ---------------------------------------------------------------------------- struct fields_t { jfieldID context; jfieldID surface; jfieldID surfaceTexture; /* actually in android.view.Surface XXX */ jfieldID surface_native; // actually in android.graphics.SurfaceTexture jfieldID surfaceTexture_native; jmethodID post_event; }; static fields_t fields; static Mutex sLock; // ---------------------------------------------------------------------------- // ref-counted object for callbacks class JNIMediaPlayerListener: public MediaPlayerListener { public: JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz); ~JNIMediaPlayerListener(); void notify(int msg, int ext1, int ext2); private: JNIMediaPlayerListener(); jclass mClass; // Reference to MediaPlayer class jobject mObject; // Weak ref to MediaPlayer Java object to call on }; JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz) { // Hold onto the MediaPlayer class for use in calling the static method // that posts events to the application thread. jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { LOGE("Can't find android/media/MediaPlayer"); jniThrowException(env, "java/lang/Exception", NULL); return; } mClass = (jclass)env->NewGlobalRef(clazz); // We use a weak reference so the MediaPlayer object can be garbage collected. // The reference is only used as a proxy for callbacks. mObject = env->NewGlobalRef(weak_thiz); } JNIMediaPlayerListener::~JNIMediaPlayerListener() { // remove global references JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteGlobalRef(mObject); env->DeleteGlobalRef(mClass); } void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2) { JNIEnv *env = AndroidRuntime::getJNIEnv(); env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0); } // ---------------------------------------------------------------------------- static Surface* get_surface(JNIEnv* env, jobject clazz) { return (Surface*)env->GetIntField(clazz, fields.surface_native); } sp getSurfaceTexture(JNIEnv* env, jobject clazz) { sp surfaceTexture( (ISurfaceTexture*)env->GetIntField(clazz, fields.surfaceTexture_native)); return surfaceTexture; } static sp getMediaPlayer(JNIEnv* env, jobject thiz) { Mutex::Autolock l(sLock); MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context); return sp(p); } static sp setMediaPlayer(JNIEnv* env, jobject thiz, const sp& player) { Mutex::Autolock l(sLock); sp old = (MediaPlayer*)env->GetIntField(thiz, fields.context); if (player.get()) { player->incStrong(thiz); } if (old != 0) { old->decStrong(thiz); } env->SetIntField(thiz, fields.context, (int)player.get()); return old; } // If exception is NULL and opStatus is not OK, this method sends an error // event to the client application; otherwise, if exception is not NULL and // opStatus is not OK, this method throws the given exception to the client // application. static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message) { if (exception == NULL) { // Don't throw exception. Instead, send an event. if (opStatus != (status_t) OK) { sp mp = getMediaPlayer(env, thiz); if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0); } } else { // Throw exception! if ( opStatus == (status_t) INVALID_OPERATION ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); } else if ( opStatus != (status_t) OK ) { if (strlen(message) > 230) { // if the message is too long, don't bother displaying the status code jniThrowException( env, exception, message); } else { char msg[256]; // append the status code to the message sprintf(msg, "%s: status=0x%X", message, opStatus); jniThrowException( env, exception, msg); } } } } static void android_media_MediaPlayer_setDataSourceAndHeaders( JNIEnv *env, jobject thiz, jstring path, jobject headers) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } if (path == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } const char *pathStr = env->GetStringUTFChars(path, NULL); if (pathStr == NULL) { // Out of memory jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; } // headers is a Map. // We build a similar KeyedVector out of it. KeyedVector headersVector; if (headers) { // Get the Map's entry Set. jclass mapClass = env->FindClass("java/util/Map"); jmethodID entrySet = env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;"); jobject set = env->CallObjectMethod(headers, entrySet); // Obtain an iterator over the Set jclass setClass = env->FindClass("java/util/Set"); jmethodID iterator = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;"); jobject iter = env->CallObjectMethod(set, iterator); // Get the Iterator method IDs jclass iteratorClass = env->FindClass("java/util/Iterator"); jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); jmethodID next = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); // Get the Entry class method IDs jclass entryClass = env->FindClass("java/util/Map$Entry"); jmethodID getKey = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;"); jmethodID getValue = env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;"); // Iterate over the entry Set while (env->CallBooleanMethod(iter, hasNext)) { jobject entry = env->CallObjectMethod(iter, next); jstring key = (jstring) env->CallObjectMethod(entry, getKey); jstring value = (jstring) env->CallObjectMethod(entry, getValue); const char* keyStr = env->GetStringUTFChars(key, NULL); if (!keyStr) { // Out of memory jniThrowException( env, "java/lang/RuntimeException", "Out of memory"); return; } const char* valueStr = env->GetStringUTFChars(value, NULL); if (!valueStr) { // Out of memory jniThrowException( env, "java/lang/RuntimeException", "Out of memory"); return; } headersVector.add(String8(keyStr), String8(valueStr)); env->DeleteLocalRef(entry); env->ReleaseStringUTFChars(key, keyStr); env->DeleteLocalRef(key); env->ReleaseStringUTFChars(value, valueStr); env->DeleteLocalRef(value); } env->DeleteLocalRef(entryClass); env->DeleteLocalRef(iteratorClass); env->DeleteLocalRef(iter); env->DeleteLocalRef(setClass); env->DeleteLocalRef(set); env->DeleteLocalRef(mapClass); } LOGV("setDataSource: path %s", pathStr); status_t opStatus = mp->setDataSource( String8(pathStr), headers ? &headersVector : NULL); // Make sure that local ref is released before a potential exception env->ReleaseStringUTFChars(path, pathStr); process_media_player_call( env, thiz, opStatus, "java/io/IOException", "setDataSource failed." ); } static void android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path) { android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, 0); } static void android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } if (fileDescriptor == NULL) { jniThrowException(env, "java/lang/IllegalArgumentException", NULL); return; } int fd = getParcelFileDescriptorFD(env, fileDescriptor); LOGV("setDataSourceFD: fd %d", fd); process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." ); } static void setVideoSurfaceOrSurfaceTexture( const sp& mp, JNIEnv *env, jobject thiz, const char *prefix) { // The Java MediaPlayer class makes sure that at most one of mSurface and // mSurfaceTexture is non-null. But just in case, we give priority to // mSurface over mSurfaceTexture. jobject surface = env->GetObjectField(thiz, fields.surface); if (surface != NULL) { sp native_surface(get_surface(env, surface)); LOGV("%s: surface=%p (id=%d)", prefix, native_surface.get(), native_surface->getIdentity()); mp->setVideoSurface(native_surface); } else { jobject surfaceTexture = env->GetObjectField(thiz, fields.surfaceTexture); if (surfaceTexture != NULL) { sp native_surfaceTexture( getSurfaceTexture(env, surfaceTexture)); LOGV("%s: texture=%p", prefix, native_surfaceTexture.get()); mp->setVideoSurfaceTexture(native_surfaceTexture); } } } static void android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture(JNIEnv *env, jobject thiz) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "_setVideoSurfaceOrSurfaceTexture"); } static void android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepare"); process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." ); } static void android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } setVideoSurfaceOrSurfaceTexture(mp, env, thiz, "prepareAsync"); process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." ); } static void android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) { LOGV("start"); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->start(), NULL, NULL ); } static void android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz) { LOGV("stop"); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->stop(), NULL, NULL ); } static void android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz) { LOGV("pause"); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->pause(), NULL, NULL ); } static jboolean android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return false; } const jboolean is_playing = mp->isPlaying(); LOGV("isPlaying: %d", is_playing); return is_playing; } static void android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } LOGV("seekTo: %d(msec)", msec); process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL ); } static int android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return 0; } int w; if (0 != mp->getVideoWidth(&w)) { LOGE("getVideoWidth failed"); w = 0; } LOGV("getVideoWidth: %d", w); return w; } static int android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return 0; } int h; if (0 != mp->getVideoHeight(&h)) { LOGE("getVideoHeight failed"); h = 0; } LOGV("getVideoHeight: %d", h); return h; } static int android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return 0; } int msec; process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL ); LOGV("getCurrentPosition: %d (msec)", msec); return msec; } static int android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz) { sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return 0; } int msec; process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL ); LOGV("getDuration: %d (msec)", msec); return msec; } static void android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz) { LOGV("reset"); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); } static void android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype) { LOGV("setAudioStreamType: %d", streamtype); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL ); } static void android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping) { LOGV("setLooping: %d", looping); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL ); } static jboolean android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz) { LOGV("isLooping"); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return false; } return mp->isLooping(); } static void android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume) { LOGV("setVolume: left %f right %f", leftVolume, rightVolume); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL ); } // FIXME: deprecated static jobject android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) { return NULL; } // Sends the request and reply parcels to the media player via the // binder interface. static jint android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz, jobject java_request, jobject java_reply) { sp media_player = getMediaPlayer(env, thiz); if (media_player == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return UNKNOWN_ERROR; } Parcel *request = parcelForJavaObject(env, java_request); Parcel *reply = parcelForJavaObject(env, java_reply); // Don't use process_media_player_call which use the async loop to // report errors, instead returns the status. return media_player->invoke(*request, reply); } // Sends the new filter to the client. static jint android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request) { sp media_player = getMediaPlayer(env, thiz); if (media_player == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return UNKNOWN_ERROR; } Parcel *filter = parcelForJavaObject(env, request); if (filter == NULL ) { jniThrowException(env, "java/lang/RuntimeException", "Filter is null"); return UNKNOWN_ERROR; } return media_player->setMetadataFilter(*filter); } static jboolean android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only, jboolean apply_filter, jobject reply) { sp media_player = getMediaPlayer(env, thiz); if (media_player == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return false; } Parcel *metadata = parcelForJavaObject(env, reply); if (metadata == NULL ) { jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null"); return false; } metadata->freeData(); // On return metadata is positioned at the beginning of the // metadata. Note however that the parcel actually starts with the // return code so you should not rewind the parcel using // setDataPosition(0). return media_player->getMetadata(update_only, apply_filter, metadata) == OK; } // This function gets some field IDs, which in turn causes class initialization. // It is called from a static block in MediaPlayer, which won't run until the // first time an instance of this class is used. static void android_media_MediaPlayer_native_init(JNIEnv *env) { jclass clazz; clazz = env->FindClass("android/media/MediaPlayer"); if (clazz == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaPlayer"); return; } fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); if (fields.context == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mNativeContext"); return; } fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V"); if (fields.post_event == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.postEventFromNative"); return; } fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;"); if (fields.surface == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mSurface"); return; } jclass surface = env->FindClass("android/view/Surface"); if (surface == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface"); return; } fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I"); if (fields.surface_native == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface." ANDROID_VIEW_SURFACE_JNI_ID); return; } fields.surfaceTexture = env->GetFieldID(clazz, "mSurfaceTexture", "Landroid/graphics/SurfaceTexture;"); if (fields.surfaceTexture == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaPlayer.mSurfaceTexture"); return; } jclass surfaceTexture = env->FindClass("android/graphics/SurfaceTexture"); if (surfaceTexture == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find android/graphics/SurfaceTexture"); return; } fields.surfaceTexture_native = env->GetFieldID(surfaceTexture, ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "I"); if (fields.surfaceTexture_native == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Can't find SurfaceTexture." ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID); return; } } static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { LOGV("native_setup"); sp mp = new MediaPlayer(); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; } // create new listener and give it to MediaPlayer sp listener = new JNIMediaPlayerListener(env, thiz, weak_this); mp->setListener(listener); // Stow our new C++ MediaPlayer in an opaque field in the Java object. setMediaPlayer(env, thiz, mp); } static void android_media_MediaPlayer_release(JNIEnv *env, jobject thiz) { LOGV("release"); sp mp = setMediaPlayer(env, thiz, 0); if (mp != NULL) { // this prevents native callbacks after the object is released mp->setListener(0); mp->disconnect(); } } static void android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz) { LOGV("native_finalize"); android_media_MediaPlayer_release(env, thiz); } static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) { LOGV("set_session_id(): %d", sessionId); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL ); } static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) { LOGV("get_session_id()"); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return 0; } return mp->getAudioSessionId(); } static void android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level) { LOGV("setAuxEffectSendLevel: level %f", level); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL ); } static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) { LOGV("attachAuxEffect(): %d", effectId); sp mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL ); } static jint android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply) { sp binder = defaultServiceManager()->getService(String16("media.player")); sp service = interface_cast(binder); if (service.get() == NULL) { jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService"); return UNKNOWN_ERROR; } Parcel *reply = parcelForJavaObject(env, java_reply); return service->pullBatteryData(reply); } // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource}, {"setDataSource", "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders}, {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, {"_setVideoSurfaceOrSurfaceTexture", "()V", (void *)android_media_MediaPlayer_setVideoSurfaceOrSurfaceTexture}, {"prepare", "()V", (void *)android_media_MediaPlayer_prepare}, {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, {"_start", "()V", (void *)android_media_MediaPlayer_start}, {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, {"_release", "()V", (void *)android_media_MediaPlayer_release}, {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, {"setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel}, {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect}, {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, }; static const char* const kClassPathName = "android/media/MediaPlayer"; // This function only registers the native methods static int register_android_media_MediaPlayer(JNIEnv *env) { return AndroidRuntime::registerNativeMethods(env, "android/media/MediaPlayer", gMethods, NELEM(gMethods)); } extern int register_android_media_MediaMetadataRetriever(JNIEnv *env); extern int register_android_media_MediaRecorder(JNIEnv *env); extern int register_android_media_MediaScanner(JNIEnv *env); extern int register_android_media_ResampleInputStream(JNIEnv *env); extern int register_android_media_MediaProfiles(JNIEnv *env); extern int register_android_media_AmrInputStream(JNIEnv *env); extern int register_android_mtp_MtpDatabase(JNIEnv *env); extern int register_android_mtp_MtpDevice(JNIEnv *env); extern int register_android_mtp_MtpServer(JNIEnv *env); jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed\n"); goto bail; } assert(env != NULL); if (register_android_media_MediaPlayer(env) < 0) { LOGE("ERROR: MediaPlayer native registration failed\n"); goto bail; } if (register_android_media_MediaRecorder(env) < 0) { LOGE("ERROR: MediaRecorder native registration failed\n"); goto bail; } if (register_android_media_MediaScanner(env) < 0) { LOGE("ERROR: MediaScanner native registration failed\n"); goto bail; } if (register_android_media_MediaMetadataRetriever(env) < 0) { LOGE("ERROR: MediaMetadataRetriever native registration failed\n"); goto bail; } if (register_android_media_AmrInputStream(env) < 0) { LOGE("ERROR: AmrInputStream native registration failed\n"); goto bail; } if (register_android_media_ResampleInputStream(env) < 0) { LOGE("ERROR: ResampleInputStream native registration failed\n"); goto bail; } if (register_android_media_MediaProfiles(env) < 0) { LOGE("ERROR: MediaProfiles native registration failed"); goto bail; } if (register_android_mtp_MtpDatabase(env) < 0) { LOGE("ERROR: MtpDatabase native registration failed"); goto bail; } if (register_android_mtp_MtpDevice(env) < 0) { LOGE("ERROR: MtpDevice native registration failed"); goto bail; } if (register_android_mtp_MtpServer(env) < 0) { LOGE("ERROR: MtpServer native registration failed"); goto bail; } /* success -- return valid version number */ result = JNI_VERSION_1_4; bail: return result; } // KTHXBYE