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