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