2 * Copyright (C) 2012, Collabora Ltd.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 * Copyright (C) 2013, Fluendo S.A.
5 * Author: Andoni Morales <amorales@fluendo.com>
6 * Copyright (C) 2014, Sebastian Dröge <sebastian@centricular.com>
7 * Copyright (C) 2014, Collabora Ltd.
8 * Author: Matthieu Bouron <matthieu.bouron@collabora.com>
9 * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation
14 * version 2.1 of the License.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
35 #include "gstjniutils.h"
37 static GModule *java_module;
38 static jint (*get_created_java_vms) (JavaVM ** vmBuf, jsize bufLen,
40 static jint (*create_java_vm) (JavaVM ** p_vm, JNIEnv ** p_env, void *vm_args);
41 static JavaVM *java_vm;
42 static gboolean started_java_vm = FALSE;
43 static pthread_key_t current_jni_env;
44 static jobject (*get_class_loader) (void);
47 gst_amc_jni_get_class (JNIEnv * env, GError ** err, const gchar * name)
49 jclass tmp, ret = NULL;
51 GST_DEBUG ("Retrieving Java class %s", name);
53 tmp = (*env)->FindClass (env, name);
54 if ((*env)->ExceptionCheck (env) || !tmp) {
55 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
56 GST_LIBRARY_ERROR_FAILED, "Failed to find class %s", name);
60 ret = (*env)->NewGlobalRef (env, tmp);
62 GST_ERROR ("Failed to get %s class global reference", name);
67 (*env)->DeleteLocalRef (env, tmp);
74 gst_amc_jni_get_method_id (JNIEnv * env, GError ** err, jclass klass,
75 const gchar * name, const gchar * signature)
79 ret = (*env)->GetMethodID (env, klass, name, signature);
80 if ((*env)->ExceptionCheck (env) || !ret) {
81 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
82 GST_LIBRARY_ERROR_FAILED, "Failed to get method ID %s (%s)", name,
89 gst_amc_jni_get_static_method_id (JNIEnv * env, GError ** err, jclass klass,
90 const gchar * name, const gchar * signature)
94 ret = (*env)->GetStaticMethodID (env, klass, name, signature);
95 if ((*env)->ExceptionCheck (env) || !ret) {
96 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
97 GST_LIBRARY_ERROR_FAILED, "Failed to get static method ID %s (%s)",
104 gst_amc_jni_get_field_id (JNIEnv * env, GError ** err, jclass klass,
105 const gchar * name, const gchar * type)
109 ret = (*env)->GetFieldID (env, klass, name, type);
110 if ((*env)->ExceptionCheck (env) || !ret) {
111 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
112 GST_LIBRARY_ERROR_FAILED, "Failed to get field ID %s (%s)", name, type);
118 gst_amc_jni_get_static_field_id (JNIEnv * env, GError ** err, jclass klass,
119 const gchar * name, const gchar * type)
123 ret = (*env)->GetStaticFieldID (env, klass, name, type);
124 if ((*env)->ExceptionCheck (env) || !ret) {
125 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
126 GST_LIBRARY_ERROR_FAILED, "Failed to get static field ID %s (%s)", name,
133 gst_amc_jni_new_object (JNIEnv * env, GError ** err, gboolean global,
134 jclass klass, jmethodID constructor, ...)
139 va_start (args, constructor);
140 tmp = (*env)->NewObjectV (env, klass, constructor, args);
143 if ((*env)->ExceptionCheck (env) || !tmp) {
144 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
145 GST_LIBRARY_ERROR_FAILED, "Failed to create object");
150 return gst_amc_jni_object_make_global (env, tmp);
156 gst_amc_jni_new_object_from_static (JNIEnv * env, GError ** err,
157 gboolean global, jclass klass, jmethodID method, ...)
162 va_start (args, method);
163 tmp = (*env)->CallStaticObjectMethodV (env, klass, method, args);
166 if ((*env)->ExceptionCheck (env) || !tmp) {
167 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
168 GST_LIBRARY_ERROR_FAILED, "Failed to create object");
173 return gst_amc_jni_object_make_global (env, tmp);
179 gst_amc_jni_object_make_global (JNIEnv * env, jobject object)
183 ret = (*env)->NewGlobalRef (env, object);
185 GST_ERROR ("Failed to create global reference");
187 gst_amc_jni_object_local_unref (env, object);
193 gst_amc_jni_object_ref (JNIEnv * env, jobject object)
197 ret = (*env)->NewGlobalRef (env, object);
199 GST_ERROR ("Failed to create global reference");
205 gst_amc_jni_object_unref (JNIEnv * env, jobject object)
207 g_return_if_fail (object != NULL);
209 (*env)->DeleteGlobalRef (env, object);
213 gst_amc_jni_object_local_unref (JNIEnv * env, jobject object)
215 g_return_if_fail (object != NULL);
217 (*env)->DeleteLocalRef (env, object);
221 gst_amc_jni_string_from_gchar (JNIEnv * env, GError ** err,
222 gboolean global, const gchar * string)
226 tmp = (*env)->NewStringUTF (env, string);
227 if ((*env)->ExceptionCheck (env)) {
228 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
229 GST_LIBRARY_ERROR_FAILED, "Failed to call Java method");
234 return gst_amc_jni_object_make_global (env, tmp);
240 gst_amc_jni_string_to_gchar (JNIEnv * env, jstring string, gboolean release)
242 const gchar *s = NULL;
245 s = (*env)->GetStringUTFChars (env, string, NULL);
247 GST_ERROR ("Failed to convert string to UTF8");
252 (*env)->ReleaseStringUTFChars (env, string, s);
256 (*env)->DeleteLocalRef (env, string);
261 /* getExceptionSummary() and getStackTrace() taken from Android's
262 * platform/libnativehelper/JNIHelp.cpp
263 * Modified to work with normal C strings and without C++.
265 * Copyright (C) 2006 The Android Open Source Project
267 * Licensed under the Apache License, Version 2.0 (the "License");
268 * you may not use this file except in compliance with the License.
269 * You may obtain a copy of the License at
271 * http://www.apache.org/licenses/LICENSE-2.0
273 * Unless required by applicable law or agreed to in writing, software
274 * distributed under the License is distributed on an "AS IS" BASIS,
275 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
276 * See the License for the specific language governing permissions and
277 * limitations under the License.
281 * Returns a human-readable summary of an exception object. The buffer will
282 * be populated with the "binary" class name and, if present, the
286 getExceptionSummary (JNIEnv * env, jthrowable exception)
288 GString *gs = g_string_new ("");
289 jclass exceptionClass = NULL, classClass = NULL;
290 jmethodID classGetNameMethod, getMessage;
291 jstring classNameStr = NULL, messageStr = NULL;
292 const char *classNameChars, *messageChars;
294 /* get the name of the exception's class */
295 exceptionClass = (*env)->GetObjectClass (env, exception);
296 classClass = (*env)->GetObjectClass (env, exceptionClass);
298 (*env)->GetMethodID (env, classClass, "getName", "()Ljava/lang/String;");
301 (jstring) (*env)->CallObjectMethod (env, exceptionClass,
304 if (classNameStr == NULL) {
305 if ((*env)->ExceptionCheck (env))
306 (*env)->ExceptionClear (env);
307 g_string_append (gs, "<error getting class name>");
311 classNameChars = (*env)->GetStringUTFChars (env, classNameStr, NULL);
312 if (classNameChars == NULL) {
313 if ((*env)->ExceptionCheck (env))
314 (*env)->ExceptionClear (env);
315 g_string_append (gs, "<error getting class name UTF-8>");
319 g_string_append (gs, classNameChars);
321 (*env)->ReleaseStringUTFChars (env, classNameStr, classNameChars);
323 /* if the exception has a detail message, get that */
325 (*env)->GetMethodID (env, exceptionClass, "getMessage",
326 "()Ljava/lang/String;");
327 messageStr = (jstring) (*env)->CallObjectMethod (env, exception, getMessage);
328 if (messageStr == NULL) {
329 if ((*env)->ExceptionCheck (env))
330 (*env)->ExceptionClear (env);
333 g_string_append (gs, ": ");
335 messageChars = (*env)->GetStringUTFChars (env, messageStr, NULL);
336 if (messageChars != NULL) {
337 g_string_append (gs, messageChars);
338 (*env)->ReleaseStringUTFChars (env, messageStr, messageChars);
340 if ((*env)->ExceptionCheck (env))
341 (*env)->ExceptionClear (env);
342 g_string_append (gs, "<error getting message>");
347 (*env)->DeleteLocalRef (env, exceptionClass);
349 (*env)->DeleteLocalRef (env, classClass);
351 (*env)->DeleteLocalRef (env, classNameStr);
353 (*env)->DeleteLocalRef (env, messageStr);
355 return g_string_free (gs, FALSE);
359 * Returns an exception (with stack trace) as a string.
362 getStackTrace (JNIEnv * env, jthrowable exception)
364 GString *gs = g_string_new ("");
365 jclass stringWriterClass = NULL, printWriterClass = NULL;
366 jclass exceptionClass = NULL;
367 jmethodID stringWriterCtor, stringWriterToStringMethod;
368 jmethodID printWriterCtor, printStackTraceMethod;
369 jobject stringWriter = NULL, printWriter = NULL;
370 jstring messageStr = NULL;
371 const char *utfChars;
373 stringWriterClass = (*env)->FindClass (env, "java/io/StringWriter");
375 if (stringWriterClass == NULL) {
376 g_string_append (gs, "<error getting java.io.StringWriter class>");
381 (*env)->GetMethodID (env, stringWriterClass, "<init>", "()V");
382 stringWriterToStringMethod =
383 (*env)->GetMethodID (env, stringWriterClass, "toString",
384 "()Ljava/lang/String;");
386 printWriterClass = (*env)->FindClass (env, "java/io/PrintWriter");
387 if (printWriterClass == NULL) {
388 g_string_append (gs, "<error getting java.io.PrintWriter class>");
393 (*env)->GetMethodID (env, printWriterClass, "<init>",
394 "(Ljava/io/Writer;)V");
395 stringWriter = (*env)->NewObject (env, stringWriterClass, stringWriterCtor);
396 if (stringWriter == NULL) {
397 if ((*env)->ExceptionCheck (env))
398 (*env)->ExceptionClear (env);
399 g_string_append (gs, "<error creating new StringWriter instance>");
404 (*env)->NewObject (env, printWriterClass, printWriterCtor, stringWriter);
405 if (printWriter == NULL) {
406 if ((*env)->ExceptionCheck (env))
407 (*env)->ExceptionClear (env);
408 g_string_append (gs, "<error creating new PrintWriter instance>");
412 exceptionClass = (*env)->GetObjectClass (env, exception);
413 printStackTraceMethod =
414 (*env)->GetMethodID (env, exceptionClass, "printStackTrace",
415 "(Ljava/io/PrintWriter;)V");
416 (*env)->CallVoidMethod (env, exception, printStackTraceMethod, printWriter);
417 if ((*env)->ExceptionCheck (env)) {
418 (*env)->ExceptionClear (env);
419 g_string_append (gs, "<exception while printing stack trace>");
423 messageStr = (jstring) (*env)->CallObjectMethod (env, stringWriter,
424 stringWriterToStringMethod);
425 if (messageStr == NULL) {
426 if ((*env)->ExceptionCheck (env))
427 (*env)->ExceptionClear (env);
428 g_string_append (gs, "<failed to call StringWriter.toString()>");
432 utfChars = (*env)->GetStringUTFChars (env, messageStr, NULL);
433 if (utfChars == NULL) {
434 if ((*env)->ExceptionCheck (env))
435 (*env)->ExceptionClear (env);
436 g_string_append (gs, "<failed to get UTF chars for message>");
440 g_string_append (gs, utfChars);
442 (*env)->ReleaseStringUTFChars (env, messageStr, utfChars);
445 if (stringWriterClass)
446 (*env)->DeleteLocalRef (env, stringWriterClass);
447 if (printWriterClass)
448 (*env)->DeleteLocalRef (env, printWriterClass);
450 (*env)->DeleteLocalRef (env, exceptionClass);
452 (*env)->DeleteLocalRef (env, stringWriter);
454 (*env)->DeleteLocalRef (env, printWriter);
456 (*env)->DeleteLocalRef (env, messageStr);
458 return g_string_free (gs, FALSE);
462 gst_amc_jni_attach_current_thread (void)
465 JavaVMAttachArgs args;
468 GST_DEBUG ("Attaching thread %p", g_thread_self ());
469 args.version = JNI_VERSION_1_6;
473 if ((ret = (*java_vm)->AttachCurrentThread (java_vm, &env, &args)) != JNI_OK) {
474 GST_ERROR ("Failed to attach current thread: %d", ret);
482 gst_amc_jni_detach_current_thread (void *env)
486 GST_DEBUG ("Detaching thread %p", g_thread_self ());
487 if ((ret = (*java_vm)->DetachCurrentThread (java_vm)) != JNI_OK) {
488 GST_DEBUG ("Failed to detach current thread: %d", ret);
493 get_application_java_vm (void)
495 GModule *module = NULL;
496 JavaVM *(*get_java_vm) (void);
499 module = g_module_open (NULL, G_MODULE_BIND_LOCAL);
505 if (g_module_symbol (module, "gst_android_get_java_vm",
506 (gpointer *) & get_java_vm) && get_java_vm) {
510 g_module_close (module);
516 check_nativehelper (void)
519 void **jni_invocation = NULL;
520 gboolean ret = FALSE;
522 module = g_module_open (NULL, G_MODULE_BIND_LOCAL);
526 /* Check if libnativehelper is loaded in the process and if
527 * it has these awful wrappers for JNI_CreateJavaVM and
528 * JNI_GetCreatedJavaVMs that crash the app if you don't
529 * create a JniInvocation instance first. If it isn't we
530 * just fail here and don't initialize anything.
531 * See this code for reference:
532 * https://android.googlesource.com/platform/libnativehelper/+/master/JniInvocation.cpp
534 if (!g_module_symbol (module, "_ZN13JniInvocation15jni_invocation_E",
535 (gpointer *) & jni_invocation)) {
538 ret = (jni_invocation != NULL && *jni_invocation != NULL);
541 g_module_close (module);
547 load_java_module (const gchar * name)
549 java_module = g_module_open (name, G_MODULE_BIND_LOCAL);
553 if (!g_module_symbol (java_module, "JNI_CreateJavaVM",
554 (gpointer *) & create_java_vm)) {
555 GST_ERROR ("Could not find 'JNI_CreateJavaVM' in '%s': %s",
556 GST_STR_NULL (name), g_module_error ());
557 create_java_vm = NULL;
560 if (!g_module_symbol (java_module, "JNI_GetCreatedJavaVMs",
561 (gpointer *) & get_created_java_vms))
568 GST_ERROR ("Failed to load Java module '%s': %s", GST_STR_NULL (name),
574 GST_ERROR ("Failed to locate required JNI symbols in '%s': %s",
575 GST_STR_NULL (name), g_module_error ());
576 g_module_close (java_module);
583 check_application_class_loader (void)
586 GModule *module = NULL;
588 module = g_module_open (NULL, G_MODULE_BIND_LOCAL);
592 if (!g_module_symbol (module, "gst_android_get_application_class_loader",
593 (gpointer *) & get_class_loader)) {
597 g_module_close (module);
603 initialize_classes (void)
605 if (!check_application_class_loader ()) {
606 GST_ERROR ("Could not find application class loader provider");
614 gst_amc_jni_initialize_java_vm (void)
620 GST_DEBUG ("Java VM already provided by the application");
621 return initialize_classes ();
624 java_vm = get_application_java_vm ();
626 GST_DEBUG ("Java VM successfully requested from the application");
627 return initialize_classes ();
630 /* Returns TRUE if we can safely
631 * a) get the current VMs and
632 * b) start a VM if none is started yet
634 * FIXME: On Android >= 4.4 we won't be able to safely start a
635 * VM on our own without using private C++ API!
637 if (!check_nativehelper ()) {
638 GST_ERROR ("Can't safely check for VMs or start a VM");
642 if (!load_java_module (NULL)) {
643 if (!load_java_module ("libdvm"))
648 if ((ret = get_created_java_vms (&java_vm, 1, &n_vms)) != JNI_OK)
649 goto get_created_failed;
652 GST_DEBUG ("Successfully got existing Java VM %p", java_vm);
653 } else if (create_java_vm) {
655 JavaVMInitArgs vm_args;
656 JavaVMOption options[4];
658 GST_DEBUG ("Found no existing Java VM, trying to start one");
660 options[0].optionString = "-verbose:jni";
661 options[1].optionString = "-verbose:gc";
662 options[2].optionString = "-Xcheck:jni";
663 options[3].optionString = "-Xdebug";
665 vm_args.version = JNI_VERSION_1_4;
666 vm_args.options = options;
667 vm_args.nOptions = 4;
668 vm_args.ignoreUnrecognized = JNI_TRUE;
669 if ((ret = create_java_vm (&java_vm, &env, &vm_args)) != JNI_OK)
671 GST_DEBUG ("Successfully created Java VM %p", java_vm);
673 started_java_vm = TRUE;
675 GST_ERROR ("JNI_CreateJavaVM not available");
682 return initialize_classes ();
686 GST_ERROR ("Failed to get already created VMs: %d", ret);
687 g_module_close (java_module);
693 GST_ERROR ("Failed to create a Java VM: %d", ret);
694 g_module_close (java_module);
701 gst_amc_jni_set_error_string (JNIEnv * env, GError ** err, GQuark domain,
702 gint code, const gchar * message)
704 jthrowable exception;
707 if ((*env)->ExceptionCheck (env))
708 (*env)->ExceptionClear (env);
712 if ((*env)->ExceptionCheck (env)) {
713 if ((exception = (*env)->ExceptionOccurred (env))) {
714 gchar *exception_description, *exception_stacktrace;
716 /* Clear exception so that we can call Java methods again */
717 (*env)->ExceptionClear (env);
719 exception_description = getExceptionSummary (env, exception);
720 exception_stacktrace = getStackTrace (env, exception);
721 g_set_error (err, domain, code, "%s: %s\n%s", message,
722 exception_description, exception_stacktrace);
723 g_free (exception_description);
724 g_free (exception_stacktrace);
726 (*env)->DeleteLocalRef (env, exception);
728 (*env)->ExceptionClear (env);
729 g_set_error (err, domain, code, "%s", message);
732 g_set_error (err, domain, code, "%s", message);
737 void gst_amc_jni_set_error (JNIEnv * env, GError ** err, GQuark domain,
738 gint code, const gchar * format, ...)
743 va_start (var_args, format);
744 message = g_strdup_vprintf (format, var_args);
747 gst_amc_jni_set_error_string (env, err, domain, code, message);
753 gst_amc_jni_initialize_internal (gpointer data)
755 pthread_key_create (¤t_jni_env, gst_amc_jni_detach_current_thread);
756 return gst_amc_jni_initialize_java_vm ()? GINT_TO_POINTER (1) : NULL;
759 /* Allow the application to set the Java VM */
761 gst_amc_jni_set_java_vm (JavaVM * vm)
763 GST_DEBUG ("Application provides Java VM %p", vm);
768 gst_amc_jni_initialize (void)
770 GOnce once = G_ONCE_INIT;
772 g_once (&once, gst_amc_jni_initialize_internal, NULL);
773 return once.retval != NULL;
777 gst_amc_jni_get_env (void)
781 if ((env = pthread_getspecific (current_jni_env)) == NULL) {
782 env = gst_amc_jni_attach_current_thread ();
783 pthread_setspecific (current_jni_env, env);
790 gst_amc_jni_is_vm_started (void)
792 return started_java_vm;
796 gst_amc_jni_get_application_class (JNIEnv * env, const gchar * name,
801 jstring name_jstr = NULL;
803 jobject class_loader = NULL;
804 jclass class_loader_cls = NULL;
805 jmethodID load_class_id = 0;
807 GST_LOG ("attempting to retrieve class %s", name);
809 if (!get_class_loader) {
810 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
811 "Could not retreive application class loader function");
815 class_loader = get_class_loader ();
817 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
818 "Could not retreive application class loader");
822 class_loader_cls = (*env)->GetObjectClass (env, class_loader);
823 if (!class_loader_cls) {
824 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
825 "Could not retreive application class loader java class");
830 gst_amc_jni_get_method_id (env, err, class_loader_cls, "loadClass",
831 "(Ljava/lang/String;)Ljava/lang/Class;");
832 if (!load_class_id) {
836 name_jstr = gst_amc_jni_string_from_gchar (env, err, FALSE, name);
841 if (gst_amc_jni_call_object_method (env, err, class_loader,
842 load_class_id, &tmp, name_jstr)) {
843 class = gst_amc_jni_object_make_global (env, tmp);
847 gst_amc_jni_object_local_unref (env, name_jstr);
848 gst_amc_jni_object_local_unref (env, class_loader_cls);
853 #define CALL_STATIC_TYPE_METHOD(_type, _name, _jname) \
854 gboolean gst_amc_jni_call_static_##_name##_method (JNIEnv *env, GError ** err, jclass klass, jmethodID methodID, _type * value, ...) \
856 gboolean ret = TRUE; \
858 va_start(args, value); \
859 *value = (*env)->CallStatic##_jname##MethodV(env, klass, methodID, args); \
860 if ((*env)->ExceptionCheck (env)) { \
861 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, \
862 "Failed to call static Java method"); \
869 CALL_STATIC_TYPE_METHOD (gboolean, boolean, Boolean);
870 CALL_STATIC_TYPE_METHOD (gint8, byte, Byte);
871 CALL_STATIC_TYPE_METHOD (gshort, short, Short);
872 CALL_STATIC_TYPE_METHOD (gint, int, Int);
873 CALL_STATIC_TYPE_METHOD (gchar, char, Char);
874 CALL_STATIC_TYPE_METHOD (gint64, long, Long);
875 CALL_STATIC_TYPE_METHOD (gfloat, float, Float);
876 CALL_STATIC_TYPE_METHOD (gdouble, double, Double);
877 CALL_STATIC_TYPE_METHOD (jobject, object, Object);
880 gst_amc_jni_call_static_void_method (JNIEnv * env, GError ** err, jclass klass,
881 jmethodID methodID, ...)
885 va_start (args, methodID);
887 (*env)->CallStaticVoidMethodV (env, klass, methodID, args);
888 if ((*env)->ExceptionCheck (env)) {
889 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
890 GST_LIBRARY_ERROR_FAILED, "Failed to call static Java method");
897 #define CALL_TYPE_METHOD(_type, _name, _jname) \
898 gboolean gst_amc_jni_call_##_name##_method (JNIEnv *env, GError ** err, jobject obj, jmethodID methodID, _type *value, ...) \
900 gboolean ret = TRUE; \
902 va_start(args, value); \
903 *value = (*env)->Call##_jname##MethodV(env, obj, methodID, args); \
904 if ((*env)->ExceptionCheck (env)) { \
905 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, \
906 "Failed to call Java method"); \
913 CALL_TYPE_METHOD (gboolean, boolean, Boolean);
914 CALL_TYPE_METHOD (gint8, byte, Byte);
915 CALL_TYPE_METHOD (gshort, short, Short);
916 CALL_TYPE_METHOD (gint, int, Int);
917 CALL_TYPE_METHOD (gchar, char, Char);
918 CALL_TYPE_METHOD (gint64, long, Long);
919 CALL_TYPE_METHOD (gfloat, float, Float);
920 CALL_TYPE_METHOD (gdouble, double, Double);
921 CALL_TYPE_METHOD (jobject, object, Object);
924 gst_amc_jni_call_void_method (JNIEnv * env, GError ** err, jobject obj,
925 jmethodID methodID, ...)
929 va_start (args, methodID);
931 (*env)->CallVoidMethodV (env, obj, methodID, args);
932 if ((*env)->ExceptionCheck (env)) {
933 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
934 GST_LIBRARY_ERROR_FAILED, "Failed to call Java method");
941 #define GET_TYPE_FIELD(_type, _name, _jname) \
942 gboolean gst_amc_jni_get_##_name##_field (JNIEnv *env, GError ** err, jobject obj, jfieldID fieldID, _type *value) \
944 gboolean ret = TRUE; \
946 *value = (*env)->Get##_jname##Field(env, obj, fieldID); \
947 if ((*env)->ExceptionCheck (env)) { \
948 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, \
949 "Failed to get Java field"); \
955 GET_TYPE_FIELD (gboolean, boolean, Boolean);
956 GET_TYPE_FIELD (gint8, byte, Byte);
957 GET_TYPE_FIELD (gshort, short, Short);
958 GET_TYPE_FIELD (gint, int, Int);
959 GET_TYPE_FIELD (gchar, char, Char);
960 GET_TYPE_FIELD (gint64, long, Long);
961 GET_TYPE_FIELD (gfloat, float, Float);
962 GET_TYPE_FIELD (gdouble, double, Double);
963 GET_TYPE_FIELD (jobject, object, Object);
965 #define GET_STATIC_TYPE_FIELD(_type, _name, _jname) \
966 gboolean gst_amc_jni_get_static_##_name##_field (JNIEnv *env, GError ** err, jclass klass, jfieldID fieldID, _type *value) \
968 gboolean ret = TRUE; \
970 *value = (*env)->GetStatic##_jname##Field(env, klass, fieldID); \
971 if ((*env)->ExceptionCheck (env)) { \
972 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, \
973 "Failed to get static Java field"); \
979 GET_STATIC_TYPE_FIELD (gboolean, boolean, Boolean);
980 GET_STATIC_TYPE_FIELD (gint8, byte, Byte);
981 GET_STATIC_TYPE_FIELD (gshort, short, Short);
982 GET_STATIC_TYPE_FIELD (gint, int, Int);
983 GET_STATIC_TYPE_FIELD (gchar, char, Char);
984 GET_STATIC_TYPE_FIELD (gint64, long, Long);
985 GET_STATIC_TYPE_FIELD (gfloat, float, Float);
986 GET_STATIC_TYPE_FIELD (gdouble, double, Double);
987 GET_STATIC_TYPE_FIELD (jobject, object, Object);