LCOV - code coverage report
Current view: top level - capi-machine-learning-inference-1.8.6/c/src - ml-api-service.c (source / functions) Coverage Total Hit
Test: ML API 1.8.6-0 nnstreamer/api#7f8530c294f86ec880b29347a861499239d358a1 Lines: 87.3 % 416 363
Test Date: 2025-06-27 05:28:40 Functions: 100.0 % 23 23

            Line data    Source code
       1              : /* SPDX-License-Identifier: Apache-2.0 */
       2              : /**
       3              :  * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
       4              :  *
       5              :  * @file ml-api-service.c
       6              :  * @date 31 Aug 2022
       7              :  * @brief Some implementation of NNStreamer/Service C-API
       8              :  * @see https://github.com/nnstreamer/nnstreamer
       9              :  * @author Yongjoo Ahn <yongjoo1.ahn@samsung.com>
      10              :  * @bug No known bugs except for NYI items
      11              :  */
      12              : 
      13              : #include <nnstreamer_plugin_api_util.h>
      14              : 
      15              : #include "ml-api-service.h"
      16              : #include "ml-api-service-extension.h"
      17              : #include "ml-api-service-offloading.h"
      18              : #include "ml-api-service-query.h"
      19              : 
      20              : #define ML_SERVICE_MAGIC 0xfeeedeed
      21              : #define ML_SERVICE_MAGIC_DEAD 0xdeaddead
      22              : 
      23              : /**
      24              :  * @brief Internal function to validate ml-service handle.
      25              :  */
      26              : gboolean
      27          466 : _ml_service_handle_is_valid (ml_service_s * mls)
      28              : {
      29          466 :   if (!mls)
      30           28 :     return FALSE;
      31              : 
      32          438 :   if (mls->magic != ML_SERVICE_MAGIC)
      33           18 :     return FALSE;
      34              : 
      35          420 :   switch (mls->type) {
      36          419 :     case ML_SERVICE_TYPE_SERVER_PIPELINE:
      37              :     case ML_SERVICE_TYPE_CLIENT_QUERY:
      38              :     case ML_SERVICE_TYPE_OFFLOADING:
      39              :     case ML_SERVICE_TYPE_EXTENSION:
      40          419 :       if (mls->priv == NULL)
      41            0 :         return FALSE;
      42          419 :       break;
      43            1 :     default:
      44              :       /* Invalid handle type. */
      45            1 :       return FALSE;
      46              :   }
      47              : 
      48          419 :   return TRUE;
      49              : }
      50              : 
      51              : /**
      52              :  * @brief Internal function to set information.
      53              :  */
      54              : static int
      55           37 : _ml_service_set_information_internal (ml_service_s * mls, const char *name,
      56              :     const char *value)
      57              : {
      58           37 :   int status = ML_ERROR_NONE;
      59              : 
      60              :   /* Prevent empty string case. */
      61           37 :   if (!STR_IS_VALID (name) || !STR_IS_VALID (value))
      62            0 :     return ML_ERROR_INVALID_PARAMETER;
      63              : 
      64           37 :   status = ml_option_set (mls->information, name, g_strdup (value), g_free);
      65           37 :   if (status != ML_ERROR_NONE)
      66            0 :     return status;
      67              : 
      68           37 :   switch (mls->type) {
      69           34 :     case ML_SERVICE_TYPE_EXTENSION:
      70           34 :       status = _ml_service_extension_set_information (mls, name, value);
      71           34 :       break;
      72            3 :     case ML_SERVICE_TYPE_OFFLOADING:
      73            3 :       status = _ml_service_offloading_set_information (mls, name, value);
      74            3 :       break;
      75            0 :     default:
      76            0 :       break;
      77              :   }
      78              : 
      79           37 :   return status;
      80              : }
      81              : 
      82              : /**
      83              :  * @brief Internal function to create new ml-service handle.
      84              :  */
      85              : ml_service_s *
      86          111 : _ml_service_create_internal (ml_service_type_e ml_service_type)
      87              : {
      88              :   ml_service_s *mls;
      89              :   int status;
      90              : 
      91          111 :   mls = g_try_new0 (ml_service_s, 1);
      92          111 :   if (mls) {
      93          111 :     status = ml_option_create (&mls->information);
      94          111 :     if (status != ML_ERROR_NONE) {
      95            0 :       g_free (mls);
      96            0 :       _ml_error_report_return (NULL,
      97              :           "Failed to create ml-option handle in ml-service.");
      98              :     }
      99              : 
     100          111 :     mls->magic = ML_SERVICE_MAGIC;
     101          111 :     mls->type = ml_service_type;
     102          111 :     g_mutex_init (&mls->lock);
     103          111 :     g_cond_init (&mls->cond);
     104              :   }
     105              : 
     106          111 :   return mls;
     107              : }
     108              : 
     109              : /**
     110              :  * @brief Internal function to release ml-service handle.
     111              :  */
     112              : int
     113          111 : _ml_service_destroy_internal (ml_service_s * mls)
     114              : {
     115              :   ml_service_event_cb_info_s old_cb;
     116          111 :   int status = ML_ERROR_NONE;
     117              : 
     118          111 :   if (!mls) {
     119              :     /* Internal error? */
     120          111 :     return ML_ERROR_INVALID_PARAMETER;
     121              :   }
     122              : 
     123              :   /* Clear callback before closing internal handles. */
     124          111 :   g_mutex_lock (&mls->lock);
     125          111 :   old_cb = mls->cb_info;
     126          111 :   memset (&mls->cb_info, 0, sizeof (ml_service_event_cb_info_s));
     127          111 :   g_mutex_unlock (&mls->lock);
     128              : 
     129          111 :   switch (mls->type) {
     130           18 :     case ML_SERVICE_TYPE_SERVER_PIPELINE:
     131           18 :       status = _ml_service_pipeline_release_internal (mls);
     132           18 :       break;
     133            4 :     case ML_SERVICE_TYPE_CLIENT_QUERY:
     134            4 :       status = _ml_service_query_release_internal (mls);
     135            4 :       break;
     136           29 :     case ML_SERVICE_TYPE_OFFLOADING:
     137           29 :       status = _ml_service_offloading_release_internal (mls);
     138           29 :       break;
     139           60 :     case ML_SERVICE_TYPE_EXTENSION:
     140           60 :       status = _ml_service_extension_destroy (mls);
     141           60 :       break;
     142            0 :     default:
     143            0 :       _ml_error_report ("Invalid type of ml_service_h.");
     144            0 :       status = ML_ERROR_INVALID_PARAMETER;
     145            0 :       break;
     146              :   }
     147              : 
     148          111 :   if (status == ML_ERROR_NONE) {
     149          108 :     mls->magic = ML_SERVICE_MAGIC_DEAD;
     150          108 :     ml_option_destroy (mls->information);
     151              : 
     152          108 :     g_cond_clear (&mls->cond);
     153          108 :     g_mutex_clear (&mls->lock);
     154          108 :     g_free (mls);
     155              :   } else {
     156            3 :     _ml_error_report ("Failed to release ml-service handle, internal error?");
     157              : 
     158            3 :     g_mutex_lock (&mls->lock);
     159            3 :     mls->cb_info = old_cb;
     160            3 :     g_mutex_unlock (&mls->lock);
     161              :   }
     162              : 
     163          111 :   return status;
     164              : }
     165              : 
     166              : /**
     167              :  * @brief Internal function to get ml-service event callback.
     168              :  */
     169              : void
     170           63 : _ml_service_get_event_cb_info (ml_service_s * mls,
     171              :     ml_service_event_cb_info_s * cb_info)
     172              : {
     173           63 :   if (!mls || !cb_info)
     174            0 :     return;
     175              : 
     176           63 :   g_mutex_lock (&mls->lock);
     177           63 :   *cb_info = mls->cb_info;
     178           63 :   g_mutex_unlock (&mls->lock);
     179              : }
     180              : 
     181              : /**
     182              :  * @brief Internal function to parse string value from json.
     183              :  */
     184              : int
     185           36 : _ml_service_conf_parse_string (JsonNode * str_node, const gchar * delimiter,
     186              :     gchar ** str)
     187              : {
     188              :   guint i, n;
     189              : 
     190           36 :   if (!str_node || !delimiter || !str)
     191            0 :     return ML_ERROR_INVALID_PARAMETER;
     192              : 
     193           36 :   *str = NULL;
     194              : 
     195           36 :   if (JSON_NODE_HOLDS_ARRAY (str_node)) {
     196           34 :     JsonArray *array = json_node_get_array (str_node);
     197           34 :     GString *val = g_string_new (NULL);
     198              : 
     199           34 :     n = (array) ? json_array_get_length (array) : 0U;
     200           68 :     for (i = 0; i < n; i++) {
     201           34 :       const gchar *p = json_array_get_string_element (array, i);
     202              : 
     203              :       g_string_append (val, p);
     204           34 :       if (i < n - 1)
     205              :         g_string_append (val, delimiter);
     206              :     }
     207              : 
     208           34 :     *str = g_string_free (val, FALSE);
     209              :   } else {
     210            4 :     *str = g_strdup (json_node_get_string (str_node));
     211              :   }
     212              : 
     213           36 :   return (*str != NULL) ? ML_ERROR_NONE : ML_ERROR_INVALID_PARAMETER;
     214              : }
     215              : 
     216              : /**
     217              :  * @brief Internal function to parse tensors-info from json.
     218              :  */
     219              : int
     220           68 : _ml_service_conf_parse_tensors_info (JsonNode * info_node,
     221              :     ml_tensors_info_h * info_h)
     222              : {
     223           68 :   JsonArray *array = NULL;
     224              :   JsonObject *object;
     225              :   GstTensorsInfo info;
     226              :   GstTensorInfo *_info;
     227              :   const gchar *_str;
     228              :   guint i;
     229              :   int status;
     230              : 
     231           68 :   if (!info_node || !info_h)
     232           68 :     return ML_ERROR_INVALID_PARAMETER;
     233              : 
     234           68 :   gst_tensors_info_init (&info);
     235              : 
     236           68 :   info.num_tensors = 1;
     237           68 :   if (JSON_NODE_HOLDS_ARRAY (info_node)) {
     238           68 :     array = json_node_get_array (info_node);
     239           68 :     info.num_tensors = json_array_get_length (array);
     240              :   }
     241              : 
     242          136 :   for (i = 0; i < info.num_tensors; i++) {
     243           68 :     _info = gst_tensors_info_get_nth_info (&info, i);
     244              : 
     245           68 :     if (array)
     246           68 :       object = json_array_get_object_element (array, i);
     247              :     else
     248            0 :       object = json_node_get_object (info_node);
     249              : 
     250           68 :     if (json_object_has_member (object, "type")) {
     251           68 :       _str = json_object_get_string_member (object, "type");
     252              : 
     253           68 :       if (STR_IS_VALID (_str))
     254           68 :         _info->type = gst_tensor_get_type (_str);
     255              :     }
     256              : 
     257           68 :     if (json_object_has_member (object, "dimension")) {
     258           64 :       _str = json_object_get_string_member (object, "dimension");
     259              : 
     260           64 :       if (STR_IS_VALID (_str))
     261           64 :         gst_tensor_parse_dimension (_str, _info->dimension);
     262              :     }
     263              : 
     264           68 :     if (json_object_has_member (object, "name")) {
     265            0 :       _str = json_object_get_string_member (object, "name");
     266              : 
     267            0 :       if (STR_IS_VALID (_str))
     268            0 :         _info->name = g_strdup (_str);
     269              :     }
     270              :   }
     271              : 
     272           68 :   if (gst_tensors_info_validate (&info))
     273           64 :     status = _ml_tensors_info_create_from_gst (info_h, &info);
     274              :   else
     275            4 :     status = ML_ERROR_INVALID_PARAMETER;
     276              : 
     277           68 :   gst_tensors_info_free (&info);
     278           68 :   return status;
     279              : }
     280              : 
     281              : /**
     282              :  * @brief Internal function to get ml-service type.
     283              :  */
     284              : static ml_service_type_e
     285           91 : _ml_service_get_type (JsonObject * object)
     286              : {
     287           91 :   ml_service_type_e type = ML_SERVICE_TYPE_UNKNOWN;
     288              : 
     289              :   /** @todo add more services such as training offloading, offloading service */
     290           91 :   if (json_object_has_member (object, "single") ||
     291           52 :       json_object_has_member (object, "pipeline")) {
     292           60 :     type = ML_SERVICE_TYPE_EXTENSION;
     293           31 :   } else if (json_object_has_member (object, "offloading")) {
     294           29 :     type = ML_SERVICE_TYPE_OFFLOADING;
     295              :   }
     296              : 
     297           91 :   return type;
     298              : }
     299              : 
     300              : /**
     301              :  * @brief Creates a handle for machine learning service with configuration.
     302              :  */
     303              : int
     304           99 : ml_service_new (const char *config, ml_service_h * handle)
     305              : {
     306              :   ml_service_s *mls;
     307           99 :   ml_service_type_e service_type = ML_SERVICE_TYPE_UNKNOWN;
     308           99 :   g_autofree gchar *json_string = NULL;
     309           99 :   g_autofree gchar *contents = NULL;
     310           99 :   g_autoptr (JsonParser) parser = NULL;
     311           99 :   g_autoptr (GError) err = NULL;
     312              :   JsonNode *root;
     313              :   JsonObject *object;
     314              :   int status;
     315              : 
     316           99 :   check_feature_state (ML_FEATURE_SERVICE);
     317              : 
     318           99 :   if (!handle) {
     319            2 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     320              :         "The parameter, 'handle' (ml_service_h), is NULL. It should be a valid pointer to create new instance.");
     321              :   }
     322              : 
     323              :   /* Init null. */
     324           97 :   *handle = NULL;
     325              : 
     326           97 :   if (!STR_IS_VALID (config) ||
     327           93 :       !g_file_test (config, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
     328            6 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     329              :         "The parameter, config, is invalid. It should be a valid path.");
     330              :   }
     331              : 
     332           91 :   if (!g_file_get_contents (config, &contents, NULL, NULL)) {
     333            0 :     _ml_error_report_return (ML_ERROR_IO_ERROR,
     334              :         "Failed to read configuration file '%s'.", config);
     335              :   }
     336              : 
     337           91 :   json_string = _ml_convert_predefined_entity (contents);
     338              : 
     339           91 :   parser = json_parser_new ();
     340           91 :   if (!parser) {
     341            0 :     _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
     342              :         "Failed to parse configuration file, cannot allocate memory for JsonParser. Out of memory?");
     343              :   }
     344              : 
     345           91 :   if (!json_parser_load_from_data (parser, json_string, -1, &err)) {
     346            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     347              :         "Failed to parse configuration file. Parse error: %s",
     348              :         err ? err->message : "Unknown error");
     349              :   }
     350              : 
     351           91 :   root = json_parser_get_root (parser);
     352           91 :   if (!root) {
     353            0 :     _ml_error_report_return (ML_ERROR_IO_ERROR,
     354              :         "Failed to parse configuration file, cannot get the top node from json string.");
     355              :   }
     356              : 
     357           91 :   object = json_node_get_object (root);
     358              : 
     359           91 :   service_type = _ml_service_get_type (object);
     360           91 :   if (ML_SERVICE_TYPE_UNKNOWN == service_type) {
     361            2 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     362              :         "Failed to parse configuration file, cannot get the valid type from configuration.");
     363              :   }
     364              : 
     365              :   /* Parse each service type. */
     366           89 :   mls = _ml_service_create_internal (service_type);
     367           89 :   if (mls == NULL) {
     368            0 :     _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
     369              :         "Failed to allocate memory for the ml-service handle. Out of memory?");
     370              :   }
     371              : 
     372           89 :   switch (service_type) {
     373           60 :     case ML_SERVICE_TYPE_EXTENSION:
     374           60 :       status = _ml_service_extension_create (mls, object);
     375           60 :       break;
     376           29 :     case ML_SERVICE_TYPE_OFFLOADING:
     377           29 :       status = _ml_service_offloading_create (mls, object);
     378           29 :       break;
     379            0 :     default:
     380              :       /* Invalid handle type. */
     381            0 :       status = ML_ERROR_NOT_SUPPORTED;
     382            0 :       break;
     383              :   }
     384              : 
     385           89 :   if (status != ML_ERROR_NONE)
     386           12 :     goto error;
     387              : 
     388              :   /* Parse information. */
     389           77 :   if (json_object_has_member (object, "information")) {
     390           15 :     JsonObject *info = json_object_get_object_member (object, "information");
     391           15 :     g_autoptr (GList) members = json_object_get_members (info);
     392              :     GList *iter;
     393              : 
     394           47 :     for (iter = members; iter; iter = g_list_next (iter)) {
     395           32 :       const gchar *name = iter->data;
     396           32 :       const gchar *value = _ml_service_get_json_string_member (info, name);
     397              : 
     398           32 :       status = _ml_service_set_information_internal (mls, name, value);
     399           32 :       if (status != ML_ERROR_NONE)
     400            0 :         goto error;
     401              :     }
     402              :   }
     403              : 
     404           62 : error:
     405           89 :   if (status == ML_ERROR_NONE) {
     406           77 :     *handle = mls;
     407              :   } else {
     408           12 :     _ml_error_report ("Failed to open the ml-service configuration.");
     409           12 :     _ml_service_destroy_internal (mls);
     410              :   }
     411              : 
     412           89 :   return status;
     413              : }
     414              : 
     415              : /**
     416              :  * @brief Sets the callbacks which will be invoked when a new event occurs from ml-service.
     417              :  */
     418              : int
     419           40 : ml_service_set_event_cb (ml_service_h handle, ml_service_event_cb cb,
     420              :     void *user_data)
     421              : {
     422           40 :   ml_service_s *mls = (ml_service_s *) handle;
     423              : 
     424           40 :   check_feature_state (ML_FEATURE_SERVICE);
     425              : 
     426           40 :   if (!_ml_service_handle_is_valid (mls)) {
     427            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     428              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     429              :   }
     430              : 
     431           36 :   g_mutex_lock (&mls->lock);
     432              : 
     433           36 :   mls->cb_info.cb = cb;
     434           36 :   mls->cb_info.pdata = user_data;
     435              : 
     436           36 :   g_mutex_unlock (&mls->lock);
     437              : 
     438           36 :   return ML_ERROR_NONE;
     439              : }
     440              : 
     441              : /**
     442              :  * @brief Starts the process of ml-service.
     443              :  */
     444              : int
     445           17 : ml_service_start (ml_service_h handle)
     446              : {
     447           17 :   ml_service_s *mls = (ml_service_s *) handle;
     448           17 :   int status = ML_ERROR_NONE;
     449              : 
     450           17 :   check_feature_state (ML_FEATURE_SERVICE);
     451              : 
     452           17 :   if (!_ml_service_handle_is_valid (mls)) {
     453            5 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     454              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     455              :   }
     456              : 
     457           12 :   switch (mls->type) {
     458            8 :     case ML_SERVICE_TYPE_SERVER_PIPELINE:
     459              :     {
     460            8 :       _ml_service_server_s *server = (_ml_service_server_s *) mls->priv;
     461              : 
     462            8 :       status = ml_agent_pipeline_start (server->id);
     463            8 :       if (status < 0)
     464            2 :         _ml_error_report ("Failed to invoke the method start_pipeline.");
     465              : 
     466            8 :       break;
     467              :     }
     468            2 :     case ML_SERVICE_TYPE_EXTENSION:
     469            2 :       status = _ml_service_extension_start (mls);
     470            2 :       break;
     471            2 :     case ML_SERVICE_TYPE_OFFLOADING:
     472            2 :       status = _ml_service_offloading_start (mls);
     473            2 :       break;
     474            0 :     default:
     475              :       /* Invalid handle type. */
     476            0 :       status = ML_ERROR_NOT_SUPPORTED;
     477            0 :       break;
     478              :   }
     479              : 
     480           12 :   return status;
     481              : }
     482              : 
     483              : /**
     484              :  * @brief Stops the process of ml-service.
     485              :  */
     486              : int
     487           15 : ml_service_stop (ml_service_h handle)
     488              : {
     489           15 :   ml_service_s *mls = (ml_service_s *) handle;
     490           15 :   int status = ML_ERROR_NONE;
     491              : 
     492           15 :   check_feature_state (ML_FEATURE_SERVICE);
     493              : 
     494           15 :   if (!_ml_service_handle_is_valid (mls)) {
     495            5 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     496              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     497              :   }
     498              : 
     499           10 :   switch (mls->type) {
     500            6 :     case ML_SERVICE_TYPE_SERVER_PIPELINE:
     501              :     {
     502            6 :       _ml_service_server_s *server = (_ml_service_server_s *) mls->priv;
     503              : 
     504            6 :       status = ml_agent_pipeline_stop (server->id);
     505            6 :       if (status < 0)
     506            2 :         _ml_error_report ("Failed to invoke the method stop_pipeline.");
     507              : 
     508            6 :       break;
     509              :     }
     510            2 :     case ML_SERVICE_TYPE_EXTENSION:
     511            2 :       status = _ml_service_extension_stop (mls);
     512            2 :       break;
     513            2 :     case ML_SERVICE_TYPE_OFFLOADING:
     514            2 :       status = _ml_service_offloading_stop (mls);
     515            2 :       break;
     516            0 :     default:
     517              :       /* Invalid handle type. */
     518            0 :       status = ML_ERROR_NOT_SUPPORTED;
     519            0 :       break;
     520              :   }
     521              : 
     522           10 :   return status;
     523              : }
     524              : 
     525              : /**
     526              :  * @brief Gets the information of required input data.
     527              :  */
     528              : int
     529           32 : ml_service_get_input_information (ml_service_h handle, const char *name,
     530              :     ml_tensors_info_h * info)
     531              : {
     532           32 :   ml_service_s *mls = (ml_service_s *) handle;
     533              :   int status;
     534              : 
     535           32 :   check_feature_state (ML_FEATURE_SERVICE);
     536              : 
     537           32 :   if (!_ml_service_handle_is_valid (mls)) {
     538            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     539              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     540              :   }
     541              : 
     542           28 :   if (!info) {
     543            2 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     544              :         "The parameter, info (ml_tensors_info_h), is NULL. It should be a valid pointer to create new instance.");
     545              :   }
     546              : 
     547              :   /* Init null. */
     548           26 :   *info = NULL;
     549              : 
     550           26 :   switch (mls->type) {
     551           26 :     case ML_SERVICE_TYPE_EXTENSION:
     552           26 :       status = _ml_service_extension_get_input_information (mls, name, info);
     553           26 :       break;
     554            0 :     default:
     555              :       /* Invalid handle type. */
     556            0 :       status = ML_ERROR_NOT_SUPPORTED;
     557            0 :       break;
     558              :   }
     559              : 
     560           26 :   if (status != ML_ERROR_NONE) {
     561            8 :     if (*info) {
     562            0 :       ml_tensors_info_destroy (*info);
     563            0 :       *info = NULL;
     564              :     }
     565              :   }
     566              : 
     567           26 :   return status;
     568              : }
     569              : 
     570              : /**
     571              :  * @brief Gets the information of output data.
     572              :  */
     573              : int
     574           24 : ml_service_get_output_information (ml_service_h handle, const char *name,
     575              :     ml_tensors_info_h * info)
     576              : {
     577           24 :   ml_service_s *mls = (ml_service_s *) handle;
     578              :   int status;
     579              : 
     580           24 :   check_feature_state (ML_FEATURE_SERVICE);
     581              : 
     582           24 :   if (!_ml_service_handle_is_valid (mls)) {
     583            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     584              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     585              :   }
     586              : 
     587           20 :   if (!info) {
     588            2 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     589              :         "The parameter, info (ml_tensors_info_h), is NULL. It should be a valid pointer to create new instance.");
     590              :   }
     591              : 
     592              :   /* Init null. */
     593           18 :   *info = NULL;
     594              : 
     595           18 :   switch (mls->type) {
     596           18 :     case ML_SERVICE_TYPE_EXTENSION:
     597           18 :       status = _ml_service_extension_get_output_information (mls, name, info);
     598           18 :       break;
     599            0 :     default:
     600              :       /* Invalid handle type. */
     601            0 :       status = ML_ERROR_NOT_SUPPORTED;
     602            0 :       break;
     603              :   }
     604              : 
     605           18 :   if (status != ML_ERROR_NONE) {
     606            8 :     if (*info) {
     607            0 :       ml_tensors_info_destroy (*info);
     608            0 :       *info = NULL;
     609              :     }
     610              :   }
     611              : 
     612           18 :   return status;
     613              : }
     614              : 
     615              : /**
     616              :  * @brief Sets the information for ml-service.
     617              :  */
     618              : int
     619           17 : ml_service_set_information (ml_service_h handle, const char *name,
     620              :     const char *value)
     621              : {
     622           17 :   ml_service_s *mls = (ml_service_s *) handle;
     623              :   int status;
     624              : 
     625           17 :   check_feature_state (ML_FEATURE_SERVICE);
     626              : 
     627           17 :   if (!_ml_service_handle_is_valid (mls)) {
     628            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     629              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     630              :   }
     631              : 
     632           13 :   if (!STR_IS_VALID (name)) {
     633            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     634              :         "The parameter, name '%s', is invalid.", name);
     635              :   }
     636              : 
     637            9 :   if (!STR_IS_VALID (value)) {
     638            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     639              :         "The parameter, value '%s', is invalid.", value);
     640              :   }
     641              : 
     642            5 :   g_mutex_lock (&mls->lock);
     643            5 :   status = _ml_service_set_information_internal (mls, name, value);
     644            5 :   g_mutex_unlock (&mls->lock);
     645              : 
     646            5 :   if (status != ML_ERROR_NONE) {
     647            0 :     _ml_error_report_return (status,
     648              :         "Failed to set the information '%s'.", name);
     649              :   }
     650              : 
     651            5 :   return ML_ERROR_NONE;
     652              : }
     653              : 
     654              : /**
     655              :  * @brief Gets the information from ml-service.
     656              :  */
     657              : int
     658           18 : ml_service_get_information (ml_service_h handle, const char *name, char **value)
     659              : {
     660           18 :   ml_service_s *mls = (ml_service_s *) handle;
     661           18 :   gchar *val = NULL;
     662              :   int status;
     663              : 
     664           36 :   check_feature_state (ML_FEATURE_SERVICE);
     665              : 
     666           18 :   if (!_ml_service_handle_is_valid (mls)) {
     667            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     668              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     669              :   }
     670              : 
     671           14 :   if (!STR_IS_VALID (name)) {
     672            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     673              :         "The parameter, name '%s', is invalid.", name);
     674              :   }
     675              : 
     676           10 :   if (!value) {
     677            2 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     678              :         "The parameter, value, is NULL. It should be a valid pointer.");
     679              :   }
     680              : 
     681            8 :   g_mutex_lock (&mls->lock);
     682            8 :   status = ml_option_get (mls->information, name, (void **) (&val));
     683            8 :   g_mutex_unlock (&mls->lock);
     684              : 
     685            8 :   if (status != ML_ERROR_NONE) {
     686            2 :     _ml_error_report_return (status,
     687              :         "The ml-service handle does not include the information '%s'.", name);
     688              :   }
     689              : 
     690            6 :   *value = g_strdup (val);
     691            6 :   return ML_ERROR_NONE;
     692              : }
     693              : 
     694              : /**
     695              :  * @brief Adds an input data to process the model in ml-service extension handle.
     696              :  */
     697              : int
     698           92 : ml_service_request (ml_service_h handle, const char *name,
     699              :     const ml_tensors_data_h data)
     700              : {
     701           92 :   ml_service_s *mls = (ml_service_s *) handle;
     702              :   int status;
     703              : 
     704           92 :   check_feature_state (ML_FEATURE_SERVICE);
     705              : 
     706           92 :   if (!_ml_service_handle_is_valid (mls)) {
     707            4 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     708              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     709              :   }
     710              : 
     711           88 :   if (!data) {
     712            2 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     713              :         "The parameter, data (ml_tensors_data_h), is NULL. It should be a valid ml_tensor_data_h instance, which is usually created by ml_tensors_data_create().");
     714              :   }
     715              : 
     716           86 :   switch (mls->type) {
     717           72 :     case ML_SERVICE_TYPE_EXTENSION:
     718           72 :       status = _ml_service_extension_request (mls, name, data);
     719           72 :       break;
     720           14 :     case ML_SERVICE_TYPE_OFFLOADING:
     721           14 :       status = _ml_service_offloading_request (mls, name, data);
     722           14 :       break;
     723            0 :     default:
     724              :       /* Invalid handle type. */
     725            0 :       status = ML_ERROR_NOT_SUPPORTED;
     726            0 :       break;
     727              :   }
     728              : 
     729           86 :   return status;
     730              : }
     731              : 
     732              : /**
     733              :  * @brief Destroys the handle for machine learning service.
     734              :  */
     735              : int
     736           98 : ml_service_destroy (ml_service_h handle)
     737              : {
     738           98 :   ml_service_s *mls = (ml_service_s *) handle;
     739              : 
     740           98 :   check_feature_state (ML_FEATURE_SERVICE);
     741              : 
     742           98 :   if (!_ml_service_handle_is_valid (mls)) {
     743            7 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     744              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance, which is usually created by ml_service_new().");
     745              :   }
     746              : 
     747           91 :   return _ml_service_destroy_internal (mls);
     748              : }
     749              : 
     750              : /**
     751              :  * @brief Creates query client service handle with given ml-option handle.
     752              :  */
     753              : int
     754            6 : ml_service_query_create (ml_option_h option, ml_service_h * handle)
     755              : {
     756              :   ml_service_s *mls;
     757              :   int status;
     758              : 
     759            6 :   check_feature_state (ML_FEATURE_SERVICE);
     760            6 :   check_feature_state (ML_FEATURE_INFERENCE);
     761              : 
     762            6 :   if (!option) {
     763            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     764              :         "The parameter, 'option' is NULL. It should be a valid ml_option_h, which should be created by ml_option_create().");
     765              :   }
     766              : 
     767            5 :   if (!handle) {
     768            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     769              :         "The parameter, 'handle' (ml_service_h), is NULL. It should be a valid ml_service_h.");
     770              :   }
     771              : 
     772            4 :   mls = _ml_service_create_internal (ML_SERVICE_TYPE_CLIENT_QUERY);
     773            4 :   if (mls == NULL) {
     774            0 :     _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
     775              :         "Failed to allocate memory for the service handle. Out of memory?");
     776              :   }
     777              : 
     778            4 :   status = _ml_service_query_create (mls, option);
     779              : 
     780            4 :   if (status == ML_ERROR_NONE) {
     781            2 :     *handle = mls;
     782              :   } else {
     783            2 :     _ml_error_report ("Failed to create ml-service for query.");
     784            2 :     _ml_service_destroy_internal (mls);
     785              :   }
     786              : 
     787            4 :   return status;
     788              : }
     789              : 
     790              : /**
     791              :  * @brief Requests query client service an output with given input data.
     792              :  */
     793              : int
     794           13 : ml_service_query_request (ml_service_h handle, const ml_tensors_data_h input,
     795              :     ml_tensors_data_h * output)
     796              : {
     797           13 :   ml_service_s *mls = (ml_service_s *) handle;
     798              : 
     799           13 :   check_feature_state (ML_FEATURE_SERVICE);
     800           13 :   check_feature_state (ML_FEATURE_INFERENCE);
     801              : 
     802           13 :   if (!_ml_service_handle_is_valid (mls)) {
     803            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     804              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance.");
     805              :   }
     806              : 
     807           12 :   if (!input) {
     808            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     809              :         "The parameter, 'input' (ml_tensors_data_h), is NULL. It should be a valid ml_tensors_data_h.");
     810              :   }
     811              : 
     812           11 :   if (!output) {
     813            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     814              :         "The parameter, 'output' (ml_tensors_data_h *), is NULL. It should be a valid pointer to an instance of ml_tensors_data_h.");
     815              :   }
     816              : 
     817           10 :   return _ml_service_query_request (mls, input, output);
     818              : }
     819              : 
     820              : /**
     821              :  * @brief Internal function to get json string member.
     822              :  */
     823              : const gchar *
     824          394 : _ml_service_get_json_string_member (JsonObject * object,
     825              :     const gchar * member_name)
     826              : {
     827          394 :   const gchar *ret = NULL;
     828              : 
     829          394 :   if (!object) {
     830            0 :     _ml_error_report_return (ret,
     831              :         "The parameter, object (JsonObject *), is NULL. It should be a valid JsonObject instance.");
     832              :   }
     833              : 
     834          394 :   if (!member_name) {
     835            0 :     _ml_error_report_return (ret,
     836              :         "The parameter, member_name (const gchar *), is NULL.");
     837              :   }
     838              : 
     839          394 :   if (json_object_has_member (object, member_name)) {
     840          361 :     ret = json_object_get_string_member (object, member_name);
     841              :   }
     842              : 
     843          394 :   return ret;
     844              : }
     845              : 
     846              : /**
     847              :  * @brief Generating an ML service event and passing received data and event to
     848              :  * a registered callback function.
     849              :  */
     850              : int
     851           46 : _ml_service_invoke_event_new_data (ml_service_s * mls, const char *name,
     852              :     const ml_tensors_data_h data)
     853              : {
     854           46 :   ml_service_event_cb_info_s cb_info = { 0 };
     855           46 :   ml_information_h ml_info = NULL;
     856           46 :   int status = ML_ERROR_NONE;
     857              : 
     858           46 :   if (!mls || !data) {
     859           46 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     860              :         "Failed to create ml-service event data, invalid parameter.");
     861              :   }
     862              : 
     863           46 :   _ml_service_get_event_cb_info (mls, &cb_info);
     864              : 
     865           46 :   if (cb_info.cb) {
     866              :     /* Create information handle for ml-service event. */
     867           36 :     status = _ml_information_create (&ml_info);
     868           36 :     if (status != ML_ERROR_NONE)
     869            0 :       goto done;
     870              : 
     871           36 :     if (name) {
     872           11 :       status = _ml_information_set (ml_info, "name", (void *) name, NULL);
     873           11 :       if (status != ML_ERROR_NONE)
     874            0 :         goto done;
     875              :     }
     876              : 
     877           36 :     status = _ml_information_set (ml_info, "data", (void *) data, NULL);
     878           36 :     if (status != ML_ERROR_NONE)
     879            0 :       goto done;
     880              : 
     881           36 :     cb_info.cb (ML_SERVICE_EVENT_NEW_DATA, ml_info, cb_info.pdata);
     882              :   }
     883              : 
     884           10 : done:
     885           46 :   if (ml_info)
     886           36 :     ml_information_destroy (ml_info);
     887              : 
     888           46 :   if (status != ML_ERROR_NONE) {
     889            0 :     _ml_error_report ("Failed to invoke 'new data' event.");
     890              :   }
     891              : 
     892           46 :   return status;
     893              : }
     894              : 
     895              : /**
     896              :  * @brief Callback for sink node in pipeline description.
     897              :  * Processes incoming data from pipeline sink element and forwards it to
     898              :  * _ml_service_invoke_event_new_data().
     899              :  */
     900              : void
     901           14 : _ml_service_pipeline_sink_cb (const ml_tensors_data_h data,
     902              :     const ml_tensors_info_h info, void *user_data)
     903              : {
     904           14 :   ml_service_s *mls = NULL;
     905           14 :   ml_service_node_info_s *node_info = NULL;
     906              : 
     907           14 :   node_info = (ml_service_node_info_s *) user_data;
     908           14 :   g_return_if_fail (node_info != NULL);
     909           14 :   mls = (ml_service_s *) node_info->mls;
     910           14 :   g_return_if_fail (mls != NULL);
     911              : 
     912           14 :   _ml_service_invoke_event_new_data (mls, node_info->name, data);
     913              : }
        

Generated by: LCOV version 2.0-1