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 : }
|