| /* | |
| * Copyright (C) 2016 SurroundIO | |
| * Author: Martin Kelly <martin@surround.io> | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Library General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Library General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Library General Public | |
| * License along with this library; if not, write to the | |
| * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, | |
| * Boston, MA 02110-1301, USA. | |
| * | |
| * The UNION_CAST macro is copyright: | |
| * Copyright (C) 2008-2016 Matt Gallagher ( http://cocoawithlove.com ). | |
| * All rights reserved. | |
| * Permission to use, copy, modify, and/or distribute this software for any purpose | |
| * with or without fee is hereby granted, provided that the above copyright notice | |
| * and this permission notice appear in all copies. | |
| * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | |
| * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | |
| * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | |
| * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| * THIS SOFTWARE. | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| #include "config.h" | |
| #endif | |
| #include <glib.h> | |
| #include <gmodule.h> | |
| #include "gstjniutils.h" | |
| #include "gst-android-hardware-sensor.h" | |
| static jobject (*gst_android_get_application_context) (void) = NULL; | |
| GST_DEBUG_CATEGORY_STATIC (ahs_debug); | |
| #define GST_CAT_DEFAULT ahs_debug | |
| /* | |
| * See: | |
| * http://www.cocoawithlove.com/2008/04/using-pointers-to-recast-in-c-is-bad.html | |
| * for details. | |
| */ | |
| #define UNION_CAST(x, destType) \ | |
| (((union {__typeof__(x) a; destType b;})x).b) | |
| static struct | |
| { | |
| jclass klass; | |
| jstring SENSOR_SERVICE; | |
| jmethodID getSystemService; | |
| } android_content_context = { | |
| 0 | |
| }; | |
| static struct | |
| { | |
| jclass klass; | |
| jfieldID accuracy; | |
| jfieldID values; | |
| } android_hardware_sensor_event = { | |
| 0 | |
| }; | |
| static struct | |
| { | |
| jclass klass; | |
| jmethodID getDefaultSensor;; | |
| jmethodID registerListener; | |
| jmethodID unregisterListener; | |
| } android_hardware_sensor_manager = { | |
| 0 | |
| }; | |
| static struct | |
| { | |
| jclass klass; | |
| jmethodID constructor; | |
| } org_freedesktop_gstreamer_androidmedia_gstahscallback = { | |
| 0 | |
| }; | |
| GHashTable *sensor_sizes = NULL; | |
| static void | |
| gst_ah_sensor_sensor_sizes_init (void) | |
| { | |
| gint i; | |
| static struct | |
| { | |
| gint type; | |
| gsize size; | |
| } types[] = { | |
| { | |
| AHS_SENSOR_TYPE_ACCELEROMETER, sizeof (GstAHSAccelerometerValues)} | |
| , { | |
| AHS_SENSOR_TYPE_AMBIENT_TEMPERATURE, | |
| sizeof (GstAHSAmbientTemperatureValues)} | |
| , { | |
| AHS_SENSOR_TYPE_GAME_ROTATION_VECTOR, | |
| sizeof (GstAHSGameRotationVectorValues)} | |
| , { | |
| AHS_SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR, | |
| sizeof (GstAHSGeomagneticRotationVectorValues)} | |
| , { | |
| AHS_SENSOR_TYPE_GRAVITY, sizeof (GstAHSGravityValues)} | |
| , { | |
| AHS_SENSOR_TYPE_GYROSCOPE, sizeof (GstAHSGyroscopeValues)} | |
| , { | |
| AHS_SENSOR_TYPE_GYROSCOPE_UNCALIBRATED, | |
| sizeof (GstAHSGyroscopeUncalibratedValues)} | |
| , { | |
| AHS_SENSOR_TYPE_HEART_RATE, sizeof (GstAHSHeartRateValues)} | |
| , { | |
| AHS_SENSOR_TYPE_LIGHT, sizeof (GstAHSLightValues)} | |
| , { | |
| AHS_SENSOR_TYPE_LINEAR_ACCELERATION, | |
| sizeof (GstAHSLinearAccelerationValues)} | |
| , { | |
| AHS_SENSOR_TYPE_MAGNETIC_FIELD, sizeof (GstAHSMagneticFieldValues)} | |
| , { | |
| AHS_SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED, | |
| sizeof (GstAHSMagneticFieldUncalibratedValues)} | |
| , { | |
| AHS_SENSOR_TYPE_ORIENTATION, sizeof (GstAHSOrientationValues)} | |
| , { | |
| AHS_SENSOR_TYPE_PRESSURE, sizeof (GstAHSPressureValues)} | |
| , { | |
| AHS_SENSOR_TYPE_PROXIMITY, sizeof (GstAHSProximityValues)} | |
| , { | |
| AHS_SENSOR_TYPE_RELATIVE_HUMIDITY, | |
| sizeof (GstAHSRelativeHumidityValues)} | |
| , { | |
| AHS_SENSOR_TYPE_ROTATION_VECTOR, sizeof (GstAHSRotationVectorValues)} | |
| , { | |
| AHS_SENSOR_TYPE_STEP_COUNTER, sizeof (GstAHSStepCounterValues)} | |
| , { | |
| AHS_SENSOR_TYPE_STEP_DETECTOR, sizeof (GstAHSStepDetectorValues)} | |
| , | |
| }; | |
| g_assert_null (sensor_sizes); | |
| sensor_sizes = g_hash_table_new (g_int_hash, g_int_equal); | |
| for (i = 0; i < G_N_ELEMENTS (types); i++) | |
| g_hash_table_insert (sensor_sizes, &types[i].type, &types[i].size); | |
| } | |
| static void | |
| gst_ah_sensor_sensor_sizes_deinit (void) | |
| { | |
| g_hash_table_unref (sensor_sizes); | |
| sensor_sizes = NULL; | |
| } | |
| gsize | |
| gst_ah_sensor_get_sensor_data_size (gint sensor_type) | |
| { | |
| return *((gsize *) g_hash_table_lookup (sensor_sizes, &sensor_type)); | |
| } | |
| static void | |
| gst_ah_sensor_on_sensor_changed (JNIEnv * env, jclass klass, | |
| jobject sensor_event, jlong callback, jlong user_data) | |
| { | |
| GstAHSensorCallback cb = (GstAHSensorCallback) (gsize) callback; | |
| if (cb) | |
| cb (sensor_event, (gpointer) (gsize) user_data); | |
| } | |
| static void | |
| gst_ah_sensor_on_accuracy_changed (JNIEnv * env, jclass klass, | |
| jobject sensor, jint accuracy, jlong callback, jlong user_data) | |
| { | |
| GstAHSAccuracyCallback cb = (GstAHSAccuracyCallback) (gsize) callback; | |
| if (cb) | |
| cb (sensor, accuracy, (gpointer) (gsize) user_data); | |
| } | |
| static gboolean natives_registered = FALSE; | |
| static JNINativeMethod native_methods[] = { | |
| {(gchar *) "gst_ah_sensor_on_sensor_changed", | |
| (gchar *) "(Landroid/hardware/SensorEvent;JJ)V", | |
| (void *) gst_ah_sensor_on_sensor_changed}, | |
| {(gchar *) "gst_ah_sensor_on_accuracy_changed", | |
| (gchar *) "(Landroid/hardware/Sensor;IJJ)V", | |
| (void *) gst_ah_sensor_on_accuracy_changed} | |
| }; | |
| static gboolean | |
| _init_classes (void) | |
| { | |
| gint32 delay; | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| GError *err = NULL; | |
| jclass klass; | |
| jfieldID fieldID; | |
| GModule *module; | |
| gboolean success; | |
| gint32 type; | |
| /* | |
| * Lookup the Android function to get an Android context. This function will | |
| * be provided when the plugin is built via ndk-build. | |
| */ | |
| module = g_module_open (NULL, G_MODULE_BIND_LOCAL); | |
| if (!module) | |
| goto failed; | |
| success = g_module_symbol (module, "gst_android_get_application_context", | |
| (gpointer *) & gst_android_get_application_context); | |
| if (!success || !gst_android_get_application_context) | |
| goto failed; | |
| g_module_close (module); | |
| /* android.content.Context */ | |
| klass = android_content_context.klass = gst_amc_jni_get_class (env, &err, | |
| "android/content/Context"); | |
| if (!klass) | |
| goto failed; | |
| android_content_context.getSystemService = | |
| gst_amc_jni_get_method_id (env, &err, klass, "getSystemService", | |
| "(Ljava/lang/String;)Ljava/lang/Object;"); | |
| if (!android_content_context.getSystemService) | |
| goto failed; | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_SERVICE", | |
| "Ljava/lang/String;"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_object_field (env, &err, klass, fieldID, | |
| &android_content_context.SENSOR_SERVICE)) | |
| goto failed; | |
| android_content_context.SENSOR_SERVICE = | |
| gst_amc_jni_object_make_global (env, | |
| android_content_context.SENSOR_SERVICE); | |
| if (!android_content_context.SENSOR_SERVICE) | |
| goto failed; | |
| /* android.hardware.SensorEvent */ | |
| klass = android_hardware_sensor_event.klass = | |
| gst_amc_jni_get_class (env, &err, "android/hardware/SensorEvent"); | |
| if (!klass) | |
| goto failed; | |
| android_hardware_sensor_event.accuracy = | |
| gst_amc_jni_get_field_id (env, &err, klass, "accuracy", "I"); | |
| if (!android_hardware_sensor_event.accuracy) | |
| goto failed; | |
| android_hardware_sensor_event.values = | |
| gst_amc_jni_get_field_id (env, &err, klass, "values", "[F"); | |
| if (!android_hardware_sensor_event.values) | |
| goto failed; | |
| /* android.hardware.SensorManager */ | |
| klass = android_hardware_sensor_manager.klass = | |
| gst_amc_jni_get_class (env, &err, "android/hardware/SensorManager"); | |
| if (!klass) | |
| goto failed; | |
| android_hardware_sensor_manager.getDefaultSensor = | |
| gst_amc_jni_get_method_id (env, &err, klass, | |
| "getDefaultSensor", "(I)Landroid/hardware/Sensor;"); | |
| if (!android_hardware_sensor_manager.getDefaultSensor) | |
| goto failed; | |
| android_hardware_sensor_manager.registerListener = | |
| gst_amc_jni_get_method_id (env, &err, klass, | |
| "registerListener", | |
| "(Landroid/hardware/SensorEventListener;Landroid/hardware/Sensor;I)Z"); | |
| if (!android_hardware_sensor_manager.registerListener) | |
| goto failed; | |
| android_hardware_sensor_manager.unregisterListener = | |
| gst_amc_jni_get_method_id (env, &err, klass, | |
| "unregisterListener", "(Landroid/hardware/SensorEventListener;)V"); | |
| if (!android_hardware_sensor_manager.unregisterListener) | |
| goto failed; | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_DELAY_FASTEST", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &delay)) | |
| goto failed; | |
| if (delay != AHS_SENSOR_DELAY_FASTEST) { | |
| GST_ERROR ("SENSOR_DELAY_FASTEST has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_DELAY_GAME", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &delay)) | |
| goto failed; | |
| if (delay != AHS_SENSOR_DELAY_GAME) { | |
| GST_ERROR ("SENSOR_DELAY_GAME has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_DELAY_NORMAL", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &delay)) | |
| goto failed; | |
| if (delay != AHS_SENSOR_DELAY_NORMAL) { | |
| GST_ERROR ("SENSOR_DELAY_NORMAL has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "SENSOR_DELAY_UI", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &delay)) | |
| goto failed; | |
| if (delay != AHS_SENSOR_DELAY_UI) { | |
| GST_ERROR ("SENSOR_DELAY_UI has changed value"); | |
| goto failed; | |
| } | |
| /* android.hardware.Sensor */ | |
| klass = gst_amc_jni_get_class (env, &err, "android/hardware/Sensor"); | |
| if (!klass) | |
| goto failed; | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_ACCELEROMETER", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_ACCELEROMETER) { | |
| GST_ERROR ("TYPE_ACCELEROMETER has changed value"); | |
| goto failed; | |
| } | |
| fieldID = gst_amc_jni_get_static_field_id (env, &err, klass, | |
| "TYPE_AMBIENT_TEMPERATURE", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_AMBIENT_TEMPERATURE) { | |
| GST_ERROR ("TYPE_AMBIENT_TEMPERATURE has changed value"); | |
| goto failed; | |
| } | |
| fieldID = gst_amc_jni_get_static_field_id (env, &err, klass, | |
| "TYPE_GAME_ROTATION_VECTOR", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_GAME_ROTATION_VECTOR) { | |
| GST_ERROR ("TYPE_GAME_ROTATION_VECTOR has changed value"); | |
| goto failed; | |
| } | |
| fieldID = gst_amc_jni_get_static_field_id (env, &err, klass, | |
| "TYPE_GEOMAGNETIC_ROTATION_VECTOR", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR) { | |
| GST_ERROR ("TYPE_GEOMAGNETIC_ROTATION_VECTOR has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_GRAVITY", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_GRAVITY) { | |
| GST_ERROR ("TYPE_GRAVITY has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_GYROSCOPE", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_GYROSCOPE) { | |
| GST_ERROR ("TYPE_GYROSCOPE has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, | |
| "TYPE_GYROSCOPE_UNCALIBRATED", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) { | |
| GST_ERROR ("TYPE_GYROSCOPE_UNCALIBRATED has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_HEART_RATE", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_HEART_RATE) { | |
| GST_ERROR ("TYPE_HEART_RATE has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_LIGHT", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_LIGHT) { | |
| GST_ERROR ("TYPE_LIGHT has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, | |
| "TYPE_LINEAR_ACCELERATION", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_LINEAR_ACCELERATION) { | |
| GST_ERROR ("TYPE_LINEAR_ACCELERATION has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_MAGNETIC_FIELD", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_MAGNETIC_FIELD) { | |
| GST_ERROR ("TYPE_MAGNETIC_FIELD has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, | |
| "TYPE_MAGNETIC_FIELD_UNCALIBRATED", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED) { | |
| GST_ERROR ("TYPE_MAGNETIC_FIELD_UNCALIBRATED has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_ORIENTATION", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_ORIENTATION) { | |
| GST_ERROR ("TYPE_ORIENTATION has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_PRESSURE", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_PRESSURE) { | |
| GST_ERROR ("TYPE_PRESSURE has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_PROXIMITY", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_PROXIMITY) { | |
| GST_ERROR ("TYPE_PROXIMITY has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, | |
| "TYPE_RELATIVE_HUMIDITY", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_RELATIVE_HUMIDITY) { | |
| GST_ERROR ("TYPE_RELATIVE_HUMIDITY has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_ROTATION_VECTOR", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_ROTATION_VECTOR) { | |
| GST_ERROR ("TYPE_ROTATION_VECTOR has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, | |
| "TYPE_SIGNIFICANT_MOTION", "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_SIGNIFICANT_MOTION) { | |
| GST_ERROR ("TYPE_SIGNIFICANT_MOTION has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_STEP_COUNTER", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_STEP_COUNTER) { | |
| GST_ERROR ("TYPE_STEP_COUNTER has changed value"); | |
| goto failed; | |
| } | |
| fieldID = | |
| gst_amc_jni_get_static_field_id (env, &err, klass, "TYPE_STEP_DETECTOR", | |
| "I"); | |
| if (!fieldID) | |
| goto failed; | |
| if (!gst_amc_jni_get_static_int_field (env, &err, klass, fieldID, &type)) | |
| goto failed; | |
| if (type != AHS_SENSOR_TYPE_STEP_DETECTOR) { | |
| GST_ERROR ("TYPE_STEP_DETECTOR has changed value"); | |
| goto failed; | |
| } | |
| /* org.freedesktop.gstreamer.androidmedia.GstAhsCallback */ | |
| if (!org_freedesktop_gstreamer_androidmedia_gstahscallback.klass) { | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.klass = | |
| gst_amc_jni_get_application_class (env, | |
| "org/freedesktop/gstreamer/androidmedia/GstAhsCallback", &err); | |
| } | |
| if (!org_freedesktop_gstreamer_androidmedia_gstahscallback.klass) | |
| goto failed; | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.constructor = | |
| gst_amc_jni_get_method_id (env, &err, | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.klass, "<init>", | |
| "(JJJ)V"); | |
| if (!org_freedesktop_gstreamer_androidmedia_gstahscallback.constructor) | |
| goto failed; | |
| if ((*env)->RegisterNatives (env, | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.klass, | |
| native_methods, G_N_ELEMENTS (native_methods))) { | |
| GST_ERROR ("Failed to register native methods for GstAhsCallback"); | |
| goto failed; | |
| } | |
| natives_registered = TRUE; | |
| return TRUE; | |
| failed: | |
| if (err) { | |
| GST_ERROR ("Failed to initialize Android classes: %s", err->message); | |
| g_clear_error (&err); | |
| } | |
| return FALSE; | |
| } | |
| gboolean | |
| gst_android_hardware_sensor_init (void) | |
| { | |
| GST_DEBUG_CATEGORY_INIT (ahs_debug, "ahs", 0, | |
| "Android Gstreamer Hardware Sensor"); | |
| if (!_init_classes ()) { | |
| gst_android_hardware_sensor_deinit (); | |
| return FALSE; | |
| } | |
| gst_ah_sensor_sensor_sizes_init (); | |
| return TRUE; | |
| } | |
| void | |
| gst_android_hardware_sensor_deinit (void) | |
| { | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| if (android_content_context.SENSOR_SERVICE) { | |
| gst_amc_jni_object_unref (env, android_content_context.SENSOR_SERVICE); | |
| android_content_context.SENSOR_SERVICE = NULL; | |
| } | |
| if (android_content_context.klass) { | |
| gst_amc_jni_object_unref (env, android_content_context.klass); | |
| android_content_context.klass = NULL; | |
| } | |
| if (android_hardware_sensor_event.klass) { | |
| gst_amc_jni_object_unref (env, android_hardware_sensor_event.klass); | |
| android_hardware_sensor_event.klass = NULL; | |
| } | |
| if (android_hardware_sensor_manager.klass) { | |
| gst_amc_jni_object_unref (env, android_hardware_sensor_manager.klass); | |
| android_hardware_sensor_manager.klass = NULL; | |
| } | |
| if (org_freedesktop_gstreamer_androidmedia_gstahscallback.klass) { | |
| if (natives_registered) { | |
| (*env)->UnregisterNatives (env, | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.klass); | |
| natives_registered = FALSE; | |
| } | |
| gst_amc_jni_object_unref (env, | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.klass); | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.klass = NULL; | |
| } | |
| if (sensor_sizes) | |
| gst_ah_sensor_sensor_sizes_deinit (); | |
| } | |
| GstAHSensorManager * | |
| gst_ah_sensor_get_manager (void) | |
| { | |
| jobject context; | |
| GError *err = NULL; | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| GstAHSensorManager *manager; | |
| jobject object; | |
| gboolean success; | |
| context = gst_android_get_application_context (); | |
| success = gst_amc_jni_call_object_method (env, &err, context, | |
| android_content_context.getSystemService, | |
| &object, android_content_context.SENSOR_SERVICE); | |
| if (!success) | |
| return NULL; | |
| object = gst_amc_jni_object_make_global (env, object); | |
| if (!object) | |
| return NULL; | |
| manager = g_slice_new (GstAHSensorManager); | |
| manager->object = object; | |
| return manager; | |
| } | |
| GstAHSensor * | |
| gst_ah_sensor_get_default_sensor (GstAHSensorManager * self, gint32 sensor_type) | |
| { | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| GError *err = NULL; | |
| jobject object; | |
| GstAHSensor *sensor; | |
| if (!gst_amc_jni_call_object_method (env, &err, self->object, | |
| android_hardware_sensor_manager.getDefaultSensor, | |
| &object, sensor_type)) | |
| return NULL; | |
| object = gst_amc_jni_object_make_global (env, object); | |
| if (!object) | |
| return NULL; | |
| sensor = g_slice_new (GstAHSensor); | |
| sensor->object = object; | |
| return sensor; | |
| } | |
| GstAHSensorEventListener * | |
| gst_ah_sensor_create_listener (GstAHSensorCallback sensor_cb, | |
| GstAHSAccuracyCallback accuracy_cb, gpointer user_data) | |
| { | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| GError *err = NULL; | |
| GstAHSensorEventListener *listener; | |
| jobject object; | |
| object = gst_amc_jni_new_object (env, | |
| &err, | |
| TRUE, | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.klass, | |
| org_freedesktop_gstreamer_androidmedia_gstahscallback.constructor, | |
| UNION_CAST (sensor_cb, jlong), | |
| UNION_CAST (accuracy_cb, jlong), UNION_CAST (user_data, jlong)); | |
| if (err) { | |
| GST_ERROR ("Failed to create listener callback class"); | |
| g_clear_error (&err); | |
| return NULL; | |
| } | |
| listener = g_slice_new (GstAHSensorEventListener); | |
| listener->object = object; | |
| return listener; | |
| } | |
| gboolean | |
| gst_ah_sensor_register_listener (GstAHSensorManager * self, | |
| GstAHSensorEventListener * listener, GstAHSensor * sensor, gint32 delay) | |
| { | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| GError *err = NULL; | |
| gboolean success; | |
| gst_amc_jni_call_boolean_method (env, &err, self->object, | |
| android_hardware_sensor_manager.registerListener, &success, | |
| listener->object, sensor->object, (jint) delay); | |
| if (err) { | |
| GST_ERROR | |
| ("Failed to call android.hardware.SensorManager.registerListener: %s", | |
| err->message); | |
| g_clear_error (&err); | |
| return FALSE; | |
| } | |
| listener->registered = TRUE; | |
| return TRUE; | |
| } | |
| void | |
| gst_ah_sensor_unregister_listener (GstAHSensorManager * self, | |
| GstAHSensorEventListener * listener) | |
| { | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| GError *err = NULL; | |
| gst_amc_jni_call_void_method (env, &err, self->object, | |
| android_hardware_sensor_manager.unregisterListener, listener->object); | |
| if (err) { | |
| GST_ERROR | |
| ("Failed to call android.hardware.SensorManager.unregisterListener: %s", | |
| err->message); | |
| g_clear_error (&err); | |
| } | |
| listener->registered = FALSE; | |
| } | |
| gboolean | |
| gst_ah_sensor_populate_event (GstAHSensorEvent * event, jobject event_object, | |
| gint size) | |
| { | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| GError *err = NULL; | |
| jfloatArray object_array; | |
| jfloat *values; | |
| gst_amc_jni_get_int_field (env, &err, | |
| event_object, android_hardware_sensor_event.accuracy, &event->accuracy); | |
| if (err) { | |
| GST_ERROR ("Failed to get sensor accuracy field: %s", err->message); | |
| goto error; | |
| } | |
| gst_amc_jni_get_object_field (env, &err, event_object, | |
| android_hardware_sensor_event.values, &object_array); | |
| if (err) { | |
| GST_ERROR ("Failed to get sensor values field: %s", err->message); | |
| goto error; | |
| } | |
| values = (*env)->GetFloatArrayElements (env, object_array, NULL); | |
| if (!values) { | |
| GST_ERROR ("Failed to get float array elements from object array"); | |
| gst_amc_jni_object_local_unref (env, object_array); | |
| return FALSE; | |
| } | |
| /* We can't use gst_amc_jni_object_make_global here because we need to call | |
| * ReleaseFloatArrayElements before doing a local unref in the failure case, | |
| * but gst_amc_jni_object_make_global would unref before we could Release. | |
| */ | |
| event->data.array = gst_amc_jni_object_ref (env, object_array); | |
| if (!event->data.array) { | |
| (*env)->ReleaseFloatArrayElements (env, object_array, values, JNI_ABORT); | |
| gst_amc_jni_object_local_unref (env, object_array); | |
| return FALSE; | |
| } | |
| event->data.values = values; | |
| gst_amc_jni_object_local_unref (env, object_array); | |
| return TRUE; | |
| error: | |
| g_clear_error (&err); | |
| return FALSE; | |
| } | |
| void | |
| gst_ah_sensor_free_sensor_data (GstAHSensorData * data) | |
| { | |
| JNIEnv *env = gst_amc_jni_get_env (); | |
| (*env)->ReleaseFloatArrayElements (env, data->array, data->values, JNI_ABORT); | |
| gst_amc_jni_object_unref (env, data->array); | |
| } |