LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/ext/nnstreamer/tensor_source - tensor_src_tizensensor.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 74.7 % 451 337
Test Date: 2025-03-13 05:38:21 Functions: 92.6 % 27 25

            Line data    Source code
       1              : /**
       2              :  * GStreamer Tensor_Src_TizenSensor
       3              :  * Copyright (C) 2019 MyungJoo Ham <myungjoo.ham@samsung.com>
       4              :  *
       5              :  * This library is free software; you can redistribute it and/or
       6              :  * modify it under the terms of the GNU Library General Public
       7              :  * License as published by the Free Software Foundation;
       8              :  * version 2.1 of the License.
       9              :  *
      10              :  * This library is distributed in the hope that it will be useful,
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13              :  * Library General Public License for more details.
      14              :  *
      15              :  */
      16              : /**
      17              :  * @file        tensor_src_tizensensor.c
      18              :  * @date        07 Nov 2019
      19              :  * @brief       GStreamer plugin to support Tizen sensor framework (sensord)
      20              :  * @see         http://github.com/nnstreamer/nnstreamer
      21              :  * @author      MyungJoo Ham <myungjoo.ham@samsung.com>
      22              :  * @bug         No known bugs except for NYI items
      23              :  */
      24              : 
      25              : /**
      26              :  * SECTION:element-tensor_src_tizensensor
      27              :  *
      28              :  * #tensor_src_tizensensor extends #gstbasesrc source element to handle Tizen
      29              :  * Sensor-Framework (sensord) as input.
      30              :  *
      31              :  * <refsect2>
      32              :  * <title>Example launch line</title>
      33              :  * |[
      34              :  * gst-launch -v -m tensor_src_tizensensor type=ACCELEROMETER sequence=0 mode=POLLING ! fakesink
      35              :  * ]|
      36              :  * </refsect2>
      37              :  *
      38              :  * Available types can be retrieved with Tizen System/Sensor APIs:
      39              :  * https://docs.tizen.org/application/native/api/wearable/latest/group__CAPI__SYSTEM__SENSOR__MODULE.html#ga92804cd50337aef93d0e3a3807a9cf33 (Tizen 5.5 Mobile API)
      40              :  *
      41              :  * In case there are multiple sensors for a given sensor type,
      42              :  * you may designate the sequence to choose non-0 sensor instance.
      43              :  * which is equivalent to choosing list[sequence] from
      44              :  * Tizen-API / sensor_get_sensor_list(ACCELEROMETER, list, count);
      45              :  * When the sequence is not specified, the first (.0) is chosen.
      46              :  * You may specify the enum value of the sensor (sensor_type_e) defined
      47              :  * in sensor.h of Tizen with type.
      48              :  *
      49              :  * If sequence = -1 (default), we use "default sensor".
      50              :  *
      51              :  * @todo More manual entries coming.
      52              :  *
      53              :  * @todo Allow to use sensor URIs to designate a sensor
      54              :  * https://docs.tizen.org/application/native/api/mobile/latest/group__CAPI__SYSTEM__SENSOR__LISTENER__MODULE.html#CAPI_SYSTEM_SENSOR_LISTENER_MODULE_URI
      55              :  *
      56              :  * @todo Add "Listener" mode (creates data only if there are updates)
      57              :  *
      58              :  * @todo Every mode should handle timestamp/duration properly!
      59              :  *
      60              :  * @todo Add "power management" options (Tizen sensor f/w accepts such)
      61              :  *
      62              :  * @todo Some sensor types are privileged. We need privilege control.
      63              :  * Some sensor types are privileged. An application should have the privilege http://tizen.org/privilege/healthinfo to get handles for the following sensors: SENSOR_HRM, SENSOR_HRM_LED_GREEN, SENSOR_HRM_LED_IR, SENSOR_HRM_LED_RED, SENSOR_HUMAN_PEDOMETER, SENSOR_HUMAN_SLEEP_MONITOR, SENSOR_HUMAN_SLEEP_DETECTOR, and SENSOR_HUMAN_STRESS_MONITOR.
      64              :  *
      65              :  * @todo Some sensor types appear to have mixed types (float32 & int32).
      66              :  * @todo Add a property to set output tensor type (float32/int32/...) along
      67              :  *       with a few simple multiplications (e.g., x1000) and casting options.
      68              :  */
      69              : 
      70              : #ifdef HAVE_CONFIG_H
      71              : #include <config.h>
      72              : #endif
      73              : 
      74              : #include <string.h>
      75              : #include <errno.h>
      76              : 
      77              : #include <gst/gst.h>
      78              : #include <glib.h>
      79              : 
      80              : /** @todo VALIDATE: Tizen's System/Sensor Public C-API */
      81              : #include <sensor.h>
      82              : 
      83              : #include <tensor_typedef.h>
      84              : #include <nnstreamer_plugin_api.h>
      85              : #include <nnstreamer_log.h>
      86              : #include <nnstreamer_util.h>
      87              : 
      88              : #include "tensor_src_tizensensor.h"
      89              : 
      90              : /**
      91              :  * @brief Macro for debug mode.
      92              :  */
      93              : #ifndef DBG
      94              : #define DBG (!self->silent)
      95              : #endif
      96              : 
      97              : /**
      98              :  * @brief Macro for debug message.
      99              :  */
     100              : #define silent_debug(...) do { \
     101              :     if (DBG) { \
     102              :       GST_DEBUG_OBJECT (self, __VA_ARGS__); \
     103              :     } \
     104              :   } while (0)
     105              : 
     106              : GST_DEBUG_CATEGORY_STATIC (gst_tensor_src_tizensensor_debug);
     107              : #define GST_CAT_DEFAULT gst_tensor_src_tizensensor_debug
     108              : 
     109              : /**
     110              :  * @brief tensor_src_tizensensor properties.
     111              :  */
     112              : enum
     113              : {
     114              :   PROP_0,
     115              :   PROP_SILENT,
     116              :   PROP_TYPE,
     117              :   PROP_SEQUENCE,
     118              :   PROP_MODE,
     119              :   PROP_FREQ,
     120              : };
     121              : 
     122              : /**
     123              :  * @brief Flag to print minimized log.
     124              :  */
     125              : #define DEFAULT_PROP_SILENT TRUE
     126              : 
     127              : /**
     128              :  * @brief Default Tizen sensor type
     129              :  */
     130              : #define DEFAULT_PROP_TYPE -1    /* Denotes "ALL" (any) */
     131              : 
     132              : /**
     133              :  * @brief Default sensor value retrieving mode
     134              :  */
     135              : #define DEFAULT_PROP_MODE "polling"
     136              : 
     137              : /**
     138              :  * @brief Default sensor retrieving frequency
     139              :  */
     140              : #define DEFAULT_PROP_FREQ_N 10
     141              : #define DEFAULT_PROP_FREQ_D 1
     142              : 
     143              : /**
     144              :  * @brief Default sequence number
     145              :  */
     146              : #define DEFAULT_PROP_SEQUENCE -1
     147              : 
     148              : #define _LOCK(obj) g_mutex_lock (&(obj)->lock)
     149              : #define _UNLOCK(obj) g_mutex_unlock (&(obj)->lock)
     150              : 
     151              : /** GObject method implementation */
     152              : static void gst_tensor_src_tizensensor_set_property (GObject * object,
     153              :     guint prop_id, const GValue * value, GParamSpec * pspec);
     154              : static void gst_tensor_src_tizensensor_get_property (GObject * object,
     155              :     guint prop_id, GValue * value, GParamSpec * pspec);
     156              : static void gst_tensor_src_tizensensor_finalize (GObject * object);
     157              : 
     158              : /** GstBaseSrc method implementation */
     159              : static gboolean gst_tensor_src_tizensensor_start (GstBaseSrc * src);
     160              : static gboolean gst_tensor_src_tizensensor_stop (GstBaseSrc * src);
     161              : static gboolean gst_tensor_src_tizensensor_event (GstBaseSrc * src,
     162              :     GstEvent * event);
     163              : static gboolean gst_tensor_src_tizensensor_set_caps (GstBaseSrc * src,
     164              :     GstCaps * caps);
     165              : static GstCaps *gst_tensor_src_tizensensor_get_caps (GstBaseSrc * src,
     166              :     GstCaps * filter);
     167              : static GstCaps *gst_tensor_src_tizensensor_fixate (GstBaseSrc * src,
     168              :     GstCaps * caps);
     169              : static gboolean gst_tensor_src_tizensensor_is_seekable (GstBaseSrc * src);
     170              : static gboolean gst_tensor_src_tizensensor_query (GstBaseSrc * src, GstQuery * query);
     171              : static GstFlowReturn gst_tensor_src_tizensensor_create (GstBaseSrc * src,
     172              :     guint64 offset, guint size, GstBuffer ** buf);
     173              : static GstFlowReturn gst_tensor_src_tizensensor_fill (GstBaseSrc * src,
     174              :     guint64 offset, guint size, GstBuffer * buf);
     175              : 
     176              : #define gst_tensor_src_tizensensor_parent_class parent_class
     177           78 : G_DEFINE_TYPE (GstTensorSrcTIZENSENSOR, gst_tensor_src_tizensensor,
     178              :     GST_TYPE_BASE_SRC);
     179              : 
     180              : #define GST_TYPE_TIZEN_SENSOR_TYPE (tizen_sensor_get_type ())
     181              : /**
     182              :  * @brief Support GEnumValue array for Tizen sensor framework's sensor_type_e (sensor.h)
     183              :  * @todo We need an automated maintenance system for sensor.h's sensor_type_e, which makes a build error if it has been changed.
     184              :  */
     185              : static GType
     186           11 : tizen_sensor_get_type (void)
     187              : {
     188              :   static GType etype = 0;
     189           11 :   if (etype == 0) {
     190              :     static const GEnumValue values[] = {
     191              :       {SENSOR_ALL, "SENSOR_ALL", "all"},
     192              :       {SENSOR_ACCELEROMETER, "SENSOR_ACCELEROMETER", "accelerometer"},
     193              :       {SENSOR_GRAVITY, "SENSOR_GRAVITY", "gravity"},
     194              :       {SENSOR_LINEAR_ACCELERATION, "SENSOR_LINEAR_ACCELERATION",
     195              :           "linear_acceleration"},
     196              :       {SENSOR_MAGNETIC, "SENSOR_MAGNETIC", "magnetic"},
     197              :       {SENSOR_ROTATION_VECTOR, "SENSOR_ROTATION_VECTOR", "rotation_vector"},
     198              :       {SENSOR_ORIENTATION, "SENSOR_ORIENTATION", "orientation"},
     199              :       {SENSOR_GYROSCOPE, "SENSOR_GYROSCOPE", "gyroscope"},
     200              :       {SENSOR_LIGHT, "SENSOR_LIGHT", "light"},
     201              :       {SENSOR_PROXIMITY, "SENSOR_PROXIMITY", "proximity"},
     202              :       {SENSOR_PRESSURE, "SENSOR_PRESSURE", "pressure"},
     203              :       {SENSOR_ULTRAVIOLET, "SENSOR_ULTRAVIOLET", "ultraviolet"},
     204              :       {SENSOR_TEMPERATURE, "SENSOR_TEMPERATURE", "temperature"},
     205              :       {SENSOR_HUMIDITY, "SENSOR_HUMIDITY", "humidity"},
     206              :       {SENSOR_HRM, "SENSOR_HRM", "hrm"},
     207              :       {SENSOR_HRM_LED_GREEN, "SENSOR_HRM_LED_GREEN", "hrm_led_green"},
     208              :       {SENSOR_HRM_LED_IR, "SENSOR_HRM_LED_IR", "hrm_led_ir"},
     209              :       {SENSOR_HRM_LED_RED, "SENSOR_HRM_LED_RED", "hrm_led_red"},
     210              :       {SENSOR_GYROSCOPE_UNCALIBRATED, "SENSOR_GYROSCOPE_UNCALIBRATED",
     211              :           "gyroscope_uncalibrated"},
     212              :       {SENSOR_GEOMAGNETIC_UNCALIBRATED, "SENSOR_GEOMAGNETIC_UNCALIBRATED",
     213              :           "geomagnetic_uncalibrated"},
     214              :       {SENSOR_GYROSCOPE_ROTATION_VECTOR, "SENSOR_GYROSCOPE_ROTATION_VECTOR",
     215              :           "gyroscope_rotation_vector"},
     216              :       {SENSOR_GEOMAGNETIC_ROTATION_VECTOR, "SENSOR_GEOMAGNETIC_ROTATION_VECTOR",
     217              :           "geomagnetic_rotation_vector"},
     218              :       {SENSOR_SIGNIFICANT_MOTION, "SENSOR_SIGNIFICANT_MOTION",
     219              :           "significant_motion"},
     220              :       {SENSOR_HUMAN_PEDOMETER, "SENSOR_HUMAN_PEDOMETER", "human_pedometer"},
     221              :       {SENSOR_HUMAN_SLEEP_MONITOR, "SENSOR_HUMAN_SLEEP_MONITOR",
     222              :           "human_sleep_monitor"},
     223              :       {SENSOR_HUMAN_SLEEP_DETECTOR, "SENSOR_HUMAN_SLEEP_DETECTOR",
     224              :           "human_sleep_detector"},
     225              :       {SENSOR_HUMAN_STRESS_MONITOR, "SENSOR_HUMAN_STRESS_MONITOR",
     226              :           "human_stress_monitor"},
     227              :       {SENSOR_LAST, "SENSOR_LAST", "last"},
     228              :       {SENSOR_CUSTOM, "SENSOR_CUSTOM", "custom"},
     229              :       {0, NULL, NULL},
     230              :     };
     231           11 :     etype = g_enum_register_static ("sensor_type_e", values);
     232              :   }
     233           11 :   return etype;
     234              : }
     235              : 
     236              : static GHashTable *tizensensors = NULL;
     237              : 
     238              : /**
     239              :  * @brief Specification for each Tizen Sensor Type
     240              :  */
     241              : typedef struct
     242              : {
     243              :   sensor_type_e type;
     244              :   int value_count;
     245              :   GstTensorInfo tinfo;
     246              : } TizenSensorSpec;
     247              : 
     248              : /**
     249              :  * @brief Tizen sensor type specification
     250              :  * @details According to Tizen document,
     251              :  * https://developer.tizen.org/development/guides/native-application/location-and-sensors/device-sensors
     252              :  * Each sensor type has predetermined dimensions and types
     253              :  */
     254              : static TizenSensorSpec tizensensorspecs[] = {
     255              :   {.type = SENSOR_ACCELEROMETER,.value_count = 3,
     256              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     257              :           .dimension = {3, 1, 0, }}},
     258              :   {.type = SENSOR_GRAVITY,.value_count = 3,
     259              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     260              :           .dimension = {3, 1, 0, }}},
     261              :   {.type = SENSOR_LINEAR_ACCELERATION,.value_count = 3,
     262              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     263              :           .dimension = {3, 1, 0, }}},
     264              :   {.type = SENSOR_MAGNETIC,.value_count = 3,
     265              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     266              :           .dimension = {3, 1, 0, }}},
     267              :   {.type = SENSOR_ROTATION_VECTOR,.value_count = 4,
     268              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     269              :           .dimension = {4, 1, 0, }}},
     270              :   {.type = SENSOR_ORIENTATION,.value_count = 3,
     271              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     272              :           .dimension = {3, 1, 0, }}},
     273              :   {.type = SENSOR_GYROSCOPE,.value_count = 3,
     274              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     275              :           .dimension = {3, 1, 0, }}},
     276              :   {.type = SENSOR_LIGHT,.value_count = 1,
     277              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     278              :           .dimension = {1, 1, 0, }}},
     279              :   {.type = SENSOR_PROXIMITY,.value_count = 1,
     280              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     281              :           .dimension = {1, 1, 0, }}},
     282              :   {.type = SENSOR_PRESSURE,.value_count = 1,
     283              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     284              :           .dimension = {1, 1, 0, }}},
     285              :   {.type = SENSOR_ULTRAVIOLET,.value_count = 1,
     286              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     287              :           .dimension = {1, 1, 0, }}},
     288              :   {.type = SENSOR_TEMPERATURE,.value_count = 1,
     289              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     290              :           .dimension = {1, 1, 0, }}},
     291              :   {.type = SENSOR_HUMIDITY,.value_count = 1,
     292              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     293              :           .dimension = {1, 1, 0, }}},
     294              :   {.type = SENSOR_HRM,.value_count = 1,
     295              :         .tinfo = {.name = NULL,.type = _NNS_INT32,
     296              :           .dimension = {1, 1, 0, }}},
     297              :   {.type = SENSOR_HRM_LED_GREEN,.value_count = 1,
     298              :         .tinfo = {.name = NULL,.type = _NNS_INT32,
     299              :           .dimension = {1, 1, 0, }}},
     300              :   {.type = SENSOR_HRM_LED_IR,.value_count = 1,
     301              :         .tinfo = {.name = NULL,.type = _NNS_INT32,
     302              :           .dimension = {1, 1, 0, }}},
     303              :   {.type = SENSOR_HRM_LED_RED,.value_count = 1,
     304              :         .tinfo = {.name = NULL,.type = _NNS_INT32,
     305              :           .dimension = {1, 1, 0, }}},
     306              :   {.type = SENSOR_GYROSCOPE_UNCALIBRATED,.value_count = 6,
     307              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     308              :           .dimension = {6, 1, 0, }}},
     309              :   {.type = SENSOR_GEOMAGNETIC_UNCALIBRATED,.value_count = 6,
     310              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     311              :           .dimension = {6, 1, 0, }}},
     312              :   {.type = SENSOR_GYROSCOPE_ROTATION_VECTOR,.value_count = 4,
     313              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     314              :           .dimension = {4, 1, 0, }}},
     315              :   {.type = SENSOR_GEOMAGNETIC_ROTATION_VECTOR,.value_count = 4,
     316              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     317              :           .dimension = {4, 1, 0, }}},
     318              :   {.type = SENSOR_SIGNIFICANT_MOTION,.value_count = 1,
     319              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     320              :           .dimension = {1, 1, 0, }}},
     321              :   {.type = SENSOR_HUMAN_PEDOMETER,.value_count = 8,     /* Last 5 values might be flost32..? */
     322              :         .tinfo = {.name = NULL,.type = _NNS_INT32,
     323              :           .dimension = {8, 1, 0, }}},
     324              :   {.type = SENSOR_HUMAN_SLEEP_MONITOR,.value_count = 1, /* STATE */
     325              :         .tinfo = {.name = NULL,.type = _NNS_INT32,
     326              :           .dimension = {1, 1, 0, }}},
     327              :   {.type = SENSOR_HUMAN_SLEEP_DETECTOR,.value_count = 1, /** @todo check! */
     328              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     329              :           .dimension = {1, 1, 0, }}},
     330              :   {.type = SENSOR_HUMAN_STRESS_MONITOR,.value_count = 1, /** @todo check! */
     331              :         .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
     332              :           .dimension = {1, 1, 0, }}},
     333              :   {.type = SENSOR_LAST,.value_count = 0,.tinfo = {0,}},
     334              : };
     335              : 
     336              : #define GST_TYPE_TIZEN_SENSOR_MODE (tizen_sensor_get_mode ())
     337              : /**
     338              :  * @brief Provide options of sensor operations
     339              :  */
     340              : static GType
     341           11 : tizen_sensor_get_mode (void)
     342              : {
     343              :   static GType etype = 0;
     344           11 :   if (etype == 0) {
     345              :     static const GEnumValue values[] = {
     346              :       {TZN_SENSOR_MODE_POLLING, "POLLING", "polling"},
     347              :       {0, NULL, NULL},
     348              :     };
     349           11 :     etype = g_enum_register_static ("sensor_op_modes", values);
     350              :   }
     351           11 :   return etype;
     352              : }
     353              : 
     354              : /**
     355              :  * @brief initialize the tensor_src_tizensensor class.
     356              :  */
     357              : static void
     358           11 : gst_tensor_src_tizensensor_class_init (GstTensorSrcTIZENSENSORClass * klass)
     359              : {
     360           11 :   GObjectClass *gobject_class = (GObjectClass *) klass;
     361           11 :   GstElementClass *gstelement_class = (GstElementClass *) klass;
     362           11 :   GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
     363              :   GstPadTemplate *pad_template;
     364              :   GstCaps *pad_caps;
     365              : 
     366           11 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_src_tizensensor_debug,
     367              :       "tensor_src_tizensensor", 0,
     368              :       "src element to support Tizen sensor framework");
     369              : 
     370           11 :   gobject_class->set_property = gst_tensor_src_tizensensor_set_property;
     371           11 :   gobject_class->get_property = gst_tensor_src_tizensensor_get_property;
     372           11 :   gobject_class->finalize = gst_tensor_src_tizensensor_finalize;
     373              : 
     374           11 :   g_object_class_install_property (gobject_class, PROP_SILENT,
     375              :       g_param_spec_boolean ("silent", "Silent",
     376              :           "Produce verbose output", DEFAULT_PROP_SILENT,
     377              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     378           11 :   g_object_class_install_property (gobject_class, PROP_TYPE,
     379              :       g_param_spec_enum ("type", "Tizen Sensor Type (enum)",
     380              :           "Tizen sensor type as a enum-name, defined in sensor.h of Tizen",
     381              :           GST_TYPE_TIZEN_SENSOR_TYPE, SENSOR_ALL,
     382              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     383           11 :   g_object_class_install_property (gobject_class, PROP_SEQUENCE,
     384              :       g_param_spec_int ("sequence", "Sequence number of a sensor type",
     385              :           "Select a sensor if there are multiple sensors of a type",
     386              :           -1, G_MAXINT, DEFAULT_PROP_SEQUENCE, G_PARAM_READWRITE));
     387           11 :   g_object_class_install_property (gobject_class, PROP_MODE,
     388              :       g_param_spec_enum ("mode", "Sensor data retrieval mode (enum)",
     389              :           "Determine how sensor data are retrieved (e.g. polling)",
     390              :           GST_TYPE_TIZEN_SENSOR_MODE, TZN_SENSOR_MODE_POLLING,
     391              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     392           11 :   g_object_class_install_property (gobject_class, PROP_FREQ,
     393              :       gst_param_spec_fraction ("framerate", "Framerate",
     394              :           "Rate of data retrievals from a sensor. Effective only when "
     395              :           "mode is ACTIVE_POLLING",
     396              :           0, 1, G_MAXINT, 1,
     397              :           DEFAULT_PROP_FREQ_N, DEFAULT_PROP_FREQ_D,
     398              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     399              : 
     400              :   /* pad template */
     401              :   /** @todo Narrow down allowed tensors/tensor. */
     402           11 :   pad_caps = gst_caps_from_string (GST_TENSOR_CAP_DEFAULT "; "
     403              :       GST_TENSORS_CAP_WITH_NUM ("1"));
     404           11 :   pad_template = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
     405              :       pad_caps);
     406           11 :   gst_element_class_add_pad_template (gstelement_class, pad_template);
     407           11 :   gst_caps_unref (pad_caps);
     408              : 
     409           11 :   gst_element_class_set_static_metadata (gstelement_class,
     410              :       "TensorSrcTizenSensor", "Source/Tensor/Device",
     411              :       "Creates tensor(s) stream from a given Tizen sensor framework node",
     412              :       "MyungJoo Ham <myungjoo.ham@samsung.com>");
     413              : 
     414           11 :   gstbasesrc_class->set_caps =
     415           11 :       GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_set_caps);
     416           11 :   gstbasesrc_class->get_caps =
     417           11 :       GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_get_caps);
     418           11 :   gstbasesrc_class->fixate =
     419           11 :       GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_fixate);
     420           11 :   gstbasesrc_class->is_seekable =
     421           11 :       GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_is_seekable);
     422           11 :   gstbasesrc_class->start =
     423           11 :       GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_start);
     424           11 :   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_stop);
     425           11 :   gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_query);
     426           11 :   gstbasesrc_class->create =
     427           11 :       GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_create);
     428           11 :   gstbasesrc_class->fill = GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_fill);
     429           11 :   gstbasesrc_class->event =
     430           11 :       GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_event);
     431           11 : }
     432              : 
     433              : /**
     434              :  * @brief initialize tensor_src_tizensensor element.
     435              :  */
     436              : static void
     437            9 : gst_tensor_src_tizensensor_init (GstTensorSrcTIZENSENSOR * self)
     438              : {
     439              :   /** init properties */
     440            9 :   self->configured = FALSE;
     441            9 :   self->silent = DEFAULT_PROP_SILENT;
     442            9 :   self->running = FALSE;
     443            9 :   self->freq_n = DEFAULT_PROP_FREQ_N;
     444            9 :   self->freq_d = DEFAULT_PROP_FREQ_D;
     445            9 :   self->type = SENSOR_ALL;
     446              : 
     447            9 :   g_mutex_init (&self->lock);
     448              : 
     449              :   /**
     450              :    * @todo TBD. Update This!
     451              :    * format of the source since IIO device as a source is live and operates
     452              :    * at a fixed frequency, GST_FORMAT_TIME is used
     453              :    */
     454            9 :   gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
     455              :   /** set the source to be a live source */
     456            9 :   gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
     457              :   /** set base_src to automatically timestamp outgoing buffers
     458              :    * based on the current running_time of the pipeline.
     459              :    */
     460            9 :   gst_base_src_set_do_timestamp (GST_BASE_SRC (self), TRUE);
     461              :   /**
     462              :    * set async is necessary to make state change async
     463              :    * sync state changes does not need calling _start_complete() from _start()
     464              :    */
     465            9 :   gst_base_src_set_async (GST_BASE_SRC (self), TRUE);
     466              : 
     467              :   /** @todo TBD. Let's assume each frame has a fixed size */
     468            9 :   gst_base_src_set_dynamic_size (GST_BASE_SRC (self), FALSE);
     469              : 
     470            9 :   if (NULL == tizensensors) {
     471              :     int i, sensor_dim;
     472            1 :     tizensensors = g_hash_table_new (g_direct_hash, g_direct_equal);
     473              : 
     474           27 :     for (i = 0; tizensensorspecs[i].type != SENSOR_LAST; i++) {
     475           26 :       g_assert (g_hash_table_insert (tizensensors,
     476              :               GINT_TO_POINTER (tizensensorspecs[i].type),
     477              :               &tizensensorspecs[i].tinfo));
     478           26 :       sensor_dim = tizensensorspecs[i].tinfo.dimension[0];
     479           26 :       g_assert (tizensensorspecs[i].value_count == sensor_dim);
     480              :     }
     481              :   }
     482            9 : }
     483              : 
     484              : /**
     485              :  * @brief This cleans up.
     486              :  * @details This cleans up the Tizen sensor handle/context,
     487              :  *          ready for a new handle/context or exit.
     488              :  *          This does not alter saved properties.
     489              :  * @returns it returns -1 if there is an error.
     490              :  */
     491              : static int
     492           11 : _ts_clean_up_handle (GstTensorSrcTIZENSENSOR * self)
     493              : {
     494           11 :   if (self->running) {
     495            3 :     sensor_listener_stop (self->listener);
     496            3 :     if (!self->configured)
     497            0 :       return -1;
     498              :   }
     499              : 
     500           11 :   self->running = FALSE;
     501              : 
     502           11 :   if (self->configured) {
     503            3 :     sensor_destroy_listener (self->listener);
     504              :   }
     505              : 
     506           11 :   self->src_spec = NULL;
     507           11 :   self->listener = NULL;
     508           11 :   self->sensor = NULL;
     509              : 
     510           11 :   self->configured = FALSE;
     511           11 :   return 0;
     512              : }
     513              : 
     514              : /**
     515              :  * @brief Sensor event (data retrieval) handler
     516              :  * @details This is for TZN_SENSOR_MODE_ACTIVE_POLLING
     517              :  */
     518              : static void __attribute__((unused))
     519            0 : _ts_tizen_sensor_callback (sensor_h sensor, sensor_event_s events[],
     520              :     int events_count, void *user_data)
     521              : {
     522            0 :   GstTensorSrcTIZENSENSOR *self = (GstTensorSrcTIZENSENSOR *) user_data;
     523              :   sensor_event_s *event;
     524              :   sensor_type_e type;
     525            0 :   int n_tensor_size = gst_tensor_get_element_count (self->src_spec->dimension);
     526              : 
     527            0 :   g_assert (self->configured);
     528            0 :   g_assert (self->running);
     529            0 :   g_assert (events_count > 0);
     530              : 
     531              :   /** @todo last or first sensor data? */
     532            0 :   event = &events[events_count - 1];
     533              : 
     534            0 :   sensor_get_type (sensor, &type);
     535              : 
     536            0 :   g_assert (type == self->type);
     537            0 :   g_assert (n_tensor_size == event->value_count);
     538              : 
     539              :   /** @todo Call some GST/BASESRC callback to fill things in from event */
     540              : 
     541              :   /** @todo Get proper timestamp from Tizen API, record it to metadata */
     542              : 
     543            0 :   g_assert (1 == 0);/** @todo NYI. Needed if we add more modes */
     544              : }
     545              : 
     546              : /**
     547              :  * @brief Calculate interval in ms from framerate
     548              :  * @details This is effective only for TZN_SENSOR_MODE_ACTIVE_POLLING.
     549              :  */
     550              : static unsigned int
     551            3 : _ts_get_interval_ms (GstTensorSrcTIZENSENSOR * self)
     552              : {
     553            3 :   if (self->freq_n == 0)
     554            0 :     return 100;                 /* If it's 0Hz, assume 100ms interval */
     555              : 
     556            3 :   g_assert (self->freq_d > 0 && self->freq_n > 0);
     557              : 
     558            3 :   return gst_util_uint64_scale_int ((guint64) self->freq_d, 1000, self->freq_n);
     559              : }
     560              : 
     561              : /**
     562              :  * @brief Get handle, setup context, make it ready!
     563              :  */
     564              : static int
     565            4 : _ts_configure_handle (GstTensorSrcTIZENSENSOR * self)
     566              : {
     567            4 :   int ret = 0;
     568            8 :   const GstTensorInfo *val = g_hash_table_lookup (tizensensors,
     569            4 :       GINT_TO_POINTER (self->type));
     570            4 :   bool supported = false;
     571              : 
     572            4 :   if (NULL == val) {
     573            0 :     nns_loge ("The given sensor type (%d) is not supported.\n", self->type);
     574            4 :     return -ENODEV;
     575              :   }
     576            4 :   self->src_spec = val;
     577              : 
     578              :   /* Based on Tizen Native App (Sensor) Guide */
     579              :   /* 1. Check if the sensor supported */
     580            4 :   ret = sensor_is_supported (self->type, &supported);
     581            4 :   if (ret != SENSOR_ERROR_NONE) {
     582            0 :     nns_loge ("Tizen sensor framework is not working (sensor_is_supported).\n");
     583            0 :     return -ENODEV;
     584              :   }
     585              : 
     586            4 :   if (false == supported) {
     587            1 :     GST_ERROR_OBJECT (self,
     588              :         "Tizen sensor framework API, sensor_is_supported(), says the sensor %d is not supported",
     589              :         self->type);
     590            1 :     return -EINVAL;
     591              :   }
     592              : 
     593              :   /* 2. Get sensor listener */
     594            3 :   if (self->sequence == -1) {
     595              :     /* Get the default sensor */
     596            1 :     ret = sensor_get_default_sensor (self->type, &self->sensor);
     597            1 :     if (ret != SENSOR_ERROR_NONE) {
     598            0 :       nns_loge ("Cannot get default sensor");
     599            0 :       return ret;
     600              :     }
     601              :   } else {
     602              :     sensor_h *list;
     603              :     int count;
     604              : 
     605              :     /* Use the sequence number to choose one */
     606            2 :     ret = sensor_get_sensor_list (self->type, &list, &count);
     607            2 :     if (ret != SENSOR_ERROR_NONE) {
     608            0 :       nns_loge ("Cannot get sensor list");
     609            0 :       return ret;
     610              :     }
     611              : 
     612            2 :     if (count <= self->sequence) {
     613            0 :       GST_ERROR_OBJECT (self,
     614              :           "The requested sensor sequence %d for sensor %d is not available. The max-sequence is used instead",
     615              :           self->sequence, self->type);
     616            0 :       self->sequence = 0;
     617            0 :       g_free (list);
     618            0 :       return -EINVAL;
     619              :     }
     620              : 
     621            2 :     self->sensor = list[self->sequence];
     622            2 :     g_free (list);
     623              :   }
     624              : 
     625            3 :   ret = sensor_create_listener (self->sensor, &self->listener);
     626            3 :   if (ret != SENSOR_ERROR_NONE) {
     627            0 :     nns_loge ("Cannot create sensor listener");
     628            0 :     return ret;
     629              :   }
     630              : 
     631              :   /* 3. Configure interval_ms */
     632            3 :   self->interval_ms = _ts_get_interval_ms (self);
     633              : 
     634            3 :   ret = sensor_listener_set_interval (self->listener, self->interval_ms);
     635            3 :   if (ret != SENSOR_ERROR_NONE) {
     636            0 :     nns_loge ("Cannot set the sensor interval");
     637            0 :     return ret;
     638              :   }
     639              : 
     640            3 :   nns_logi ("Set sensor_listener interval: %ums", self->interval_ms);
     641              : 
     642              :   /* 4. Register sensor event handler */
     643            3 :   switch (self->mode) {
     644            3 :     case TZN_SENSOR_MODE_POLLING:
     645              :       /* Nothing to do. Let Gst poll data */
     646            3 :       break;
     647              : #if 0 /** Use this if TZN_SENSOR_MODE_ACTIVE_POLLING is implemented */
     648              :     case TZN_SENSOR_MODE_ACTIVE_POLLING:
     649              :       ret = sensor_listener_set_events_cb (listener,
     650              :           _ts_tizen_sensor_callback, self);
     651              :       if (ret != SENSOR_ERROR_NONE)
     652              :         return ret;
     653              :       break;
     654              : #endif
     655            0 :     default:
     656            0 :       GST_ERROR_OBJECT (self,
     657              :           "The requested mode (%d) is invalid, use values defined in sensor_op_modes only.",
     658              :           self->mode);
     659              :   }
     660              : 
     661            3 :   self->configured = TRUE;
     662            3 :   return 0;
     663              : }
     664              : 
     665              : /**
     666              :  * @brief Keeping the handle/context, reconfigure a few parameters
     667              :  */
     668              : static int
     669            0 : _ts_reconfigure (GstTensorSrcTIZENSENSOR * self)
     670              : {
     671            0 :   _ts_clean_up_handle (self);
     672            0 :   return _ts_configure_handle (self);
     673              : }
     674              : 
     675              : /**
     676              :  * @brief set tensor_src_tizensensor properties
     677              :  */
     678              : static void
     679           25 : gst_tensor_src_tizensensor_set_property (GObject * object,
     680              :     guint prop_id, const GValue * value, GParamSpec * pspec)
     681              : {
     682           25 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR (object);
     683           25 :   int ret = 0;
     684              : 
     685           25 :   switch (prop_id) {
     686            1 :     case PROP_SILENT:
     687            1 :       self->silent = g_value_get_boolean (value);
     688            1 :       silent_debug ("Set silent = %d", self->silent);
     689            1 :       break;
     690            9 :     case PROP_TYPE:
     691              :     {
     692            9 :       sensor_type_e new_type = g_value_get_enum (value);
     693              : 
     694            9 :       _LOCK (self);
     695              : 
     696            9 :       if (new_type != self->type) {
     697              :         /* Different sensor is being used. Clean it up! */
     698            9 :         if (self->configured)
     699            0 :           ret = _ts_clean_up_handle (self);
     700              : 
     701            9 :         if (ret) {
     702            0 :           GST_ERROR_OBJECT (self, "_ts_clean_up_handle() returns %d", ret);
     703              :         }
     704              : 
     705            9 :         silent_debug ("Set type from %d --> %d.", self->type, new_type);
     706            9 :         self->type = new_type;
     707              :       } else {
     708            0 :         silent_debug ("Set type ignored (%d --> %d).", self->type, new_type);
     709              :       }
     710              : 
     711            9 :       _UNLOCK (self);
     712              :     }
     713            9 :       break;
     714            6 :     case PROP_SEQUENCE:
     715              :     {
     716            6 :       gint new_sequence = g_value_get_int (value);
     717              : 
     718            6 :       _LOCK (self);
     719              : 
     720            6 :       if (self->sequence != new_sequence) {
     721              :         /* Different sensor is being used. Clean it up! */
     722            4 :         if (self->configured)
     723            0 :           ret = _ts_clean_up_handle (self);
     724              : 
     725            4 :         if (ret) {
     726            0 :           GST_ERROR_OBJECT (self, "_ts_clean_up_handle() returns %d", ret);
     727              :         }
     728              : 
     729            4 :         silent_debug ("Set sequence from %d --> %d.", self->sequence,
     730              :             new_sequence);
     731            4 :         self->sequence = new_sequence;
     732              :       } else {
     733            2 :         silent_debug ("Set sequence ignored (%d --> %d).", self->sequence,
     734              :             new_sequence);
     735              :       }
     736              : 
     737            6 :       _UNLOCK (self);
     738              :     }
     739            6 :       break;
     740            2 :     case PROP_MODE:
     741              :     {
     742            2 :       sensor_op_modes new_mode = g_value_get_enum (value);
     743            2 :       sensor_op_modes old_mode = self->mode;
     744              : 
     745            2 :       _LOCK (self);
     746              : 
     747            2 :       if (new_mode != self->mode) {
     748            0 :         silent_debug ("Set mode from %d --> %d.", self->mode, new_mode);
     749            0 :         self->mode = new_mode;
     750              : 
     751              :         /* Same sensor is kept. Only mode is changed */
     752            0 :         if (self->configured)
     753            0 :           ret = _ts_reconfigure (self);
     754              : 
     755            0 :         if (ret) {
     756            0 :           self->mode = old_mode;
     757            0 :           GST_ERROR_OBJECT (self, "_ts_reconfigure () returns %d", ret);
     758              :         }
     759              : 
     760              :       } else {
     761            2 :         silent_debug ("Set mode ignored (%d --> %d).", self->mode, new_mode);
     762              :       }
     763              : 
     764            2 :       _UNLOCK (self);
     765              :     }
     766            2 :       break;
     767            7 :     case PROP_FREQ:
     768              :     {
     769            7 :       gint n = self->freq_n;
     770            7 :       gint d = self->freq_d;
     771              : 
     772            7 :       _LOCK (self);
     773              : 
     774            7 :       self->freq_n = gst_value_get_fraction_numerator (value);
     775            7 :       self->freq_d = gst_value_get_fraction_denominator (value);
     776              : 
     777            7 :       if (self->freq_n < 0)
     778            0 :         self->freq_n = 0;
     779            7 :       if (self->freq_d < 1)
     780            0 :         self->freq_d = 1;
     781              : 
     782            7 :       silent_debug ("Set operating frequency %d/%d --> %d/%d",
     783              :           n, d, self->freq_n, self->freq_d);
     784              : 
     785            7 :       if (n != self->freq_n || d != self->freq_d) {
     786              :         /* Same sensor is kept. Only frequency is changed */
     787            6 :         if (self->configured)
     788            0 :           ret = _ts_reconfigure (self);
     789              : 
     790            6 :         if (ret) {
     791            0 :           self->freq_n = n;
     792            0 :           self->freq_d = d;
     793            0 :           GST_ERROR_OBJECT (self,
     794              :               "Calling _ts_reconfigure at set PROP_FREQ has failed. _ts_reconfigure () returns %d",
     795              :               ret);
     796              :         }
     797              :       }
     798            7 :       _UNLOCK (self);
     799              :     }
     800            7 :       break;
     801            0 :     default:
     802            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     803            0 :       break;
     804              :   }
     805           25 : }
     806              : 
     807              : /**
     808              :  * @brief get tensor_src_tizensensor properties
     809              :  */
     810              : static void
     811           12 : gst_tensor_src_tizensensor_get_property (GObject * object,
     812              :     guint prop_id, GValue * value, GParamSpec * pspec)
     813              : {
     814           12 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR (object);
     815              : 
     816           12 :   switch (prop_id) {
     817            1 :     case PROP_SILENT:
     818            1 :       g_value_set_boolean (value, self->silent);
     819            1 :       break;
     820            3 :     case PROP_TYPE:
     821            3 :       g_value_set_enum (value, self->type);
     822            3 :       break;
     823            1 :     case PROP_SEQUENCE:
     824            1 :       g_value_set_int (value, self->sequence);
     825            1 :       break;
     826            3 :     case PROP_MODE:
     827            3 :       g_value_set_enum (value, self->mode);
     828            3 :       break;
     829            4 :     case PROP_FREQ:
     830            4 :       gst_value_set_fraction (value, self->freq_n, self->freq_d);
     831            4 :       break;
     832            0 :     default:
     833            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     834            0 :       break;
     835              :   }
     836           12 : }
     837              : 
     838              : /**
     839              :  * @brief finalize the instance
     840              :  */
     841              : static void
     842            8 : gst_tensor_src_tizensensor_finalize (GObject * object)
     843              : {
     844            8 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR (object);
     845              : 
     846            8 :   _LOCK (self);
     847              : 
     848            8 :   _ts_clean_up_handle (self);
     849              : 
     850            8 :   _UNLOCK (self);
     851            8 :   g_mutex_clear (&self->lock);
     852              : 
     853            8 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     854            8 : }
     855              : 
     856              : /**
     857              :  * @brief start function
     858              :  * @details This is called when state changed null to ready.
     859              :  *          load the device and init the device resources
     860              :  *          We won't configure before start is called.
     861              :  *          Postcondition: configured = TRUE. src = RUNNING.
     862              :  */
     863              : static gboolean
     864            4 : gst_tensor_src_tizensensor_start (GstBaseSrc * src)
     865              : {
     866            4 :   int ret = 0;
     867            4 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
     868            4 :   gboolean retval = TRUE;
     869              :   guint blocksize;
     870              : 
     871            4 :   _LOCK (self);
     872              : 
     873              :   /* 1. Clean it up if there is a previous session */
     874            4 :   if (self->configured) {
     875            0 :     ret = _ts_clean_up_handle (self);
     876            0 :     if (ret) {
     877            0 :       GST_ERROR_OBJECT (self,
     878              :           "Start method failed, cleaning up previous context failed. _ts_clean_up_handle () returns %d",
     879              :           ret);
     880            0 :       retval = FALSE;           /* FAIL! */
     881            0 :       goto exit;
     882              :     }
     883              :   }
     884              : 
     885              :   /* 2. Configure handle / context */
     886            4 :   ret = _ts_configure_handle (self);
     887            4 :   if (ret) {
     888            1 :     retval = FALSE;
     889            1 :     goto exit;
     890              :   }
     891            3 :   g_assert (self->configured);
     892              : 
     893              :   /* 3. Fire it up! */
     894            3 :   if (sensor_listener_start (self->listener) != 0) {
     895              :     /* Failed to start listener. Clean this up */
     896            0 :     ret = _ts_clean_up_handle (self);
     897            0 :     if (ret) {
     898            0 :       GST_ERROR_OBJECT (self, "_ts_clean_up_handle () returns %d", ret);
     899              :     }
     900            0 :     retval = FALSE;
     901            0 :     goto exit;
     902              :   }
     903              : 
     904              :   /* set data size */
     905            3 :   blocksize = (guint) gst_tensor_info_get_size (self->src_spec);
     906            3 :   gst_base_src_set_blocksize (src, blocksize);
     907              : 
     908            3 :   self->running = TRUE;
     909              : 
     910              :   /** complete the start of the base src */
     911            3 :   gst_base_src_start_complete (src, GST_FLOW_OK);
     912              : 
     913            4 : exit:
     914            4 :   _UNLOCK (self);
     915            4 :   return retval;
     916              : }
     917              : 
     918              : /**
     919              :  * @brief stop function.
     920              :  * @details This is called when state changed ready to null.
     921              :  *          Postcondition: configured = FALSE. src = STOPPED.
     922              :  */
     923              : static gboolean
     924            3 : gst_tensor_src_tizensensor_stop (GstBaseSrc * src)
     925              : {
     926            3 :   int ret = 0;
     927            3 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
     928            3 :   gboolean retval = TRUE;
     929              : 
     930            3 :   _LOCK (self);
     931              : 
     932            3 :   ret = _ts_clean_up_handle (self);
     933            3 :   if (ret) {
     934            0 :     GST_ERROR_OBJECT (self,
     935              :         "Stop method failed, cleaning up previous context failed. _ts_clean_up_handle () returns %d",
     936              :         ret);
     937            0 :     retval = FALSE;             /* FAIL! */
     938            0 :     goto exit;
     939              :   }
     940              : 
     941            3 :   g_assert (!self->configured);
     942              : 
     943            3 : exit:
     944            3 :   _UNLOCK (self);
     945            3 :   return retval;
     946              : }
     947              : 
     948              : /**
     949              :  * @brief handle events
     950              :  */
     951              : static gboolean
     952          130 : gst_tensor_src_tizensensor_event (GstBaseSrc * src, GstEvent * event)
     953              : {
     954              :   /** No events to be handled yet */
     955          130 :   return GST_BASE_SRC_CLASS (parent_class)->event (src, event);
     956              : }
     957              : 
     958              : /**
     959              :  * @brief Get possible GstCap from the configuration of self.
     960              :  */
     961              : static GstCaps *
     962            6 : _ts_get_gstcaps_from_conf (GstTensorSrcTIZENSENSOR * self)
     963              : {
     964              :   const GstTensorInfo *spec;
     965              :   GstCaps *retval;
     966              : 
     967            6 :   spec = self->src_spec;
     968              : 
     969            6 :   if (!self->configured || SENSOR_ALL == self->type || NULL == spec) {
     970            0 :     retval = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (self));
     971              :   } else {
     972              :     GstTensorsConfig tensors_config;
     973              : 
     974            6 :     gst_tensors_config_init (&tensors_config);
     975            6 :     tensors_config.info.num_tensors = 1;
     976              : 
     977            6 :     gst_tensor_info_copy (&tensors_config.info.info[0], spec);
     978            6 :     tensors_config.rate_n = self->freq_n;
     979            6 :     tensors_config.rate_d = self->freq_d;
     980              : 
     981            6 :     retval = gst_tensor_caps_from_config (&tensors_config);
     982            6 :     gst_caps_append (retval, gst_tensors_caps_from_config (&tensors_config));
     983              :   }
     984              : 
     985            6 :   return retval;
     986              : }
     987              : 
     988              : /**
     989              :  * @brief set new caps
     990              :  * @retval TRUE if it's acceptable. FALSE if it's not acceptable.
     991              :  */
     992              : static gboolean
     993            3 : gst_tensor_src_tizensensor_set_caps (GstBaseSrc * src, GstCaps * caps)
     994              : {
     995            3 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
     996              :   GstCaps *cap_tensor;
     997            3 :   gboolean retval = FALSE;
     998              : 
     999            3 :   _LOCK (self);
    1000              : 
    1001            3 :   cap_tensor = _ts_get_gstcaps_from_conf (self);
    1002              : 
    1003              :   /* Check if it's compatible with either tensor or tensors */
    1004            3 :   retval = gst_caps_can_intersect (caps, cap_tensor);
    1005            3 :   gst_caps_unref (cap_tensor);
    1006              : 
    1007            3 :   _UNLOCK (self);
    1008            3 :   return retval;
    1009              : }
    1010              : 
    1011              : /**
    1012              :  * @brief get caps of subclass
    1013              :  * @note basesrc _get_caps returns the caps from the pad_template
    1014              :  * however, we set the caps manually and needs to returned here
    1015              :  */
    1016              : static GstCaps *
    1017           21 : gst_tensor_src_tizensensor_get_caps (GstBaseSrc * src, GstCaps * filter)
    1018              : {
    1019              :   GstCaps *caps;
    1020              :   GstPad *pad;
    1021              : 
    1022           21 :   pad = src->srcpad;
    1023           21 :   caps = gst_pad_get_current_caps (pad);
    1024              : 
    1025           21 :   if (caps == NULL)
    1026           21 :     caps = gst_pad_get_pad_template_caps (pad);
    1027              : 
    1028           21 :   if (filter) {
    1029              :     GstCaps *intersection =
    1030            0 :         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
    1031            0 :     gst_caps_unref (caps);
    1032            0 :     caps = intersection;
    1033              :   }
    1034              : 
    1035           21 :   return caps;
    1036              : }
    1037              : 
    1038              : /**
    1039              :  * @brief fixate the caps when needed during negotiation
    1040              :  */
    1041              : static GstCaps *
    1042            3 : gst_tensor_src_tizensensor_fixate (GstBaseSrc * src, GstCaps * caps)
    1043              : {
    1044            3 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
    1045              :   GstCaps *cap_tensor;
    1046            3 :   GstCaps *retval = NULL;
    1047              : 
    1048            3 :   _LOCK (self);
    1049              : 
    1050            3 :   cap_tensor = _ts_get_gstcaps_from_conf (self);
    1051              : 
    1052            3 :   if (gst_caps_can_intersect (caps, cap_tensor))
    1053            3 :     retval = gst_caps_intersect (caps, cap_tensor);
    1054            3 :   gst_caps_unref (cap_tensor);
    1055              : 
    1056            3 :   _UNLOCK (self);
    1057            3 :   return gst_caps_fixate (retval);
    1058              : }
    1059              : 
    1060              : /**
    1061              :  * @brief Sensor nodes are not seekable.
    1062              :  */
    1063              : static gboolean
    1064            3 : gst_tensor_src_tizensensor_is_seekable (GstBaseSrc * src)
    1065              : {
    1066              :   UNUSED (src);
    1067            3 :   nns_logd ("tensor_src_tizensensor is not seekable");
    1068            3 :   return FALSE;
    1069              : }
    1070              : 
    1071              : /**
    1072              :  * @brief Handle queries.
    1073              :  *
    1074              :  * GstBaseSrc method implementation.
    1075              :  */
    1076              : static gboolean
    1077           27 : gst_tensor_src_tizensensor_query (GstBaseSrc * src, GstQuery * query)
    1078              : {
    1079           27 :   gboolean res = FALSE;
    1080           27 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
    1081              : 
    1082           27 :   switch (GST_QUERY_TYPE (query)) {
    1083            3 :     case GST_QUERY_LATENCY:
    1084              :     {
    1085            3 :       GstClockTime min_latency, max_latency = -1;
    1086              :       gint freq_d, freq_n;
    1087              : 
    1088            3 :       freq_d = self->freq_d;
    1089            3 :       freq_n = self->freq_n;
    1090              : 
    1091              :       /* we must have a framerate */
    1092            3 :       if (freq_n <= 0 || freq_d <= 0) {
    1093            0 :         GST_WARNING_OBJECT (self,
    1094              :             "Can't give latency since framerate isn't fixated");
    1095            0 :         goto done;
    1096              :       }
    1097              : 
    1098              :       /* min latency is the time to capture one frame/field */
    1099            3 :       min_latency = gst_util_uint64_scale_int (GST_SECOND, freq_d, freq_n);
    1100              : 
    1101            3 :       GST_DEBUG_OBJECT (self,
    1102              :           "Reporting latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
    1103              :           GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
    1104              : 
    1105            3 :       gst_query_set_latency (query, TRUE, min_latency, max_latency);
    1106              : 
    1107            3 :       res = TRUE;
    1108            3 :       break;
    1109              :     }
    1110           24 :     default:
    1111           24 :       res = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
    1112           24 :       break;
    1113              :   }
    1114              : 
    1115           27 : done:
    1116           27 :   return res;
    1117              : }
    1118              : 
    1119              : /**
    1120              :  * @brief create a buffer with requested size and offset
    1121              :  * @note offset, size ignored as the tensor src tizensensor does not support pull mode
    1122              :  */
    1123              : static GstFlowReturn
    1124          130 : gst_tensor_src_tizensensor_create (GstBaseSrc * src, guint64 offset,
    1125              :     guint size, GstBuffer ** buffer)
    1126              : {
    1127          130 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
    1128          130 :   GstBuffer *buf = gst_buffer_new ();
    1129              :   GstMemory *mem;
    1130              :   guint buffer_size;
    1131          130 :   GstFlowReturn retval = GST_FLOW_OK;
    1132              :   UNUSED (size);
    1133          130 :   _LOCK (self);
    1134              : 
    1135          130 :   if (!self->configured) {
    1136            0 :     GST_ERROR_OBJECT (self,
    1137              :         "Buffer creation requested while the element is not configured. gst_tensor_src_tizensensor_create() cannot proceed if it is not configured.");
    1138            0 :     retval = GST_FLOW_ERROR;
    1139            0 :     goto exit;
    1140              :   }
    1141              : 
    1142          130 :   g_assert (self->src_spec);    /* It should be valid if configured */
    1143              : 
    1144              :   /* We don't have multi-tensor (tensors with num-tensors > 1) */
    1145          130 :   buffer_size = (guint) gst_tensor_info_get_size (self->src_spec);
    1146          130 :   mem = gst_allocator_alloc (NULL, buffer_size, NULL);
    1147          130 :   if (mem == NULL) {
    1148            0 :     GST_ERROR_OBJECT (self,
    1149              :         "Cannot allocate memory for gst buffer of %u bytes", buffer_size);
    1150            0 :     retval = GST_FLOW_ERROR;
    1151            0 :     goto exit;
    1152              :   }
    1153          130 :   gst_buffer_append_memory (buf, mem);
    1154              : 
    1155          130 :   _UNLOCK (self);
    1156          130 :   retval = gst_tensor_src_tizensensor_fill (src, offset, buffer_size, buf);
    1157          130 :   _LOCK (self);
    1158          130 :   if (retval != GST_FLOW_OK)
    1159            0 :     goto exit;
    1160              : 
    1161          130 :   *buffer = buf;
    1162              : 
    1163          130 : exit:
    1164          130 :   _UNLOCK (self);
    1165          130 :   if (retval != GST_FLOW_OK)
    1166            0 :     gst_buffer_unref (buf);
    1167          130 :   return retval;
    1168              : }
    1169              : 
    1170              : #define cast_loop(values, count, dest, desttype) \
    1171              : do { \
    1172              :   int i; \
    1173              :   char *destptr = (char *) (dest); \
    1174              :   for (i = 0; i < (count); i++) \
    1175              :     *(destptr + (sizeof (desttype) * i)) = (desttype) (values)[i]; \
    1176              : } while (0)
    1177              : 
    1178              : #define case_cast_loop(values, count, dest, desttype, desttypeenum) \
    1179              : case desttypeenum: \
    1180              :   cast_loop (values, count, dest, desttype); \
    1181              :   break;
    1182              : 
    1183              : /**
    1184              :  * @brief Copy sensor's values[] to Gst memory map.
    1185              :  */
    1186              : static void
    1187          130 : _ts_assign_values (float values[], int count, GstMapInfo * map,
    1188              :     const GstTensorInfo * spec)
    1189              : {
    1190          130 :   switch (spec->type) {
    1191          130 :     case _NNS_FLOAT32:
    1192          130 :       memcpy (map->data, values, sizeof (float) * count);
    1193          130 :       break;
    1194            0 :       case_cast_loop (values, count, map->data, int64_t, _NNS_INT64);
    1195            0 :       case_cast_loop (values, count, map->data, int32_t, _NNS_INT32);
    1196            0 :       case_cast_loop (values, count, map->data, int16_t, _NNS_INT16);
    1197            0 :       case_cast_loop (values, count, map->data, int8_t, _NNS_INT8);
    1198            0 :       case_cast_loop (values, count, map->data, uint64_t, _NNS_UINT64);
    1199            0 :       case_cast_loop (values, count, map->data, uint32_t, _NNS_UINT32);
    1200            0 :       case_cast_loop (values, count, map->data, uint16_t, _NNS_UINT16);
    1201            0 :       case_cast_loop (values, count, map->data, uint8_t, _NNS_UINT8);
    1202            0 :       case_cast_loop (values, count, map->data, double, _NNS_FLOAT64);
    1203            0 :     default:
    1204            0 :       g_assert (0);   /** Other types are not implemented! */
    1205              :   }
    1206          130 : }
    1207              : 
    1208              : /**
    1209              :  * @brief fill the buffer with data
    1210              :  * @note ignore offset,size as there is pull mode
    1211              :  * @note buffer timestamp is already handled by gstreamer with gst clock
    1212              :  * @note Get data from Tizen Sensor F/W. Get the timestamp as well!
    1213              :  */
    1214              : static GstFlowReturn
    1215          130 : gst_tensor_src_tizensensor_fill (GstBaseSrc * src, guint64 offset,
    1216              :     guint size, GstBuffer * buffer)
    1217              : {
    1218          130 :   GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
    1219          130 :   sensor_event_s *events = NULL;
    1220          130 :   GstFlowReturn retval = GST_FLOW_OK;
    1221              :   GstMemory *mem;
    1222              :   GstMapInfo map;
    1223              :   int src_dim;
    1224              :   guint data_size;
    1225              :   UNUSED (offset);
    1226          130 :   _LOCK (self);
    1227              : 
    1228          130 :   if (!self->configured) {
    1229            0 :     GST_ERROR_OBJECT (self,
    1230              :         "gst_tensor_src_tizensensor_fill() cannot proceed if it is not configured.");
    1231            0 :     retval = GST_FLOW_ERROR;
    1232            0 :     goto exit;
    1233              :   }
    1234              : 
    1235          130 :   data_size = (guint) gst_tensor_info_get_size (self->src_spec);
    1236          130 :   if (size != data_size) {
    1237            0 :     GST_ERROR_OBJECT (self,
    1238              :         "gst_tensor_src_tizensensor_fill() requires size value (%u) to be matched with the configurations of sensors (%u).",
    1239              :         size, data_size);
    1240            0 :     retval = GST_FLOW_ERROR;
    1241            0 :     goto exit;
    1242              :   }
    1243              : 
    1244          130 :   mem = gst_buffer_peek_memory (buffer, 0);
    1245          130 :   if (!gst_memory_map (mem, &map, GST_MAP_WRITE)) {
    1246            0 :     GST_ERROR_OBJECT (self,
    1247              :         "gst_tensor_src_tizensensor_fill() cannot map the given buffer for writing data.");
    1248            0 :     retval = GST_FLOW_ERROR;
    1249            0 :     goto exit;
    1250              :   }
    1251              : 
    1252          130 :   if (self->mode == TZN_SENSOR_MODE_POLLING) {
    1253              :     sensor_event_s *event;
    1254          130 :     int count = 0;
    1255              :     gint64 duration;
    1256              :     int ret;
    1257              : 
    1258              :     /* 1. Read sensor data directly from Tizen API */
    1259          130 :     ret = sensor_listener_read_data_list (self->listener, &events, &count);
    1260          130 :     if (ret != SENSOR_ERROR_NONE || count == 0) {
    1261            0 :       GST_ERROR_OBJECT (self,
    1262              :           "Tizen sensor read failed: sensor_listener_read_data returned %d, count %d",
    1263              :           ret, count);
    1264            0 :       retval = GST_FLOW_ERROR;
    1265            0 :       goto exit_unmap;
    1266              :     }
    1267              : 
    1268          130 :     event = &events[count - 1];
    1269          130 :     src_dim = self->src_spec->dimension[0];
    1270          130 :     if (event->value_count != src_dim) {
    1271            0 :       GST_ERROR_OBJECT (self,
    1272              :           "The number of values (%d) mismatches the metadata (%d).",
    1273              :           event->value_count, src_dim);
    1274            0 :       retval = GST_FLOW_ERROR;
    1275            0 :       goto exit_unmap;
    1276              :     }
    1277              : 
    1278              :     /* 2. Do not timestamp. Let BaseSrc timestamp */
    1279          130 :     nns_logd ("read sensor_data at %" GST_TIME_FORMAT,
    1280              :         GST_TIME_ARGS (event->timestamp * 1000));
    1281              : 
    1282              :     /* 3. Set duration so that BaseSrc handles the frequency */
    1283          130 :     if (self->freq_n == 0)
    1284              :       /* 100ms */
    1285            0 :       duration = 100 * 1000 * 1000;
    1286              :     else
    1287          130 :       duration = gst_util_uint64_scale_int (GST_SECOND,
    1288              :           self->freq_d, self->freq_n);
    1289              : 
    1290          130 :     GST_BUFFER_DURATION (buffer) = duration;
    1291              : 
    1292              :     /* 4. Write values to buffer. Be careful on type casting */
    1293          130 :     _ts_assign_values (event->values, event->value_count, &map, self->src_spec);
    1294              :   } else {
    1295              :     /** NYI! */
    1296            0 :     GST_ERROR_OBJECT (self,
    1297              :         "gst_tensor_src_tizensensor_fill reached unimplemented code.");
    1298            0 :     retval = GST_FLOW_ERROR;
    1299            0 :     goto exit_unmap;
    1300              :   }
    1301              : 
    1302          130 : exit_unmap:
    1303          130 :   g_free (events);
    1304          130 :   gst_memory_unmap (mem, &map);
    1305          130 : exit:
    1306          130 :   _UNLOCK (self);
    1307          130 :   return retval;
    1308              : }
        

Generated by: LCOV version 2.0-1