From: sooyeon.kim Date: Fri, 31 Aug 2018 07:05:51 +0000 (+0900) Subject: [ACR-1294] Add the initial version of multi-assistant X-Git-Tag: submit/tizen/20180921.100546^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=26b3a71ab46dcc13fa12bbe0ae4b336210ae654e;p=platform%2Fcore%2Fuifw%2Fmulti-assistant.git [ACR-1294] Add the initial version of multi-assistant Change-Id: I034a1baf9e5ef49f8c8ea7b85492045752b89ea6 Signed-off-by: sooyeon.kim --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..f3d4e38 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +Sehwan Park +WonNam Jang +Sooyeon Kim +Suyeon Hwang +Seongrae Jo diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cf1a85c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,74 @@ +# +# Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an AS IS BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Sooyeon Kim (sooyeon.kim@samsung.com) +# @version 0.0.1 +# @brief + +# Check minimum CMake version +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +# Project name +PROJECT(ma) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(EXEC_PREFIX "${PREFIX}") +SET(VERSION 0.0.1) + +FIND_PROGRAM(UNAME NAMES uname) +EXEC_PROGRAM("${UNAME}" ARGS "-m" OUTPUT_VARIABLE "ARCH") + +ADD_DEFINITIONS("-Werror") + +# pkg config tool +INCLUDE(FindPkgConfig) + +## Include common directory ## +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/common") +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include") + +## Dependent packages ## +INCLUDE(FindPkgConfig) +IF("${_TV_PRODUCT}" STREQUAL "TRUE") +pkg_check_modules(pkgs REQUIRED + capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wayland + capi-network-bluetooth capi-network-bluetooth-tv capi-system-info cynara-client cynara-session dbus-1 dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 vconf +) +ELSE() +pkg_check_modules(pkgs REQUIRED + capi-base-common capi-media-audio-io capi-media-sound-manager ecore-wayland + capi-system-info cynara-client cynara-session dbus-1 dlog ecore glib-2.0 json-glib-1.0 libgum libtzplatform-config libxml-2.0 vconf +) +ENDIF() + + +## API ## +ADD_SUBDIRECTORY(include) + +## Client library ## +ADD_SUBDIRECTORY(client) + +## Server daemon ## +#ADD_SUBDIRECTORY(server) + +## config ## +INSTALL(FILES ${CMAKE_SOURCE_DIR}/ma-config.xml DESTINATION ${TZ_SYS_RO_SHARE}/multiassistant/ma/1.0) + +INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.multiassistant.maclient.service DESTINATION ${TZ_SYS_RO_SHARE}/dbus-1/services) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/org.tizen.multiassistant.mauiclient.service DESTINATION ${TZ_SYS_RO_SHARE}/dbus-1/services) + +INSTALL(FILES ${CMAKE_SOURCE_DIR}/ma-server.conf DESTINATION /etc/dbus-1/session.d) + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..9424bf6 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) 2012-2015 Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE file for Apache License terms and conditions. diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 0000000..648c023 --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,31 @@ +SET(SRCS + ma.c + ma_client.c + ma_dbus.c + ../common/ma_config_mgr.c +) + +SET(UI_SRCS + ma_ui.c + ma_ui_client.c + ma_ui_dbus.c + ../common/ma_config_mgr.c +) + +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +## multi assistant library ## +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS}) + +## multi assistant ui library ## +ADD_LIBRARY("${PROJECT_NAME}_ui" SHARED ${UI_SRCS}) +TARGET_LINK_LIBRARIES("${PROJECT_NAME}_ui" ${pkgs_LDFLAGS}) + +## Install library files ## +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIBDIR} COMPONENT RuntimeLibraries) +INSTALL(TARGETS "${PROJECT_NAME}_ui" DESTINATION ${LIBDIR} COMPONENT RuntimeLibraries) diff --git a/client/ma.c b/client/ma.c new file mode 100644 index 0000000..2078808 --- /dev/null +++ b/client/ma.c @@ -0,0 +1,960 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include + + +#include "multi_assistant.h" +#include "ma_dbus.h" +#include "ma_client.h" +#include "ma_main.h" +#include "ma_defs.h" + + + +static ma_h g_ma = NULL; + + +//static int g_feature_enabled = -1; +static int g_privilege_allowed = -1; +static cynara *p_cynara = NULL; + +static void __ma_notify_state_changed(void* data); +static void __ma_notify_error(void* data); + +//static void __ma_lang_changed_cb(const char* previous_lang, const char* current_lang); + +static int __ma_get_feature_enabled() +{ + return 0; +/* + if (0 == g_feature_enabled) { + //LCOV_EXCL_START + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Multi-assistant feature NOT supported"); + return MA_ERROR_NOT_SUPPORTED; + //LCOV_EXCL_STOP + } else if (-1 == g_feature_enabled) { + bool ma_supported = false; + bool mic_supported = false; + if (0 == system_info_get_platform_bool(MA_FEATURE_PATH, &ma_supported)) { + if (0 == system_info_get_platform_bool(MA_MIC_FEATURE_PATH, &mic_supported)) { + if (false == ma_supported || false == mic_supported) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Multi-assistant feature NOT supported"); + g_feature_enabled = 0; + return MA_ERROR_NOT_SUPPORTED; + } + + g_feature_enabled = 1; + } else { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to get feature value"); //LCOV_EXCL_LINE + return MA_ERROR_NOT_SUPPORTED; + } + } else { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to get feature value"); //LCOV_EXCL_LINE + return MA_ERROR_NOT_SUPPORTED; + } + } +*/ + return 0; +} + +static int __check_privilege_initialize() +{ + int ret = cynara_initialize(&p_cynara, NULL); + if (CYNARA_API_SUCCESS != ret) + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] fail to initialize"); //LCOV_EXCL_LINE + + return ret == CYNARA_API_SUCCESS; +} + +static int __check_privilege(const char* uid, const char * privilege) +{ + FILE *fp = NULL; + char label_path[1024] = "/proc/self/attr/current"; + char smack_label[1024] = {'\0',}; + + if (!p_cynara) { + return false; + } + + fp = fopen(label_path, "r"); + if (fp != NULL) { + if (0 >= fread(smack_label, 1, sizeof(smack_label), fp)) + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] fail to fread"); //LCOV_EXCL_LINE + + fclose(fp); + } + + pid_t pid = getpid(); + char *session = cynara_session_from_pid(pid); + int ret = cynara_check(p_cynara, smack_label, session, uid, privilege); + SLOG(LOG_DEBUG, TAG_MAC, "[Client]cynara_check returned %d(%s)", ret, (CYNARA_API_ACCESS_ALLOWED == ret) ? "Allowed" : "Denied"); + if (session) + free(session); + + if (ret != CYNARA_API_ACCESS_ALLOWED) + return false; + return true; +} + +static void __check_privilege_deinitialize() +{ + if (p_cynara) + cynara_finish(p_cynara); + p_cynara = NULL; +} + +static int __ma_check_privilege() +{ + char uid[16]; + + if (0 == g_privilege_allowed) { + //LCOV_EXCL_START + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Permission is denied"); + return MA_ERROR_PERMISSION_DENIED; + //LCOV_EXCL_STOP + } else if (-1 == g_privilege_allowed) { + if (false == __check_privilege_initialize()) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] privilege initialize is failed"); //LCOV_EXCL_LINE + return MA_ERROR_PERMISSION_DENIED; + } + snprintf(uid, 16, "%d", getuid()); + if (false == __check_privilege(uid, MA_PRIVILEGE)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Permission is denied"); + g_privilege_allowed = 0; + __check_privilege_deinitialize(); + return MA_ERROR_PERMISSION_DENIED; + } + __check_privilege_deinitialize(); + } + + g_privilege_allowed = 1; + return MA_ERROR_NONE; +} + + +int ma_initialize(void) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Initialize"); + + + /* check handle */ + if (true == ma_client_is_valid(g_ma)) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Already initialized"); //LCOV_EXCL_LINE + return MA_ERROR_NONE; //LCOV_EXCL_LINE + } + + if (0 < ma_client_get_count()) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Already initialized"); //LCOV_EXCL_LINE + return MA_ERROR_NONE; //LCOV_EXCL_LINE + } + + if (0 != ma_dbus_open_connection()) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to open connection"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE + } + + if (0 != ma_client_create(&g_ma)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to create client!!!!!"); //LCOV_EXCL_LINE + return MA_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE + } +/* + int ret = ma_config_mgr_initialize(g_ma->handle); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to init config manager"); //LCOV_EXCL_LINE + ma_client_destroy(g_ma); //LCOV_EXCL_LINE + return ret; //LCOV_EXCL_LINE + } + + ret = ma_config_mgr_set_lang_cb(g_ma->handle, __ma_lang_changed_cb); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to set config changed : %d", ret); //LCOV_EXCL_LINE + ma_config_mgr_deinitialize(g_ma->handle); //LCOV_EXCL_LINE + ma_client_destroy(g_ma); //LCOV_EXCL_LINE + return ret; + } +*/ + return MA_ERROR_NONE; +} + +static void __ma_internal_unprepare(void) +{ + int ret = ma_dbus_request_deinitialize(g_ma->handle); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to request finalize"); //LCOV_EXCL_LINE + } + + return; +} + +int ma_deinitialize(void) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Deinitialize"); + + if (false == ma_client_is_valid(g_ma)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] NOT initialized"); + return MA_ERROR_INVALID_STATE; + } + + ma_state_e state; + ma_client_get_client_state(g_ma, &state); + + /* check state */ + switch (state) { + case MA_STATE_READY: + __ma_internal_unprepare(); + /* no break. need to next step*/ + case MA_STATE_INITIALIZED: +// ma_config_mgr_unset_lang_cb(g_ma->handle); +// ma_config_mgr_deinitialize(g_ma->handle); + + /* Free client resources */ + ma_client_destroy(g_ma); + g_ma = NULL; + break; + case MA_STATE_NONE: + break; + } + + SLOG(LOG_DEBUG, TAG_MAC, "Success: destroy"); + + if (0 != ma_dbus_close_connection()) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to close connection"); //LCOV_EXCL_LINE + } + + return MA_ERROR_NONE; +} + +static Eina_Bool __ma_connect_daemon(void *data) +{ + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Connect daemon"); + + /* request initialization */ + int ret = -1; + int ui_pid = -1; + + /* check handle */ + if (true == ma_client_is_valid(g_ma)) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] g_ma is valid"); + + ret = ma_dbus_request_initialize(g_ma->handle); + //LCOV_EXCL_START + if (MA_ERROR_ENGINE_NOT_FOUND == ret) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to initialize"); + + ma_client_set_error(g_ma, MA_ERROR_ENGINE_NOT_FOUND); + ecore_main_loop_thread_safe_call_async(__ma_notify_error, (void*)g_ma); + + return EINA_FALSE; + //LCOV_EXCL_STOP + } else if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to initialize"); //LCOV_EXCL_LINE + + ma_client_set_error(g_ma, MA_ERROR_TIMED_OUT); + ecore_main_loop_thread_safe_call_async(__ma_notify_error, (void*)g_ma); + + return EINA_TRUE; + } else { + /* Success to connect */ + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Success to connect daemon"); + } + + ma_client_set_client_state(g_ma, MA_STATE_READY); + ecore_main_loop_thread_safe_call_async(__ma_notify_state_changed, (void*)g_ma); + + ma_client_set_ui_pid(g_ma, ui_pid); + } else { + SLOG(LOG_ERROR, TAG_MAC, "[Not ERROR] g_ma is not valid. It is destroyed."); //LCOV_EXCL_LINE + return EINA_FALSE; + } + + return EINA_FALSE; +} + +static void __start_prepare_thread(void *data, Ecore_Thread *thread) +{ + SLOG(LOG_ERROR, TAG_MAC, "[DEBUG] Start prepare thread"); + int ret = -1; + int retry_count = 0; + + /* Send hello */ + while (0 != ret) { + if (retry_count == 10) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to request hello !!"); //LCOV_EXCL_LINE + return; + } + + ret = ma_dbus_request_hello(); + if (ret == 0) { + SLOG(LOG_DEBUG, TAG_MAC, "Success to request hello. retry count(%d)", retry_count); + break; + } else { + retry_count++; + } + } + + ret = -1; + retry_count = 0; + while (0 != ret) { + if (retry_count == 10) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to connect daemon !!"); //LCOV_EXCL_LINE + return; + } + ret = __ma_connect_daemon(NULL); + if (ret == 0) { + SLOG(LOG_DEBUG, TAG_MAC, "Success to connect daemon. retry count(%d)", retry_count); + break; + } else { + retry_count++; + } + } + + return; +} + +static void __end_prepare_thread(void *data, Ecore_Thread *thread) +{ + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] End prepare thread"); +} + +int ma_prepare(void) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Prepare"); + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized' (%d)", state); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ecore_thread_run(__start_prepare_thread, __end_prepare_thread, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_unprepare(void) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Unprepare"); + + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_READY) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'READY' (%d)", state); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + __ma_internal_unprepare(); + + ma_client_set_client_state(g_ma, MA_STATE_INITIALIZED); + ecore_main_loop_thread_safe_call_async(__ma_notify_state_changed, (void*)g_ma); + + return MA_ERROR_NONE; +} + +static void __ma_notify_state_changed(void * data) +{ + ma_h ma = (ma_h)data; + + ma_state_changed_cb callback = NULL; + void* user_data; + + ma_client_get_state_changed_cb(ma, &callback, &user_data); + + ma_state_e current_state; + ma_state_e previous_state; + + ma_client_get_previous_state(ma, ¤t_state, &previous_state); + + if (NULL != callback) { + ma_client_use_callback(ma); + callback(previous_state, current_state, user_data); + ma_client_not_use_callback(ma); + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] State changed callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[WARNING] State changed callback is NULL"); + } +} + +int __ma_cb_audio_streaming(int event, char* buffer, int len) +{ + ma_audio_streaming_cb callback = NULL; + void* user_data; + + ma_client_get_audio_streaming_cb(g_ma, &callback, &user_data); + + if (NULL != callback) { + ma_client_use_callback(g_ma); + callback((ma_audio_streaming_event_e)event, buffer, len, user_data); + ma_client_not_use_callback(g_ma); + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Audio streaming callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[WARNING] Audio streaming callback is NULL"); + } + + return 0; +} + +int __ma_cb_error(int reason, char* msg) +{ + ma_state_e state; + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid client"); + return MA_ERROR_INVALID_PARAMETER; + } + + /* check state */ + if (state != MA_STATE_READY) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Current state is not 'READY'"); //LCOV_EXCL_LINE + if (MA_ERROR_SERVICE_RESET != reason) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] client is not connected yet"); + return MA_ERROR_INVALID_STATE; + } + return MA_ERROR_NONE; + } + + if (MA_ERROR_SERVICE_RESET == reason) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] multi-assistant service reset"); + + ma_client_set_client_state(g_ma, MA_STATE_INITIALIZED); + ecore_main_loop_thread_safe_call_async(__ma_notify_state_changed, (void*)g_ma); + + if (0 != ma_prepare()) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to prepare"); + } + } + + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Error reason(%d), msg(%s)", reason, msg); + + ma_client_set_error(g_ma, reason); + ecore_main_loop_thread_safe_call_async(__ma_notify_error, (void*)g_ma); + + return MA_ERROR_NONE; +} + +static void __ma_notify_error(void* data) +{ + ma_h ma = (ma_h)data; + + ma_error_cb callback = NULL; + void* user_data; + int reason; + + ma_client_get_error_cb(ma, &callback, &user_data); + ma_client_get_error(ma, &reason); + + if (NULL != callback) { + ma_client_use_callback(ma); + callback(reason, user_data); + ma_client_not_use_callback(ma); + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Error callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[WARNING] Error callback is NULL"); + } +} + +/* +static void __ma_lang_changed_cb(const char* previous_lang, const char* current_lang) +{ + ma_language_changed_cb callback = NULL; + void* user_data; + + ma_client_get_lang_changed_cb(g_ma, &callback, user_data); + + if (NULL != callback) { + ma_client_use_callback(g_ma); + callback(previous_lang, current_lang, user_data); + ma_client_not_use_callback(g_ma); + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Language changed callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[WARNING] Language changed callback is NULL"); + } +} +*/ + +int ma_get_state(ma_state_e* state) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Get current state"); + + if (NULL == state) { + SLOG(LOG_ERROR, TAG_MAC, "[Client ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + + ma_state_e tmp_state; + if (0 != ma_client_get_client_state(g_ma, &tmp_state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + *state = tmp_state; + + return MA_ERROR_NONE; +} + +int ma_get_current_language(char** language) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Get current language"); + + + if (NULL == language) { + SLOG(LOG_ERROR, TAG_MAC, "[Client ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + int ret = -1; +/* ret = ma_config_mgr_get_default_language(language); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAC, "[Client ERROR] Fail to get current language"); + } +*/ + ret = 0; + return ret; +} + +int ma_get_recording_audio_format(int *rate, ma_audio_channel_e *channel, ma_audio_type_e *audio_type) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + ma_state_e state; + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_READY) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'READY'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Get recording audio format"); + + int count = 0; + int ret = -1; + int pid = getpid(); + do { + ret = ma_dbus_get_recording_audio_format(pid, rate, channel, audio_type); + if (0 != ret) { + if (MA_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to get audio format"); + break; + } else { + SLOG(LOG_WARN, TAG_MAC, "[WARNING] Retry to get audio format"); + usleep(10000); + count++; + if (MA_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to get audio format"); + break; + } + } + } + } while (0 != ret); + + return ret; +} + +int ma_set_state_changed_cb(ma_state_changed_cb callback, void* user_data) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Set Multi-assistant client state changed cb"); + + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid parameter"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized' (%d)", state); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_client_set_state_changed_cb(g_ma, callback, user_data); + + return MA_ERROR_NONE; +} + +int ma_unset_state_changed_cb(void) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Unset Multi-assistant client state changed cb"); + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized' (%d)", state); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_client_set_state_changed_cb(g_ma, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_set_error_cb(ma_error_cb callback, void* user_data) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Set Multi-assistant client error cb"); + + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid parameter"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized' (%d)", state); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_client_set_error_cb(g_ma, callback, user_data); + + return MA_ERROR_NONE; +} + +int ma_unset_error_cb(void) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Unset Multi-assistant client error cb"); + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized' (%d)", state); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_client_set_error_cb(g_ma, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_set_language_changed_cb(ma_language_changed_cb callback, void* user_data) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Set Multi-assistant language changed cb"); + + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid parameter"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_client_set_lang_changed_cb(g_ma, callback, user_data); + + return MA_ERROR_NONE; +} + +int ma_unset_language_changed_cb(void) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Unset Multi-assistant language changed cb"); + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_client_set_lang_changed_cb(g_ma, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_set_audio_streaming_cb(ma_audio_streaming_cb callback, void* user_data) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Set Multi-assistant audio streaming cb"); + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid parameter"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized' (%d)", state); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_client_set_audio_streaming_cb(g_ma, callback, user_data); + + return MA_ERROR_NONE; +} + +int ma_unset_audio_streaming_cb(void) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Unset Multi-assistant audio streaming cb"); + + ma_state_e state; + + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'Initialized'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_client_set_audio_streaming_cb(g_ma, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_send_asr_result(ma_asr_result_event_e event, const char* asr_result) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + if (event < MA_ASR_RESULT_EVENT_FINAL_RESULT || event > MA_ASR_RESULT_EVENT_ERROR) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_READY) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'READY'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + if (NULL == asr_result) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Input parameter is NULL. (no result)"); + return MA_ERROR_INVALID_PARAMETER; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Send ASR result to the Multi-assistant service"); + + int ret = -1; + int pid = getpid(); + ret = ma_dbus_send_asr_result(pid, event, asr_result); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to send ASR result"); + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[ERROR] Success to send ASR result"); + } + + return ret; +} + +int ma_send_result(const char* display_text, const char* utterance_text, const char* result_json) +{ + if (0 != __ma_get_feature_enabled()) { + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + ma_state_e state; + if (0 != ma_client_get_client_state(g_ma, &state)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_READY) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Invalid State: Current state is not 'READY'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Send result to the Multi-assistant"); + + if (NULL == display_text || NULL == utterance_text || NULL == result_json) { + SLOG(LOG_DEBUG, TAG_MAC, "[Client DEBUG] Input parameter is NULL."); + } + + int ret = -1; + int pid = getpid(); + ret = ma_dbus_send_result(pid, display_text, utterance_text, result_json); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to send result"); + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[ERROR] Success to send result"); + } + + return ret; +} + + diff --git a/client/ma_client.c b/client/ma_client.c new file mode 100644 index 0000000..3bb416f --- /dev/null +++ b/client/ma_client.c @@ -0,0 +1,382 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "ma_client.h" + + +typedef struct { + /* base info */ + ma_h ma; + int pid; + int uid; /*<< unique id = pid + handle */ + + ma_error_cb error_cb; + void* error_user_data; + ma_state_changed_cb state_changed_cb; + void* state_changed_user_data; + ma_language_changed_cb lang_changed_cb; + void* lang_changed_user_data; + ma_audio_streaming_cb audio_streaming_cb; + void* audio_streaming_user_data; + + /* state */ + ma_state_e previous_state; + ma_state_e current_state; + + /* mutex */ + int cb_ref_count; + + /* error data */ + int reason; + + int ui_pid; +} ma_client_s; + +/* client list */ +static GSList* g_client_list = NULL; + + + +static ma_client_s* __client_get(ma_h ma) +{ + if (NULL == ma) { + SLOG(LOG_ERROR, TAG_MAC, "[DEBUG] Handle is NULL"); + return NULL; + } + + ma_client_s* data = NULL; + int count = g_slist_length(g_client_list); + int i; + + for (i = 0 ; i < count ; i++) { + data = g_slist_nth_data(g_client_list, i); + + if (NULL != data) { + if (ma->handle == data->ma->handle) { + return data; + } + } + } + + return NULL; +} + +int ma_client_create(ma_h* ma) +{ + ma_client_s* client = NULL; + + client = (ma_client_s*)calloc(1, sizeof(ma_client_s)); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to allocate memory"); //LCOV_EXCL_LINE + return MA_ERROR_OUT_OF_MEMORY; + } + + ma_h temp = (ma_h)calloc(1, sizeof(struct ma_s)); + if (NULL == temp) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to allocate memory"); //LCOV_EXCL_LINE + free(client); + return MA_ERROR_OUT_OF_MEMORY; + } + + temp->handle = getpid(); + + /* initialize client data */ + client->ma = temp; + client->pid = getpid(); + client->uid = temp->handle; + + client->error_cb = NULL; + client->error_user_data = NULL; + client->state_changed_cb = NULL; + client->state_changed_user_data = NULL; + client->lang_changed_cb = NULL; + client->lang_changed_user_data = NULL; + client->audio_streaming_cb = NULL; + client->audio_streaming_user_data = NULL; + + client->previous_state = MA_STATE_INITIALIZED; + client->current_state = MA_STATE_INITIALIZED; + + client->cb_ref_count = 0; + + + g_client_list = g_slist_append(g_client_list, client); + + *ma = temp; + + return 0; +} + +int ma_client_destroy(ma_h ma) +{ + if (ma == NULL) { + SLOG(LOG_ERROR, TAG_MAC, "Input parameter is NULL"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } + + ma_client_s *data = NULL; + + int count = g_slist_length(g_client_list); + int i; + + for (i = 0; i < count; i++) { + data = g_slist_nth_data(g_client_list, i); + + if (NULL != data) { + if (ma->handle == data->ma->handle) { + g_client_list = g_slist_remove(g_client_list, data); + + while (0 != data->cb_ref_count) { + /* wait for release callback function */ + } + free(data); + free(ma); + data = NULL; + ma = NULL; + return 0; + } + } + } + + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] client Not found"); + + return -1; +} + +bool ma_client_is_valid(ma_h ma) +{ + ma_client_s* client = __client_get(ma); + + /* check handle */ + if (NULL == client) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] multi-assistant client is not valid"); + return false; + } + + return true; +} + +int ma_client_get_count(void) +{ + return g_slist_length(g_client_list); +} + +int ma_client_use_callback(ma_h ma) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->cb_ref_count++; + + return MA_ERROR_NONE; +} + +int ma_client_not_use_callback(ma_h ma) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->cb_ref_count--; + + return MA_ERROR_NONE; +} + + +int ma_client_set_client_state(ma_h ma, ma_state_e state) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->previous_state = client->current_state; + client->current_state = state; + + return MA_ERROR_NONE; +} + +int ma_client_get_client_state(ma_h ma, ma_state_e* state) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *state = client->current_state; + + return MA_ERROR_NONE; +} + +int ma_client_get_previous_state(ma_h ma, ma_state_e* current_state, ma_state_e* previous_state) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *current_state = client->current_state; + *previous_state = client->previous_state; + + return MA_ERROR_NONE; +} + +int ma_client_set_error(ma_h ma, ma_error_e reason) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->reason = reason; + + return MA_ERROR_NONE; +} + +int ma_client_get_error(ma_h ma, ma_error_e* reason) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *reason = (ma_error_e)client->reason; + + return MA_ERROR_NONE; +} + +int ma_client_set_ui_pid(ma_h ma, int pid) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->ui_pid = pid; + + return MA_ERROR_NONE; +} + + +int ma_client_set_state_changed_cb(ma_h ma, ma_state_changed_cb callback, void* user_data) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->state_changed_cb = callback; + client->state_changed_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_client_get_state_changed_cb(ma_h ma, ma_state_changed_cb* callback, void** user_data) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->state_changed_cb; + *user_data = client->state_changed_user_data; + + return MA_ERROR_NONE; +} + +int ma_client_set_lang_changed_cb(ma_h ma, ma_language_changed_cb callback, void* user_data) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->lang_changed_cb = callback; + client->lang_changed_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_client_get_lang_changed_cb(ma_h ma, ma_language_changed_cb* callback, void** user_data) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->lang_changed_cb; + *user_data = client->lang_changed_user_data; + + return MA_ERROR_NONE; +} + +int ma_client_set_audio_streaming_cb(ma_h ma, ma_audio_streaming_cb callback, void* user_data) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->audio_streaming_cb = callback; + client->audio_streaming_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_client_get_audio_streaming_cb(ma_h ma, ma_audio_streaming_cb* callback, void** user_data) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->audio_streaming_cb; + *user_data = client->audio_streaming_user_data; + + return MA_ERROR_NONE; +} + +int ma_client_set_error_cb(ma_h ma, ma_error_cb callback, void* user_data) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->error_cb = callback; + client->error_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_client_get_error_cb(ma_h ma, ma_error_cb* callback, void** user_data) +{ + ma_client_s* client = __client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->error_cb; + *user_data = client->error_user_data; + + return MA_ERROR_NONE; +} + + diff --git a/client/ma_client.h b/client/ma_client.h new file mode 100644 index 0000000..9174443 --- /dev/null +++ b/client/ma_client.h @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __MA_CLIENT_H__ +#define __MA_CLIENT_H__ + +#include "ma_main.h" +#include "multi_assistant_common.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +int ma_client_create(ma_h* ma); + +int ma_client_destroy(ma_h ma); + +bool ma_client_is_valid(ma_h ma); + +int ma_client_get_count(void); + +int ma_client_use_callback(ma_h ma); + +int ma_client_not_use_callback(ma_h ma); + + +int ma_client_set_client_state(ma_h ma, ma_state_e state); + +int ma_client_get_client_state(ma_h ma, ma_state_e* state); + +int ma_client_get_previous_state(ma_h ma, ma_state_e* current_state, ma_state_e* previous_state); + +int ma_client_set_error(ma_h ma, ma_error_e reason); + +int ma_client_get_error(ma_h ma, ma_error_e* reason); + +int ma_client_set_ui_pid(ma_h ma, int pid); + + +int ma_client_set_state_changed_cb(ma_h ma, ma_state_changed_cb callback, void* user_data); + +int ma_client_get_state_changed_cb(ma_h ma, ma_state_changed_cb* callback, void** user_data); + +int ma_client_set_lang_changed_cb(ma_h ma, ma_language_changed_cb callback, void* user_data); + +int ma_client_get_lang_changed_cb(ma_h ma, ma_language_changed_cb* callback, void** user_data); + +int ma_client_set_audio_streaming_cb(ma_h ma, ma_audio_streaming_cb callback, void* user_data); + +int ma_client_get_audio_streaming_cb(ma_h ma, ma_audio_streaming_cb* callback, void** user_data); + +int ma_client_set_error_cb(ma_h ma, ma_error_cb callback, void* user_data); + +int ma_client_get_error_cb(ma_h ma, ma_error_cb* callback, void** user_data); + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __MA_CLIENT_H__ */ + + diff --git a/client/ma_dbus.c b/client/ma_dbus.c new file mode 100644 index 0000000..d4ab196 --- /dev/null +++ b/client/ma_dbus.c @@ -0,0 +1,751 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "ma_dbus.h" +#include "ma_defs.h" +#include "ma_main.h" +#include "ma_client.h" + + +static int g_waiting_time = 3000; + +static Ecore_Fd_Handler* g_fd_handler = NULL; + +static DBusConnection* g_conn_sender = NULL; +static DBusConnection* g_conn_listener = NULL; + +extern int __ma_cb_error(int reason, char* msg); +extern int __ma_cb_audio_streaming(int event, char* buffer, int len); + +static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler* fd_handler) +{ + if (NULL == g_conn_listener) + return ECORE_CALLBACK_RENEW; + + dbus_connection_read_write_dispatch(g_conn_listener, 50); + + while (1) { + DBusMessage* msg = NULL; + msg = dbus_connection_pop_message(g_conn_listener); + + /* loop again if we haven't read a message */ + if (NULL == msg) { + break; + } + + DBusError err; + dbus_error_init(&err); + + char if_name[64] = {0, }; + snprintf(if_name, 64, "%s", MA_CLIENT_SERVICE_INTERFACE); + + if (dbus_message_is_method_call(msg, if_name, MAS_METHOD_HELLO)) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Get Hello"); + int pid = 0; + int response = -1; + + dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } + + if (pid > 0) { + SLOG(LOG_DEBUG, TAG_MAC, "@@ ma client get hello : pid(%d) ", pid); + response = 1; + } else { + SLOG(LOG_ERROR, TAG_MAC, "@@ ma client get hello : invalid pid "); + } + + DBusMessage* reply = NULL; + reply = dbus_message_new_method_return(msg); + + if (NULL != reply) { + dbus_message_append_args(reply, DBUS_TYPE_INT32, &response, DBUS_TYPE_INVALID); + + if (!dbus_connection_send(g_conn_listener, reply, NULL)) + SLOG(LOG_ERROR, TAG_MAC, "@@ multi-assistant get hello : fail to send reply"); + else + SLOG(LOG_DEBUG, TAG_MAC, "@@ multi-assistant get hello : result(%d)", response); + + dbus_connection_flush(g_conn_listener); + dbus_message_unref(reply); + } else { + SLOG(LOG_ERROR, TAG_MAC, "@@ multi-assistant get hello : fail to create reply message"); + } + + } /* MAS_METHOD_HELLO */ + + else if (dbus_message_is_method_call(msg, if_name, MAS_METHOD_SEND_SPEECH_DATA)) { + SLOG(LOG_INFO, TAG_MAC, "@@@ Send speech data"); + int event; + char* buffer = NULL; + int len; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &event, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &buffer, &len, + DBUS_TYPE_INVALID); + + __ma_cb_audio_streaming(event, buffer, len); + + SLOG(LOG_INFO, TAG_MAC, "@@@"); + } /* MAS_METHOD_SEND_SPEECH_DATA */ + + + else if (dbus_message_is_signal(msg, if_name, MAS_METHOD_ERROR)) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Get Error"); + int reason; + char* err_msg; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &reason, + DBUS_TYPE_STRING, &err_msg, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "@@ multi-assistant Get Error message : Get arguments error (%s)", err.message); + dbus_error_free(&err); + } else { + SLOG(LOG_DEBUG, TAG_MAC, "@@ multi-assistant Get Error message : reason(%d), msg(%s)", reason, err_msg); + __ma_cb_error(reason, err_msg); + } + + } /* MAS_METHOD_ERROR */ + + else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameOwnerChanged")) { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] Owner Changed"); + DBusError err; + dbus_error_init(&err); + /* remove a rule for daemon error */ + char rule_err[256] = {0, }; + snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", MA_SERVER_SERVICE_INTERFACE); + dbus_bus_remove_match(g_conn_listener, rule_err, &err); + dbus_connection_flush(g_conn_listener); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "Match Error (%s)", err.message); + dbus_error_free(&err); + } + + __ma_cb_error(MA_ERROR_SERVICE_RESET, "Daemon Reset"); + } /* NameOwnerChanged */ + + else { + SLOG(LOG_DEBUG, TAG_MAC, "Message is NOT valid"); + dbus_message_unref(msg); + break; + } + + /* free the message */ + dbus_message_unref(msg); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static void __ma_dbus_connection_free() +{ + if (NULL != g_conn_listener) { + dbus_connection_close(g_conn_listener); + dbus_connection_unref(g_conn_listener); + g_conn_listener = NULL; + } + if (NULL != g_conn_sender) { + dbus_connection_close(g_conn_sender); + dbus_connection_unref(g_conn_sender); + g_conn_sender = NULL; + } +} + +int ma_dbus_open_connection() +{ + if (NULL != g_conn_sender && NULL != g_conn_listener) { + SLOG(LOG_WARN, TAG_MAC, "already existed connection "); //LCOV_EXCL_LINE + return 0; + } + + DBusError err; + int ret; + + /* initialize the error value */ + dbus_error_init(&err); + + /* connect to the DBUS system bus, and check for errors */ + g_conn_sender = dbus_bus_get_private(DBUS_BUS_SESSION, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "Dbus Connection Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + if (NULL == g_conn_sender) { + SLOG(LOG_ERROR, TAG_MAC, "Fail to get dbus connection "); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } + + dbus_connection_set_exit_on_disconnect(g_conn_sender, false); + + g_conn_listener = dbus_bus_get_private(DBUS_BUS_SESSION, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "Dbus Connection Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + if (NULL == g_conn_listener) { + SLOG(LOG_ERROR, TAG_MAC, "Fail to get dbus connection "); //LCOV_EXCL_LINE + __ma_dbus_connection_free(); + return MA_ERROR_OPERATION_FAILED; + } + + dbus_connection_set_exit_on_disconnect(g_conn_listener, false); + +// int pid = getpid(); + + char service_name[64]; + memset(service_name, '\0', 64); +// snprintf(service_name, 64, "%s%d", MA_CLIENT_SERVICE_NAME, pid); + snprintf(service_name, 64, "%s", MA_CLIENT_SERVICE_NAME); + + SLOG(LOG_DEBUG, TAG_MAC, "service name is %s", service_name); + + /* register our name on the bus, and check for errors */ + ret = dbus_bus_request_name(g_conn_listener, service_name, DBUS_NAME_FLAG_REPLACE_EXISTING, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "Name Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { + SLOG(LOG_ERROR, TAG_MAC, "fail dbus_bus_request_name()"); //LCOV_EXCL_LINE + __ma_dbus_connection_free(); + return -2; + } + + if (NULL != g_fd_handler) { + SLOG(LOG_WARN, TAG_MAC, "The handler already exists."); //LCOV_EXCL_LINE + __ma_dbus_connection_free(); + return 0; + } + + /* Flush messages which are received before fd event handler registration */ + while (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_get_dispatch_status(g_conn_listener)) { + listener_event_callback(NULL, NULL); + } + + char rule[256] = {0, }; + snprintf(rule, 256, "type='signal',interface='%s'", MA_CLIENT_SERVICE_INTERFACE); + + /* add a rule for which messages we want to see */ + dbus_bus_add_match(g_conn_listener, rule, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "Match Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + __ma_dbus_connection_free(); + return MA_ERROR_OPERATION_FAILED; + } + + int fd = 0; + if (1 != dbus_connection_get_unix_fd(g_conn_listener, &fd)) { + SLOG(LOG_ERROR, TAG_MAC, "fail to get fd from dbus "); //LCOV_EXCL_LINE + __ma_dbus_connection_free(); + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAC, "Get fd from dbus : %d", fd); + } + + g_fd_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, (Ecore_Fd_Cb)listener_event_callback, g_conn_listener, NULL, NULL); + if (NULL == g_fd_handler) { + SLOG(LOG_ERROR, TAG_MAC, "fail to get fd handler from ecore "); //LCOV_EXCL_LINE + __ma_dbus_connection_free(); + return MA_ERROR_OPERATION_FAILED; + } + + return 0;} + +int ma_dbus_close_connection() +{ + DBusError err; + dbus_error_init(&err); + + if (NULL != g_fd_handler) { + ecore_main_fd_handler_del(g_fd_handler); + g_fd_handler = NULL; + } + + if (NULL != g_conn_listener) { +// int pid = getpid(); + + char service_name[64]; + memset(service_name, '\0', 64); +// snprintf(service_name, 64, "%s%d", MA_CLIENT_SERVICE_NAME, pid); + snprintf(service_name, 64, "%s", MA_CLIENT_SERVICE_NAME); + + dbus_bus_release_name(g_conn_listener, service_name, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Dbus Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + } + + __ma_dbus_connection_free(); + + return 0; +} + +int ma_dbus_reconnect() +{ + if (!g_conn_sender || !g_conn_listener) { + ma_dbus_close_connection(); + + if (0 != ma_dbus_open_connection()) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to reconnect"); //LCOV_EXCL_LINE + return -1; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[DBUS] Reconnect"); //LCOV_EXCL_LINE + return 0; + } + + bool sender_connected = dbus_connection_get_is_connected(g_conn_sender); + bool listener_connected = dbus_connection_get_is_connected(g_conn_listener); + SLOG(LOG_WARN, TAG_MAC, "[DBUS] Sender(%s) Listener(%s)", + sender_connected ? "Connected" : "Not connected", listener_connected ? "Connected" : "Not connected"); //LCOV_EXCL_LINE + + if (false == sender_connected || false == listener_connected) { + ma_dbus_close_connection(); + + if (0 != ma_dbus_open_connection()) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Fail to reconnect"); //LCOV_EXCL_LINE + return -1; + } + + SLOG(LOG_DEBUG, TAG_MAC, "[DBUS] Reconnect"); //LCOV_EXCL_LINE + } + + return 0;} + +static int __dbus_check() +{ + if (NULL == g_conn_sender) { + SLOG(LOG_ERROR, TAG_MAC, "[ERROR] Null connection"); //LCOV_EXCL_LINE + return ma_dbus_reconnect(); + } + + return MA_ERROR_NONE; +} + +int ma_dbus_request_hello() +{ + if (0 != __dbus_check()) { + return MA_ERROR_OPERATION_FAILED; + } + + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_METHOD_HELLO); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Request multi-assistant hello : Fail to make message"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } + + DBusError err; + dbus_error_init(&err); + + DBusMessage* result_msg = NULL; + int result = 0; + + result_msg = dbus_connection_send_with_reply_and_block(g_conn_sender, msg, -1, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_DEBUG, TAG_MAC, "[ERROR] Dbus Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + dbus_message_unref(msg); + + if (NULL != result_msg) { + dbus_message_unref(result_msg); + result = 0; + } else { + result = MA_ERROR_TIMED_OUT; + } + + return result;} + +int ma_dbus_request_initialize(int pid) +{ + if (0 != __dbus_check()) { + return MA_ERROR_OPERATION_FAILED; + } + + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_METHOD_INITIALIZE); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Request multi-assistant initialize : Fail to make message"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] multi-assistant initialize : pid(%d)", pid); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INVALID); + + + DBusError err; + dbus_error_init(&err); + + DBusMessage* result_msg = NULL; + int result = MA_ERROR_OPERATION_FAILED; + + result_msg = dbus_connection_send_with_reply_and_block(g_conn_sender, msg, g_waiting_time, &err); + dbus_message_unref(msg); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_DEBUG, TAG_MAC, "[ERROR] Dbus Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + if (NULL != result_msg) { + dbus_message_get_args(result_msg, &err, + DBUS_TYPE_INT32, &result, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Get arguments error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + result = MA_ERROR_OPERATION_FAILED; + } + + dbus_message_unref(result_msg); + + if (0 == result) { + /* add a rule for daemon error */ + char rule[256] = {0, }; + snprintf(rule, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", MA_SERVER_SERVICE_INTERFACE); + dbus_bus_add_match(g_conn_listener, rule, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "Match Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + SLOG(LOG_DEBUG, TAG_MAC, "@@ multi-assistant initialize : result = %d", result); //LCOV_EXCL_LINE + } else { + SLOG(LOG_ERROR, TAG_MAC, "@@ multi-assistant initialize : result = %d", result); //LCOV_EXCL_LINE + } + } else { + SLOG(LOG_ERROR, TAG_MAC, "@@ Result message is NULL "); //LCOV_EXCL_LINE + ma_dbus_reconnect(); + result = MA_ERROR_TIMED_OUT; + } + + return result; +} + +int ma_dbus_request_deinitialize(int pid) +{ + if (0 != __dbus_check()) { + return MA_ERROR_OPERATION_FAILED; + } + + DBusError err; + dbus_error_init(&err); + + /* remove a rule for daemon error */ + char rule[256] = {0, }; + snprintf(rule, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", MA_SERVER_SERVICE_INTERFACE); + dbus_bus_remove_match(g_conn_listener, rule, &err); + dbus_connection_flush(g_conn_listener); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "Match Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_METHOD_DEINITIALIZE); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Request multi-assistant deinitialize : Fail to make message"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] multi-assistant deinitialize : pid(%d)", pid); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INVALID); + + DBusMessage* result_msg = NULL; + int result = MA_ERROR_OPERATION_FAILED; + + result_msg = dbus_connection_send_with_reply_and_block(g_conn_sender, msg, g_waiting_time, &err); + dbus_message_unref(msg); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_DEBUG, TAG_MAC, "[ERROR] Dbus Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + if (NULL != result_msg) { + dbus_message_get_args(result_msg, &err, + DBUS_TYPE_INT32, &result, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Get arguments error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + result = MA_ERROR_OPERATION_FAILED; + } + + dbus_message_unref(result_msg); + + if (0 == result) { + SLOG(LOG_DEBUG, TAG_MAC, "@@ multi-assistant finalize : result = %d", result); + } else { + SLOG(LOG_ERROR, TAG_MAC, "@@ multi-assistant finalize : result = %d", result); + } + } else { + SLOG(LOG_ERROR, TAG_MAC, "@@ Result message is NULL "); //LCOV_EXCL_LINE + ma_dbus_reconnect(); + result = MA_ERROR_TIMED_OUT; + } + + return result; +} + + +int ma_dbus_get_recording_audio_format(int pid, int *rate, ma_audio_channel_e *channel, ma_audio_type_e *audio_type) +{ + if (0 != __dbus_check()) { + return MA_ERROR_OPERATION_FAILED; + } + + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_METHOD_GET_RECORDING_AUDIO_FORMAT); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Request multi-assistant recording audio format : Fail to make message"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] multi-assistant recording audio format"); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INVALID); + + + DBusError err; + dbus_error_init(&err); + + DBusMessage* result_msg = NULL; + int result = MA_ERROR_OPERATION_FAILED; + + result_msg = dbus_connection_send_with_reply_and_block(g_conn_sender, msg, g_waiting_time, &err); + dbus_message_unref(msg); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_DEBUG, TAG_MAC, "[ERROR] Dbus Error (%s)", err.message); //LCOV_EXCL_LINE + dbus_error_free(&err); + } + + int tmp_rate; + int tmp_channel; + int tmp_audio_type; + + if (NULL != result_msg) { + dbus_message_get_args(result_msg, &err, + DBUS_TYPE_INT32, &result, + DBUS_TYPE_INT32, &tmp_rate, + DBUS_TYPE_INT32, &tmp_channel, + DBUS_TYPE_INT32, &tmp_audio_type, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Get arguments error (%s)", err.message); + dbus_error_free(&err); + result = MA_ERROR_OPERATION_FAILED; + } + dbus_message_unref(result_msg); + + if (0 == result) { + *rate = tmp_rate; + *channel = tmp_channel; + *audio_type = tmp_audio_type; + SLOG(LOG_DEBUG, TAG_MAC, "@@ multi-assistant get recording audio format : result = %d, rate = %d, channel = %d, audio_type = %d", result, *rate, *channel, *audio_type); + } else { + SLOG(LOG_ERROR, TAG_MAC, "@@ multi-assistant get recordingaudio format : result = %d", result); + } + } else { + SLOG(LOG_ERROR, TAG_MAC, "@@ Result message is NULL"); + ma_dbus_reconnect(); + result = MA_ERROR_TIMED_OUT; + } + + return result; +} + +int ma_dbus_send_asr_result(int pid, ma_asr_result_event_e event, const char* asr_result) +{ + if (0 != __dbus_check()) { + return MA_ERROR_OPERATION_FAILED; + } + + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_METHOD_SEND_ASR_RESULT); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Request multi-assistant send ASR result : Fail to make message"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] multi-assistant send ASR result"); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INT32, &event, + DBUS_TYPE_STRING, &asr_result, + DBUS_TYPE_INVALID); + + dbus_message_set_no_reply(msg, TRUE); + + if (1 != dbus_connection_send(g_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_MAC, "[Dbus ERROR] Fail to Send"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[Dbus DEBUG] Success to Send"); + dbus_connection_flush(g_conn_sender); + } + + dbus_message_unref(msg); + + return 0; +} + +int ma_dbus_send_result(int pid, const char* display_text, const char* utterance_text, const char* result_json) +{ + if (0 != __dbus_check()) { + return MA_ERROR_OPERATION_FAILED; + } + + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_METHOD_SEND_RESULT); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAC, "@@ Request multi-assistant send result : Fail to make message"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[DEBUG] multi-assistant send result"); + } + + char* tmp_disp_text = NULL; + char* tmp_utt_text = NULL; + char* tmp_result_json = NULL; + + if (NULL != display_text) { + tmp_disp_text = strdup(display_text); + } else { + tmp_disp_text = strdup("#NULL"); + } + + if (NULL != utterance_text) { + tmp_utt_text = strdup(utterance_text); + } else { + tmp_utt_text = strdup("#NULL"); + } + + if (NULL != result_json) { + tmp_result_json = strdup(result_json); + } else { + tmp_result_json = strdup("#NULL"); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_STRING, &tmp_disp_text, + DBUS_TYPE_STRING, &tmp_utt_text, + DBUS_TYPE_STRING, &tmp_result_json, + DBUS_TYPE_INVALID); + + dbus_message_set_no_reply(msg, TRUE); + + if (1 != dbus_connection_send(g_conn_sender, msg, NULL)) { + SLOG(LOG_ERROR, TAG_MAC, "[Dbus ERROR] Fail to Send"); //LCOV_EXCL_LINE + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAC, "[Dbus DEBUG] Success to Send"); + dbus_connection_flush(g_conn_sender); + } + + dbus_message_unref(msg); + + if (NULL != tmp_disp_text) { + free(tmp_disp_text); + tmp_disp_text = NULL; + } + if (NULL != tmp_utt_text) { + free(tmp_utt_text); + tmp_utt_text = NULL; + } + if (NULL != tmp_result_json) { + free(tmp_result_json); + tmp_result_json = NULL; + } + + return 0; +} + diff --git a/client/ma_dbus.h b/client/ma_dbus.h new file mode 100644 index 0000000..86b7e85 --- /dev/null +++ b/client/ma_dbus.h @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __MA_DBUS_H__ +#define __MA_DBUS_H__ + + +#include "multi_assistant_common.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +int ma_dbus_open_connection(); + +int ma_dbus_close_connection(); + + +int ma_dbus_request_hello(); + +int ma_dbus_request_initialize(int pid); + +int ma_dbus_request_deinitialize(int pid); + + +int ma_dbus_get_recording_audio_format(int pid, int *rate, ma_audio_channel_e *channel, ma_audio_type_e *audio_type); + +int ma_dbus_send_asr_result(int pid, ma_asr_result_event_e event, const char* asr_result); + +int ma_dbus_send_result(int pid, const char* display_text, const char* utterance_text, const char* result_json); + + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __MA_DBUS_H__ */ + diff --git a/client/ma_ui.c b/client/ma_ui.c new file mode 100644 index 0000000..1924eda --- /dev/null +++ b/client/ma_ui.c @@ -0,0 +1,965 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +#include +#include +#include +#include +#include + + +#include "multi_assistant_ui.h" +#include "ma_ui_dbus.h" +#include "ma_ui_client.h" +#include "ma_main.h" +#include "ma_defs.h" + + + +#define MA_UI_CONFIG_HANDLE 100000 + +static ma_h g_ma_ui = NULL; + +//static int g_feature_enabled = -1; +static int g_privilege_allowed = -1; +static cynara *p_cynara = NULL; + +static Eina_Bool __ma_ui_notify_state_changed(void* data); +static void __ma_ui_notify_error(void* data); + +//static void __ma_ui_lang_changed_cb(const char* previous_lang, const char* current_lang); + +static int __ma_ui_get_feature_enabled() +{ + return 0; +/* + if (0 == g_feature_enabled) { + //LCOV_EXCL_START + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Multi-assistant feature NOT supported"); + return MA_ERROR_NOT_SUPPORTED; + //LCOV_EXCL_STOP + } else if (-1 == g_feature_enabled) { + bool ma_supported = false; + bool mic_supported = false; + if (0 == system_info_get_platform_bool(MA_FEATURE_PATH, &ma_supported)) { + if (0 == system_info_get_platform_bool(MA_MIC_FEATURE_PATH, &mic_supported)) { + if (false == ma_supported || false == mic_supported) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Multi-assistant feature NOT supported"); + g_feature_enabled = 0; + return MA_ERROR_NOT_SUPPORTED; + } + + g_feature_enabled = 1; + } else { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to get feature value"); //LCOV_EXCL_LINE + return MA_ERROR_NOT_SUPPORTED; + } + } else { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to get feature value"); //LCOV_EXCL_LINE + return MA_ERROR_NOT_SUPPORTED; + } + } +*/ + return 0; +} + +static int __check_privilege_initialize() +{ + int ret = cynara_initialize(&p_cynara, NULL); + if (CYNARA_API_SUCCESS != ret) + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] fail to initialize"); //LCOV_EXCL_LINE + + return ret == CYNARA_API_SUCCESS; +} + +static int __check_privilege(const char* uid, const char * privilege) +{ + FILE *fp = NULL; + char label_path[1024] = "/proc/self/attr/current"; + char smack_label[1024] = {'\0',}; + + if (!p_cynara) { + return false; + } + + fp = fopen(label_path, "r"); + if (fp != NULL) { + if (0 >= fread(smack_label, 1, sizeof(smack_label), fp)) + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] fail to fread"); //LCOV_EXCL_LINE + + fclose(fp); + } + + pid_t pid = getpid(); + char *session = cynara_session_from_pid(pid); + int ret = cynara_check(p_cynara, smack_label, session, uid, privilege); + SLOG(LOG_DEBUG, TAG_MAUI, "[Client]cynara_check returned %d(%s)", ret, (CYNARA_API_ACCESS_ALLOWED == ret) ? "Allowed" : "Denied"); + if (session) + free(session); + + if (ret != CYNARA_API_ACCESS_ALLOWED) + return false; + return true; +} + +static void __check_privilege_deinitialize() +{ + if (p_cynara) + cynara_finish(p_cynara); + p_cynara = NULL; +} + +static int __ma_ui_check_privilege() +{ + char uid[16]; + + if (0 == g_privilege_allowed) { + //LCOV_EXCL_START + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Permission is denied"); + return MA_ERROR_PERMISSION_DENIED; + //LCOV_EXCL_STOP + } else if (-1 == g_privilege_allowed) { + if (false == __check_privilege_initialize()) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] privilege initialize is failed"); //LCOV_EXCL_LINE + return MA_ERROR_PERMISSION_DENIED; + } + snprintf(uid, 16, "%d", getuid()); + if (false == __check_privilege(uid, MA_PRIVILEGE)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Permission is denied"); + g_privilege_allowed = 0; + __check_privilege_deinitialize(); + return MA_ERROR_PERMISSION_DENIED; + } + __check_privilege_deinitialize(); + } + + g_privilege_allowed = 1; + return MA_ERROR_NONE; +} + + + +int ma_ui_initialize(void) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_ui_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_ERROR, TAG_MAUI, "[UI] Initialize"); + + + /* check handle */ + if (true == ma_ui_client_is_valid(g_ma_ui)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Already initialized"); + return MA_ERROR_NONE; + } + + if (0 != ma_ui_dbus_open_connection()) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to open connection"); + return MA_ERROR_OPERATION_FAILED; + } + + if (0 != ma_ui_client_create(&g_ma_ui)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to create client!!!!!"); + return MA_ERROR_OUT_OF_MEMORY; + } +/* + int ret = ma_config_mgr_initialize(g_ma_ui->handle + MA_UI_CONFIG_HANDLE); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to init config manager : %d", ret); + ma_ui_client_destroy(g_ma_ui); + return MA_ERROR_OPERATION_FAILED; + } + + ret = ma_config_mgr_set_lang_cb(g_ma_ui->handle + MA_UI_CONFIG_HANDLE, __ma_ui_lang_changed_cb); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to set callback : %d", ret); + ma_config_mgr_deinitialize(g_ma_ui->handle + MA_UI_CONFIG_HANDLE); + ma_ui_client_destroy(g_ma_ui); + return MA_ERROR_OPERATION_FAILED; + } +*/ + SLOG(LOG_ERROR, TAG_MAUI, "[Success] pid(%d)", g_ma_ui->handle); + + return MA_ERROR_NONE; +} + +static void __ma_ui_internal_unprepare(void) +{ + int ret = ma_ui_dbus_request_deinitialize(g_ma_ui->handle); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to request deinitialize"); + } + + return ; +} + +int ma_ui_deinitialze(void) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_ui_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_ERROR, TAG_MAUI, "@@@ [UI] Deinitialize"); + + if (false == ma_ui_client_is_valid(g_ma_ui)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] NOT initialized"); + return MA_ERROR_INVALID_STATE; + } + + ma_state_e state; + ma_ui_client_get_client_state(g_ma_ui, &state); + + /* check state */ + switch (state) { + case MA_STATE_READY: + __ma_ui_internal_unprepare(); + /* no break. need to next step*/ + case MA_STATE_INITIALIZED: +// ma_config_mgr_unset_lang_cb(g_ma_ui->handle + MA_UI_CONFIG_HANDLE); +// ma_config_mgr_deinitialize(g_ma_ui->handle + MA_UI_CONFIG_HANDLE); + + /* Free client resources */ + ma_ui_client_destroy(g_ma_ui); + g_ma_ui = NULL; + break; + case MA_STATE_NONE: + break; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "Success: destroy"); + + if (0 != ma_ui_dbus_close_connection()) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to close connection"); + } + + SLOG(LOG_ERROR, TAG_MAUI, "@@@"); + + return MA_ERROR_NONE; +} + +static Eina_Bool __ma_ui_connect_daemon(void *data) +{ + /* request initialization */ + int ret = -1; + + ret = ma_ui_dbus_request_initialize(g_ma_ui->handle); + + if (MA_ERROR_ENGINE_NOT_FOUND == ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to initialize"); + + ma_ui_client_set_error(g_ma_ui, MA_ERROR_ENGINE_NOT_FOUND); + ecore_main_loop_thread_safe_call_async(__ma_ui_notify_error, (void*)g_ma_ui); + + return EINA_FALSE; + + } else if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[WARNING] Fail to connection. Retry to connect"); + return EINA_TRUE; + } else { + /* Success to connect */ + } + + + SLOG(LOG_ERROR, TAG_MAUI, "[SUCCESS] Connected daemon"); + + /* Set client state */ + ma_ui_client_set_client_state(g_ma_ui, MA_STATE_READY); + void* user_data; + + ma_state_changed_cb changed_callback = NULL; + ma_ui_client_get_state_changed_cb(g_ma_ui, &changed_callback, &user_data); + + ma_state_e current_state; + ma_state_e previous_state; + + ma_ui_client_get_previous_state(g_ma_ui, ¤t_state, &previous_state); + + if (NULL != changed_callback) { + ma_ui_client_use_callback(g_ma_ui); + changed_callback(previous_state, current_state, user_data); + ma_ui_client_not_use_callback(g_ma_ui); + SLOG(LOG_DEBUG, TAG_MAUI, "State changed callback is called"); + } else { + SLOG(LOG_WARN, TAG_MAUI, "[WARNING] State changed callback is null"); + } + + return EINA_FALSE; +} + +static void __start_prepare_thread(void *data, Ecore_Thread *thread) +{ + SLOG(LOG_ERROR, TAG_MAUI, "@@@ Start prepare thread"); + int ret = 1, retry_count = 0; + + /* Send hello */ + while (0 != ret) { + if (retry_count == 10) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to request hello !!"); + return; + } + + ret = ma_ui_dbus_request_hello(); + if (ret == 0) { + SLOG(LOG_DEBUG, TAG_MAUI, "Success to request hello. retry count(%d)", retry_count); + break; + } else { + retry_count++; + } + } + + ret = 1; + retry_count = 0; + while (0 != ret) { + if (retry_count == 10) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to connect daemon !!"); + return; + } + ret = __ma_ui_connect_daemon(NULL); + if (ret == 0) + break; + else + retry_count++; + } + + return; +} + +static void __end_prepare_thread(void *data, Ecore_Thread *thread) +{ + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ End prepare thread"); +} + +int ma_ui_prepare(void) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_ui_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Prepare"); + + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] A handle is not available"); + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (MA_STATE_INITIALIZED != state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'Initialized' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + ecore_thread_run(__start_prepare_thread, __end_prepare_thread, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_ui_unprepare(void) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_ui_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Unprepare"); + + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] A handle is not available"); + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (MA_STATE_READY != state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'READY' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + __ma_ui_internal_unprepare(); + + ma_ui_client_set_client_state(g_ma_ui, MA_STATE_INITIALIZED); + ecore_timer_add(0, __ma_ui_notify_state_changed, g_ma_ui); + + return MA_ERROR_NONE; +} + +static Eina_Bool __ma_ui_notify_state_changed(void* data) +{ + ma_state_changed_cb callback = NULL; + void* user_data; + + ma_ui_client_get_state_changed_cb(g_ma_ui, &callback, &user_data); + + ma_state_e current_state; + ma_state_e previous_state; + + ma_ui_client_get_previous_state(g_ma_ui, ¤t_state, &previous_state); + + if (NULL != callback) { + ma_ui_client_use_callback(g_ma_ui); + callback(previous_state, current_state, user_data); + ma_ui_client_not_use_callback(g_ma_ui); + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] State changed callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[WARNING] State changed callback is NULL"); + } + + return EINA_FALSE; +} + +/* +static void __ma_ui_lang_changed_cb(const char* previous_lang, const char* current_lang) +{ + SLOG(LOG_DEBUG, TAG_MAUI, "[UI DEBUG] Language changed: prev(%s) curr(%s)", previous_lang, current_lang); + + ma_language_changed_cb callback = NULL; + void* user_data; + + ma_ui_client_get_lang_changed_cb(g_ma_ui, &callback, &user_data); + + if (NULL != callback) { + ma_ui_client_use_callback(g_ma_ui); + callback(previous_lang, current_lang, user_data); + ma_ui_client_not_use_callback(g_ma_ui); + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Lang changed callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[WARNING] Lang changed callback is NULL"); + } +} +*/ + +static void __ma_ui_notify_send_asr_result(ma_asr_result_event_e event, char* asr_result) +{ + ma_ui_asr_result_cb callback = NULL; + void* user_data; + + ma_ui_client_get_asr_result_cb(g_ma_ui, &callback, &user_data); + + if (NULL != callback) { + ma_ui_client_use_callback(g_ma_ui); + callback(event, asr_result, user_data); + ma_ui_client_not_use_callback(g_ma_ui); + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] asr result callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[WARNING] asr result callback is NULL"); + } +} + +int __ma_ui_cb_send_asr_result(int event, char* asr_result) +{ + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid client"); + return MA_ERROR_INVALID_PARAMETER; + } + + /* check state */ +/* if (MA_STATE_READY != state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'READY' (%d)", state); + return MA_ERROR_INVALID_STATE; + } +*/ + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] send asr result, event(%d), asr_result(%s)", event, asr_result); + + __ma_ui_notify_send_asr_result((ma_asr_result_event_e)event, asr_result); + + return MA_ERROR_NONE; +} + +static void __ma_ui_notify_send_result(const char* display_text, const char* utterance_text, const char* result_json) +{ + ma_ui_result_cb callback = NULL; + void* user_data; + + ma_ui_client_get_result_cb(g_ma_ui, &callback, &user_data); + + if (NULL != callback) { + ma_ui_client_use_callback(g_ma_ui); + callback(display_text, utterance_text, result_json, user_data); + ma_ui_client_not_use_callback(g_ma_ui); + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] result callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[WARNING] result callback is NULL"); + } +} + +int __ma_ui_cb_send_result(const char* display_text, const char* utterance_text, const char* result_json) +{ + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid client"); + return MA_ERROR_INVALID_PARAMETER; + } + + /* check state */ +/* if (MA_STATE_READY != state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'READY' (%d)", state); + return MA_ERROR_INVALID_STATE; + } +*/ + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] send result, display_text(%s), utterance_text(%s), result_json(%s)", display_text, utterance_text, result_json); + + __ma_ui_notify_send_result(display_text, utterance_text, result_json); + + return MA_ERROR_NONE; +} + +int __ma_ui_cb_error(int reason, char* msg) +{ + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid client"); + return MA_ERROR_INVALID_PARAMETER; + } + + /* check state */ + if (MA_STATE_READY != state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'READY' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + if (MA_ERROR_SERVICE_RESET == reason) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] multi-assistant service reset"); + ma_ui_client_set_client_state(g_ma_ui, MA_STATE_INITIALIZED); + __ma_ui_notify_state_changed(g_ma_ui); + + if (0 != ma_ui_prepare()) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to prepare"); + } + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Error reason(%d), msg(%s)", reason, msg); + + ma_ui_client_set_error(g_ma_ui, reason); + __ma_ui_notify_error(g_ma_ui); + + return MA_ERROR_NONE; +} + +static void __ma_ui_notify_error(void* data) +{ + ma_error_cb callback = NULL; + void* user_data; + ma_error_e reason; + + ma_ui_client_get_error_cb(g_ma_ui, &callback, &user_data); + ma_ui_client_get_error(g_ma_ui, &reason); + + if (NULL != callback) { + ma_ui_client_use_callback(g_ma_ui); + callback(reason, user_data); + ma_ui_client_not_use_callback(g_ma_ui); + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Error callback is called"); + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[WARNING] Error callback is NULL"); + } +} + +int ma_ui_get_state(ma_state_e* state) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_ui_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI DEBUG] Get current state"); + + if (NULL == state) { + SLOG(LOG_ERROR, TAG_MAUI, "[Client ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + + ma_state_e tmp_state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &tmp_state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + *state = tmp_state; + + return MA_ERROR_NONE; +} + +int ma_ui_foreach_assistant_info(ma_ui_assistant_info_cb callback, void* user_data) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_ui_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Get foreach assistant info"); + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + int ret = -1; +/* ret = ma_config_mgr_get_assistant_info(callback, user_data); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Fail to get assistant info"); + } +*/ + ret = 0; + return ret; +} + +int ma_ui_set_default_assistant(const char* app_id) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_ui_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Set a default assistant"); + + if (NULL == app_id) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] A handle is not available"); + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (MA_STATE_INITIALIZED!= state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'Initialized' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + int ret = -1; +/* ret = ma_config_mgr_set_default_assistant(app_id); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Fail to set default assistant")_; + } +*/ + ret = 0; + return ret; +} + +int ma_ui_change_assistant(const char* app_id) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + if (0 != __ma_ui_check_privilege()) { + return MA_ERROR_PERMISSION_DENIED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Change a assistant"); + + if (NULL == app_id) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] A handle is not available"); + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (MA_STATE_INITIALIZED!= state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'Initialized' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + int ret = -1; +/* ret = ma_config_mgr_change_assistant(app_id); + if (0 != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Fail to set default assistant")_; + } +*/ + ret = 0; + return ret; +} + + +int ma_ui_set_state_changed_cb(ma_state_changed_cb callback, void* user_data) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[Client DEBUG] Set Multi-assistant client state changed cb"); + + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid parameter"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid State: Current state is not 'Initialized'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_ui_client_set_state_changed_cb(g_ma_ui, callback, user_data); + + return MA_ERROR_NONE; +} + +int ma_ui_unset_state_changed_cb(void) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI DEBUG] Unset Multi-assistant client state changed cb"); + + ma_state_e state; + + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid State: Current state is not 'Initialized'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_ui_client_set_state_changed_cb(g_ma_ui, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_ui_set_error_cb(ma_error_cb callback, void* user_data) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[Client DEBUG] Set Multi-assistant UI client error cb"); + + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid parameter"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid State: Current state is not 'Initialized'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_ui_client_set_error_cb(g_ma_ui, callback, user_data); + + return MA_ERROR_NONE; +} + +int ma_ui_unset_error_cb(void) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI DEBUG] Unset Multi-assistant UI client error cb"); + + ma_state_e state; + + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] A handle is not available"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (state != MA_STATE_INITIALIZED) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Invalid State: Current state is not 'Initialized'"); //LCOV_EXCL_LINE + return MA_ERROR_INVALID_STATE; + } + + ma_ui_client_set_error_cb(g_ma_ui, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_ui_set_asr_result_cb(ma_ui_asr_result_cb callback, void* user_data) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Set a ASR result callback"); + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] A handle is not available"); + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (MA_STATE_INITIALIZED!= state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'Initialized' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + ma_ui_client_set_asr_result_cb(g_ma_ui, callback, user_data); + + return MA_ERROR_NONE; +} + +int ma_ui_unset_asr_result_cb(void) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Set a default assistant"); + + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] A handle is not available"); + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (MA_STATE_INITIALIZED!= state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'Initialized' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + ma_ui_client_set_asr_result_cb(g_ma_ui, NULL, NULL); + + return MA_ERROR_NONE; +} + +int ma_ui_set_result_cb(ma_ui_result_cb callback, void* user_data) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Set a default assistant"); + + if (NULL == callback) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid parameter"); + return MA_ERROR_INVALID_PARAMETER; + } + + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] A handle is not available"); + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (MA_STATE_INITIALIZED!= state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'Initialized' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + ma_ui_client_set_result_cb(g_ma_ui, callback, user_data); + + return MA_ERROR_NONE; +} + +int ma_ui_unset_result_cb(void) +{ + if (0 != __ma_ui_get_feature_enabled()) { + SLOG(LOG_DEBUG, TAG_MAUI, "@@@ [UI] not supported"); + return MA_ERROR_NOT_SUPPORTED; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[UI] Set a default assistant"); + + ma_state_e state; + if (0 != ma_ui_client_get_client_state(g_ma_ui, &state)) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] A handle is not available"); + return MA_ERROR_INVALID_STATE; + } + + /* check state */ + if (MA_STATE_INITIALIZED!= state) { + SLOG(LOG_ERROR, TAG_MAUI, "[UI ERROR] Invalid state: Current state is not 'Initialized' (%d)", state); + return MA_ERROR_INVALID_STATE; + } + + ma_ui_client_set_result_cb(g_ma_ui, NULL, NULL); + + return MA_ERROR_NONE; +} + diff --git a/client/ma_ui_client.c b/client/ma_ui_client.c new file mode 100644 index 0000000..7cdec42 --- /dev/null +++ b/client/ma_ui_client.c @@ -0,0 +1,426 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "ma_ui_client.h" + + +typedef struct { + ma_h ma; + int pid; + int uid; /*<< unique id = pid + handle */ + + ma_ui_result_cb result_cb; + void* result_user_data; + ma_ui_asr_result_cb asr_result_cb; + void* asr_result_user_data; + + ma_error_cb error_cb; + void* error_user_data; + ma_state_changed_cb state_changed_cb; + void* state_changed_user_data; + ma_language_changed_cb lang_changed_cb; + void* lang_changed_user_data; + + /* ASR result */ + ma_asr_result_event_e asr_result_event; + char* asr_result_text; + + /* state */ + ma_state_e previous_state; + ma_state_e current_state; + + /* language */ + char* previous_language; + char* current_language; + + /* audio type */ + char* audio_id; + + /* mutex */ + int cb_ref_count; + + /* error data */ + int reason; + char* err_msg; +} ma_ui_client_s; + +static GSList* g_ui_client_list = NULL; + +static ma_ui_client_s* __ui_client_get(ma_h ma) +{ + if (NULL == ma) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Input parameter is NULL"); + return NULL; + } + + ma_ui_client_s* data = NULL; + int count = g_slist_length(g_ui_client_list); + int i; + + for (i = 0 ; i < count ; i++) { + data = g_slist_nth_data(g_ui_client_list, i); + + if (NULL != data) { + if (ma->handle == data->ma->handle) { + return data; + } + } + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Fail to get ui client"); + return NULL; +} + +int ma_ui_client_create(ma_h* ma) +{ + ma_ui_client_s *client = NULL; + + client = (ma_ui_client_s*)calloc(1, sizeof(ma_ui_client_s)); + if (NULL == client) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to allocate memory"); + return MA_ERROR_OUT_OF_MEMORY; + } + + ma_h temp = (ma_h)calloc(1, sizeof(struct ma_s)); + if (NULL == temp) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to allocate memory"); + free(client); + return MA_ERROR_OUT_OF_MEMORY; + } + + temp->handle = getpid(); + + /* initialize client data */ + client->ma = temp; + client->pid = getpid(); + client->uid = temp->handle; + + client->result_cb = NULL; + client->result_user_data = NULL; + client->asr_result_cb = NULL; + client->asr_result_user_data = NULL; + + client->error_cb = NULL; + client->error_user_data = NULL; + client->state_changed_cb = NULL; + client->state_changed_user_data = NULL; + client->lang_changed_cb = NULL; + client->lang_changed_user_data = NULL; + + client->asr_result_event = 0; + client->asr_result_text = NULL; + + client->previous_state = MA_STATE_INITIALIZED; + client->current_state = MA_STATE_INITIALIZED; + + client->previous_language = NULL; + client->current_language = NULL; + + client->audio_id = NULL; + + client->reason = 0; + client->err_msg = NULL; + + client->cb_ref_count = 0; + + + g_ui_client_list = g_slist_append(g_ui_client_list, client); + + *ma = temp; + + return 0;} + +int ma_ui_client_destroy(ma_h ma) +{ + if (ma == NULL) { + SLOG(LOG_ERROR, TAG_MAUI, "Input parameter is NULL"); + return 0; + } + + ma_ui_client_s *data = NULL; + + int count = g_slist_length(g_ui_client_list); + int i; + + for (i = 0; i < count; i++) { + data = g_slist_nth_data(g_ui_client_list, i); + + if (NULL != data) { + if (ma->handle == data->ma->handle) { + g_ui_client_list = g_slist_remove(g_ui_client_list, data); + + while (0 != data->cb_ref_count) { + /* wait for release callback function */ + } + + if (NULL != data->audio_id) { + free(data->audio_id); + } + + if (NULL != data->asr_result_text) { + free(data->asr_result_text); + } + + if (NULL != data->err_msg) { + free(data->err_msg); + } + + free(data); + free(ma); + + data = NULL; + ma = NULL; + + return 0; + } + } + } + + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] client Not found"); + + return -1;} + +bool ma_ui_client_is_valid(ma_h ma) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] ma handle is not valid"); + return false; + } + + return true; +} + +int ma_ui_client_use_callback(ma_h ma) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->cb_ref_count++; + + return MA_ERROR_NONE; +} + +int ma_ui_client_not_use_callback(ma_h ma) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->cb_ref_count--; + + return MA_ERROR_NONE; +} + + +int ma_ui_client_set_client_state(ma_h ma, ma_state_e state) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->previous_state = client->current_state; + client->current_state = state; + + return MA_ERROR_NONE; +} + +int ma_ui_client_get_client_state(ma_h ma, ma_state_e* state) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *state = client->current_state; + + return MA_ERROR_NONE; +} + +int ma_ui_client_get_previous_state(ma_h ma, ma_state_e* current_state, ma_state_e* previous_state) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *current_state = client->current_state; + *previous_state = client->previous_state; + + return MA_ERROR_NONE; +} + +int ma_ui_client_set_error(ma_h ma, ma_error_e reason) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->reason = reason; + + return MA_ERROR_NONE; +} + +int ma_ui_client_get_error(ma_h ma, ma_error_e* reason) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *reason = client->reason; + + return MA_ERROR_NONE; +} + + +int ma_ui_client_set_asr_result_cb(ma_h ma, ma_ui_asr_result_cb callback, void* user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->asr_result_cb = callback; + client->asr_result_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_get_asr_result_cb(ma_h ma, ma_ui_asr_result_cb* callback, void** user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->asr_result_cb; + *user_data = client->asr_result_user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_set_result_cb(ma_h ma, ma_ui_result_cb callback, void* user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->result_cb = callback; + client->result_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_get_result_cb(ma_h ma, ma_ui_result_cb* callback, void** user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->result_cb; + *user_data = client->result_user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_set_error_cb(ma_h ma, ma_error_cb callback, void* user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->error_cb = callback; + client->error_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_get_error_cb(ma_h ma, ma_error_cb* callback, void** user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->error_cb; + *user_data = client->error_user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_set_state_changed_cb(ma_h ma, ma_state_changed_cb callback, void* user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->state_changed_cb = callback; + client->state_changed_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_get_state_changed_cb(ma_h ma, ma_state_changed_cb* callback, void** user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->state_changed_cb; + *user_data = client->state_changed_user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_set_lang_changed_cb(ma_h ma, ma_language_changed_cb callback, void* user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + client->lang_changed_cb = callback; + client->lang_changed_user_data = user_data; + + return MA_ERROR_NONE; +} + +int ma_ui_client_get_lang_changed_cb(ma_h ma, ma_language_changed_cb* callback, void** user_data) +{ + ma_ui_client_s* client = __ui_client_get(ma); + + if (NULL == client) + return MA_ERROR_INVALID_PARAMETER; + + *callback = client->lang_changed_cb; + *user_data = client->lang_changed_user_data; + + return MA_ERROR_NONE; +} + diff --git a/client/ma_ui_client.h b/client/ma_ui_client.h new file mode 100644 index 0000000..0562dbd --- /dev/null +++ b/client/ma_ui_client.h @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __MA_UI_CLIENT_H__ +#define __MA_UI_CLIENT_H__ + +#include "ma_main.h" +#include "multi_assistant_common.h" +#include "multi_assistant_ui.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +int ma_ui_client_create(ma_h* ma); + +int ma_ui_client_destroy(ma_h ma); + +bool ma_ui_client_is_valid(ma_h ma); + +int ma_ui_client_use_callback(ma_h ma); + +int ma_ui_client_not_use_callback(ma_h ma); + + +int ma_ui_client_set_client_state(ma_h ma, ma_state_e state); + +int ma_ui_client_get_client_state(ma_h ma, ma_state_e* state); + +int ma_ui_client_get_previous_state(ma_h ma, ma_state_e* current_state, ma_state_e* previous_state); + +int ma_ui_client_set_error(ma_h ma, ma_error_e reason); + +int ma_ui_client_get_error(ma_h ma, ma_error_e* reason); + + +int ma_ui_client_set_asr_result_cb(ma_h ma, ma_ui_asr_result_cb callback, void* user_data); + +int ma_ui_client_get_asr_result_cb(ma_h ma, ma_ui_asr_result_cb* callback, void** user_data); + +int ma_ui_client_set_result_cb(ma_h ma, ma_ui_result_cb callback, void* user_data); + +int ma_ui_client_get_result_cb(ma_h ma, ma_ui_result_cb* callback, void** user_data); + +int ma_ui_client_set_error_cb(ma_h ma, ma_error_cb callback, void* user_data); + +int ma_ui_client_get_error_cb(ma_h ma, ma_error_cb* callback, void** user_data); + +int ma_ui_client_set_state_changed_cb(ma_h ma, ma_state_changed_cb callback, void* user_data); + +int ma_ui_client_get_state_changed_cb(ma_h ma, ma_state_changed_cb* callback, void** user_data); + +int ma_ui_client_set_lang_changed_cb(ma_h ma, ma_language_changed_cb callback, void* user_data); + +int ma_ui_client_get_lang_changed_cb(ma_h ma, ma_language_changed_cb* callback, void** user_data); + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __MA_UI_CLIENT_H__ */ + diff --git a/client/ma_ui_dbus.c b/client/ma_ui_dbus.c new file mode 100644 index 0000000..5630b06 --- /dev/null +++ b/client/ma_ui_dbus.c @@ -0,0 +1,636 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "ma_ui_dbus.h" +#include "ma_defs.h" +#include "ma_main.h" + + + +static int g_ui_waiting_time = 3000; + +static Ecore_Fd_Handler* g_ui_fd_handler = NULL; + +static DBusConnection* g_ui_conn_sender = NULL; +static DBusConnection* g_ui_conn_listener = NULL; + +extern int __ma_ui_cb_error(int reason, char* msg); +extern int __ma_ui_cb_send_asr_result(int event, char* asr_result); +extern int __ma_ui_cb_send_result(const char* display_text, const char* utterance_text, const char* result_json); + + +static Eina_Bool ma_ui_listener_event_callback(void* data, Ecore_Fd_Handler* fd_handler) +{ + if (NULL == g_ui_conn_listener) + return ECORE_CALLBACK_RENEW; + + dbus_connection_read_write_dispatch(g_ui_conn_listener, 50); + + while (1) { + DBusMessage* msg = NULL; + msg = dbus_connection_pop_message(g_ui_conn_listener); + + /* loop again if we haven't read a message */ + if (NULL == msg) { + break; + } + + /* SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Message is arrived"); */ + + DBusError err; + dbus_error_init(&err); + + char if_name[64] = {0, }; + snprintf(if_name, 64, "%s", MA_UI_CLIENT_SERVICE_INTERFACE); + + if (dbus_message_is_method_call(msg, if_name, MAS_METHOD_HELLO)) { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Get Hello"); + int response = -1; + + DBusMessage *reply = NULL; + reply = dbus_message_new_method_return(msg); + + if (NULL != reply) { + dbus_message_append_args(reply, DBUS_TYPE_INT32, &response, DBUS_TYPE_INVALID); + + if (!dbus_connection_send(g_ui_conn_listener, reply, NULL)) + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] vc get hello : fail to send reply"); + else + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] vc get hello : result(%d)", response); + + dbus_connection_flush(g_ui_conn_listener); + dbus_message_unref(reply); + } else { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] multi-assistant ui get hello : fail to create reply message"); + } + + } /* MAS_METHOD_HELLO */ + + if (dbus_message_is_method_call(msg, if_name, MAS_UI_METHOD_SEND_ASR_RESULT)) { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Send asr result"); + int pid = 0; + int event = 0; + char* asr_result = NULL; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INT32, &event, + DBUS_TYPE_STRING, &asr_result, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] multi-assistant ui Send ASR result : pid(%d), event(%d), asr_result(%s)", pid, event, asr_result); + char* temp_asr = NULL; + if (NULL != asr_result && strcmp("#NULL", asr_result)) { + temp_asr = strdup(asr_result); + } + __ma_ui_cb_send_asr_result(event, temp_asr); + if (NULL != temp_asr) + free(temp_asr); + } + + } /* MAS_UI_METHOD_SEND_ASR_RESULT */ + + if (dbus_message_is_method_call(msg, if_name, MAS_UI_METHOD_SEND_RESULT)) { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Send asr result"); + int pid = 0; + char* display_text = NULL; + char* utterance_text = NULL; + char* result_json = NULL; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_STRING, &display_text, + DBUS_TYPE_STRING, &utterance_text, + DBUS_TYPE_STRING, &result_json, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] multi-assistant ui Send result : pid(%d), display_text(%s), utterance_text(%s), result_json(%s)", pid, display_text, utterance_text, result_json); +#if 0 + __ma_ui_cb_send_result(display_text, utterance_text, result_json); +#else + char* temp_display_text = NULL; + char* temp_utterance_text = NULL; + char* temp_result_json = NULL; + if (NULL != display_text && strcmp("#NULL", display_text)) + temp_display_text = strdup(display_text); + if (NULL != utterance_text && strcmp("#NULL", utterance_text)) + temp_utterance_text = strdup(utterance_text); + if (NULL != result_json && strcmp("#NULL", result_json)) + temp_result_json = strdup(result_json); + + __ma_ui_cb_send_result(temp_display_text, temp_utterance_text, temp_result_json); + + if (NULL != temp_display_text) + free(temp_display_text); + if (NULL != temp_utterance_text) + free(temp_utterance_text); + if (NULL != temp_result_json) + free(temp_result_json); +#endif + } + + } /* MAS_UI_METHOD_SEND_RESULT */ + + else if (dbus_message_is_signal(msg, if_name, MAS_UI_METHOD_ERROR)) { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Get Error"); + int reason; + char* err_msg = NULL; + + dbus_message_get_args(msg, &err, + DBUS_TYPE_INT32, &reason, + DBUS_TYPE_STRING, &err_msg, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] multi-assistant ui Get Error message : Get arguments error (%s)", err.message); + dbus_error_free(&err); + } else { + char* temp_msg = NULL; + if (NULL != err_msg && strcmp("#NULL", err_msg)) { + temp_msg = strdup(err_msg); + } + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] multi-assistant ui Get Error message : reason(%d), msg(%s)", reason, temp_msg); + __ma_ui_cb_error(reason, temp_msg); + if (NULL != temp_msg) { + free(temp_msg); + temp_msg = NULL; + } + } + } /* MAD_MANAGER_METHOD_ERROR */ + + else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameOwnerChanged")) { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] Owner Changed"); + /* remove a rule for daemon error */ + DBusError err; + /* initialize the error value */ + dbus_error_init(&err); + char rule_err[256] = {0, }; + snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", MA_SERVER_SERVICE_INTERFACE); + dbus_bus_remove_match(g_ui_conn_listener, rule_err, &err); + dbus_connection_flush(g_ui_conn_listener); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "Match Error (%s)", err.message); + dbus_error_free(&err); + } + __ma_ui_cb_error(MA_ERROR_SERVICE_RESET, "Daemon Reset"); + } /* NameOwnerChanged */ + + else { + SLOG(LOG_DEBUG, TAG_MAUI, "Message is NOT valid"); + dbus_message_unref(msg); + break; + } + + /* free the message */ + dbus_message_unref(msg); + } /* while(1) */ + + return ECORE_CALLBACK_PASS_ON; +} + +static void __ma_ui_dbus_connection_free() +{ + if (NULL != g_ui_conn_listener) { + dbus_connection_close(g_ui_conn_listener); + dbus_connection_unref(g_ui_conn_listener); + g_ui_conn_listener = NULL; + } + if (NULL != g_ui_conn_sender) { + dbus_connection_close(g_ui_conn_sender); + dbus_connection_unref(g_ui_conn_sender); + g_ui_conn_sender = NULL; + } +} + +int ma_ui_dbus_open_connection() +{ + if (NULL != g_ui_conn_sender && NULL != g_ui_conn_listener) { + SLOG(LOG_WARN, TAG_MAUI, "already existed connection "); + return 0; + } + + DBusError err; + int ret; + + /* initialize the error value */ + dbus_error_init(&err); + + /* connect to the DBUS system bus, and check for errors */ + g_ui_conn_sender = dbus_bus_get_private(DBUS_BUS_SESSION, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "Dbus Connection Error (%s)", err.message); + dbus_error_free(&err); + } + + if (NULL == g_ui_conn_sender) { + SLOG(LOG_ERROR, TAG_MAUI, "Fail to get dbus connection "); + return MA_ERROR_OPERATION_FAILED; + } + + dbus_connection_set_exit_on_disconnect(g_ui_conn_sender, false); + + /* connect to the DBUS system bus, and check for errors */ + g_ui_conn_listener = dbus_bus_get_private(DBUS_BUS_SESSION, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "Dbus Connection Error (%s)", err.message); + dbus_error_free(&err); + } + + if (NULL == g_ui_conn_listener) { + SLOG(LOG_ERROR, TAG_MAUI, "Fail to get dbus connection "); + __ma_ui_dbus_connection_free(); + return MA_ERROR_OPERATION_FAILED; + } + + dbus_connection_set_exit_on_disconnect(g_ui_conn_listener, false); + + SLOG(LOG_DEBUG, TAG_MAUI, "service name is %s", MA_UI_CLIENT_SERVICE_NAME); + + /* register our name on the bus, and check for errors */ + ret = dbus_bus_request_name(g_ui_conn_listener, MA_UI_CLIENT_SERVICE_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "Name Error (%s)", err.message); + dbus_error_free(&err); + } + + if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "fail dbus_bus_request_name()"); + __ma_ui_dbus_connection_free(); + return -2; + } + + if (NULL != g_ui_fd_handler) { + SLOG(LOG_WARN, TAG_MAUI, "The handler already exists."); + __ma_ui_dbus_connection_free(); + return 0; + } + + /* Flush messages which are received before fd event handler registration */ + while (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_get_dispatch_status(g_ui_conn_listener)) { + ma_ui_listener_event_callback(NULL, NULL); + } + + char rule[128] = {0, }; + snprintf(rule, 128, "type='signal',interface='%s'", MA_UI_CLIENT_SERVICE_INTERFACE); + + /* add a rule for which messages we want to see */ + dbus_bus_add_match(g_ui_conn_listener, rule, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "Match Error (%s)", err.message); + dbus_error_free(&err); + __ma_ui_dbus_connection_free(); + return MA_ERROR_OPERATION_FAILED; + } + + int fd = 0; + if (1 != dbus_connection_get_unix_fd(g_ui_conn_listener, &fd)) { + SLOG(LOG_ERROR, TAG_MAUI, "fail to get fd from dbus "); + __ma_ui_dbus_connection_free(); + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "Get fd from dbus : %d", fd); + } + + g_ui_fd_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, (Ecore_Fd_Cb)ma_ui_listener_event_callback, g_ui_conn_listener, NULL, NULL); + + if (NULL == g_ui_fd_handler) { + SLOG(LOG_ERROR, TAG_MAUI, "fail to get fd handler from ecore "); + __ma_ui_dbus_connection_free(); + return MA_ERROR_OPERATION_FAILED; + } + + return 0;} + +int ma_ui_dbus_close_connection() +{ + DBusError err; + dbus_error_init(&err); + + if (NULL != g_ui_fd_handler) { + ecore_main_fd_handler_del(g_ui_fd_handler); + g_ui_fd_handler = NULL; + } + + if (NULL != g_ui_conn_listener) { +// int pid = getpid(); + + char service_name[64]; + memset(service_name, '\0', 64); +// snprintf(service_name, 64, "%s%d", MA_UI_CLIENT_SERVICE_NAME, pid); + snprintf(service_name, 64, "%s", MA_UI_CLIENT_SERVICE_NAME); + + dbus_bus_release_name(g_ui_conn_listener, service_name, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } + } + + __ma_ui_dbus_connection_free(); + + return 0; +} + +int ma_ui_dbus_reconnect() +{ + if (!g_ui_conn_sender || !g_ui_conn_listener) { + ma_ui_dbus_close_connection(); + + if (0 != ma_ui_dbus_open_connection()) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to reconnect"); + return -1; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[DBUS] Reconnect"); + return 0; + } + + bool sender_connected = dbus_connection_get_is_connected(g_ui_conn_sender); + bool listener_connected = dbus_connection_get_is_connected(g_ui_conn_listener); + + SLOG(LOG_DEBUG, TAG_MAUI, "[DBUS] Sender(%s) Listener(%s)", + sender_connected ? "Connected" : "Not connected", listener_connected ? "Connected" : "Not connected"); + + if (false == sender_connected || false == listener_connected) { + ma_ui_dbus_close_connection(); + + if (0 != ma_ui_dbus_open_connection()) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to reconnect"); + return -1; + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[DBUS] Reconnect"); + } + + return 0; +} + +int ma_ui_dbus_request_hello() +{ + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_METHOD_HELLO); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Request vc hello : Fail to make message"); + return MA_ERROR_OPERATION_FAILED; + } + + DBusError err; + dbus_error_init(&err); + + DBusMessage* result_msg = NULL; + int result = 0; + + result_msg = dbus_connection_send_with_reply_and_block(g_ui_conn_sender, msg, -1, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_DEBUG, TAG_MAUI, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } + + dbus_message_unref(msg); + + if (NULL != result_msg) { + dbus_message_unref(result_msg); + result = 0; + } else { + result = MA_ERROR_TIMED_OUT; + } + + return result; +} + +static int __dbus_restore_daemon() +{ + int ret = -1; + int count = 0; + while (0 != ret) { + ret = ma_ui_dbus_request_hello(); + if (0 != ret) { + if (MA_ERROR_TIMED_OUT != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to restore daemon"); + break; + } else { + SLOG(LOG_WARN, TAG_MAUI, "[WARNING] retry restore daemon"); + usleep(10000); + count++; + if (MA_RETRY_COUNT == count) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to request"); + break; + } + } + } else { + SLOG(LOG_ERROR, TAG_MAUI, "[SUCCESS] restore daemon"); + } + } + return ret; +} + +int ma_ui_dbus_request_initialize(int pid) +{ + DBusError err; + dbus_error_init(&err); + + bool exist = dbus_bus_name_has_owner(g_ui_conn_sender, MA_SERVER_SERVICE_NAME, &err); + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } + + int ret; + if (false == exist) { + ret = __dbus_restore_daemon(); + if (MA_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to restore daemon"); + return MA_ERROR_TIMED_OUT; + } + return MA_ERROR_OPERATION_FAILED; + } + + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_UI_METHOD_INITIALIZE); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] multi-assistant ui initialize : Fail to make message "); + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[ERROR] multi-assistant ui initialize : pid(%d)", pid); + } + + dbus_message_append_args(msg, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INVALID); + + DBusMessage* result_msg; + int result = MA_ERROR_OPERATION_FAILED; + + result_msg = dbus_connection_send_with_reply_and_block(g_ui_conn_sender, msg, g_ui_waiting_time, &err); + dbus_message_unref(msg); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } + + if (NULL != result_msg) { + dbus_message_get_args(result_msg, &err, + DBUS_TYPE_INT32, &result, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Get arguments error (%s)", err.message); + dbus_error_free(&err); + result = MA_ERROR_OPERATION_FAILED; + } + + dbus_message_unref(result_msg); + + if (0 == result) { + /* add a rule for daemon error */ + char rule_err[256] = {0, }; + snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", MA_SERVER_SERVICE_INTERFACE); + dbus_bus_add_match(g_ui_conn_listener, rule_err, &err); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "Match Error (%s)", err.message); + dbus_error_free(&err); + } + + SLOG(LOG_DEBUG, TAG_MAUI, "[ERROR] multi-assistant ui initialize : result = %d", result); + } else { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] multi-assistant ui initialize : result = %d", result); + } + } else { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Result message is NULL "); + ma_ui_dbus_reconnect(); + result = MA_ERROR_TIMED_OUT; + } + + return result;} + +int ma_ui_dbus_request_deinitialize(int pid) +{ + DBusError err; + dbus_error_init(&err); + + bool exist = dbus_bus_name_has_owner(g_ui_conn_sender, MA_SERVER_SERVICE_NAME, &err); + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } + + int ret; + if (false == exist) { + ret = __dbus_restore_daemon(); + if (MA_ERROR_NONE != ret) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Fail to restore daemon"); + return MA_ERROR_TIMED_OUT; + } + return MA_ERROR_OPERATION_FAILED; + } + + /* remove a rule for daemon error */ + char rule_err[256] = {0, }; + snprintf(rule_err, 256, "sender='org.freedesktop.DBus',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',type='signal',arg0='%s'", MA_SERVER_SERVICE_INTERFACE); + dbus_bus_remove_match(g_ui_conn_listener, rule_err, &err); + dbus_connection_flush(g_ui_conn_listener); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "Match Error (%s)", err.message); + dbus_error_free(&err); + return MA_ERROR_OPERATION_FAILED; + } + + DBusMessage* msg; + + msg = dbus_message_new_method_call( + MA_SERVER_SERVICE_NAME, + MA_SERVER_SERVICE_OBJECT_PATH, + MA_SERVER_SERVICE_INTERFACE, + MA_UI_METHOD_DEINITIALIZE); + + if (NULL == msg) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] multi-assistant ui finalize : Fail to make message "); + return MA_ERROR_OPERATION_FAILED; + } else { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] multi-assistant ui finalize : pid(%d)", pid); + } + + dbus_message_append_args(msg, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID); + + DBusMessage* result_msg; + int result = MA_ERROR_OPERATION_FAILED; + + result_msg = dbus_connection_send_with_reply_and_block(g_ui_conn_sender, msg, g_ui_waiting_time, &err); + dbus_message_unref(msg); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Dbus Error (%s)", err.message); + dbus_error_free(&err); + } + + if (NULL != result_msg) { + dbus_message_get_args(result_msg, &err, + DBUS_TYPE_INT32, &result, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set(&err)) { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Get arguments error (%s)", err.message); + dbus_error_free(&err); + result = MA_ERROR_OPERATION_FAILED; + } + + dbus_message_unref(result_msg); + + if (0 == result) { + SLOG(LOG_DEBUG, TAG_MAUI, "[DEBUG] multi-assistant ui finalize : result = %d", result); + } else { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] multi-assistant ui finalize : result = %d", result); + } + } else { + SLOG(LOG_ERROR, TAG_MAUI, "[ERROR] Result message is NULL "); + ma_ui_dbus_reconnect(); + result = MA_ERROR_TIMED_OUT; + } + + return result; +} + diff --git a/client/ma_ui_dbus.h b/client/ma_ui_dbus.h new file mode 100644 index 0000000..ac7ea2d --- /dev/null +++ b/client/ma_ui_dbus.h @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __MA_UI_DBUS_H__ +#define __MA_UI_DBUS_H__ + +#include "multi_assistant_common.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +int ma_ui_dbus_open_connection(); + +int ma_ui_dbus_close_connection(); + + +int ma_ui_dbus_request_hello(); + +int ma_ui_dbus_request_initialize(int pid); + +int ma_ui_dbus_request_deinitialize(int pid); + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __MA_UI_DBUS_H__ */ + diff --git a/common/ma_config_mgr.c b/common/ma_config_mgr.c new file mode 100644 index 0000000..9330317 --- /dev/null +++ b/common/ma_config_mgr.c @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "ma_config_mgr.h" +#include "ma_main.h" + +typedef struct { + int uid; + ma_config_lang_changed_cb lang_cb; +} ma_config_client_s; + + +//static GSList* g_config_client_list = NULL; + +//static pthread_mutex_t ma_config_mgr_mutex = PTHREAD_MUTEX_INITIALIZER; + + +int ma_config_mgr_initialize(int uid) +{ + return 0; +} +int ma_config_mgr_deinitialize(int uid) +{ + return 0; +} + +int ma_config_mgr_get_default_language(char** language) +{ + return 0; +} + +int ma_config_mgr_get_assistant_info(ma_ui_assistant_info_cb callback, void* user_data) +{ + return 0; +} + +int ma_config_mgr_set_default_assistant(const char* app_id) +{ + return 0; +} + +int ma_config_mgr_change_assistant(const char* app_id) +{ + return 0; +} + + +int ma_config_mgr_set_lang_cb(int uid, ma_config_lang_changed_cb lang_cb) +{ + return 0; +} + +int ma_config_mgr_unset_lang_cb(int uid) +{ + return 0; +} + diff --git a/common/ma_config_mgr.h b/common/ma_config_mgr.h new file mode 100644 index 0000000..b4e458a --- /dev/null +++ b/common/ma_config_mgr.h @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __MA_CONFIG_MGR_H__ +#define __MA_CONFIG_MGR_H__ + +#include "ma_defs.h" +#include "multi_assistant_ui.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +typedef void (*ma_config_lang_changed_cb)(const char* previous_lang, const char* current_lang); + +int ma_config_mgr_initialize(int uid); + +int ma_config_mgr_deinitialize(int uid); + +int ma_config_mgr_get_default_language(char** language); + +int ma_config_mgr_get_assistant_info(ma_ui_assistant_info_cb callback, void* user_data); + +int ma_config_mgr_set_default_assistant(const char* app_id); + +int ma_config_mgr_change_assistant(const char* app_id); + + +int ma_config_mgr_set_lang_cb(int uid, ma_config_lang_changed_cb lang_cb); + +int ma_config_mgr_unset_lang_cb(int uid); + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __MA_CONFIG_MGR_H__ */ + diff --git a/common/ma_defs.h b/common/ma_defs.h new file mode 100644 index 0000000..71d8932 --- /dev/null +++ b/common/ma_defs.h @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __MA_DEFS_H__ +#define __MA_DEFS_H__ + +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/************************************************************************************** + *** Definitions for configurations + *************************************************************************************/ +#define MA_FEATURE_PATH "tizen.org/feature/multi_assistant" +#define MA_MIC_FEATURE_PATH "tizen.org/feature/microphone" + +#define MA_PRIVILEGE "http://tizen.org/privilege/recorder" + +#define MA_DEFAULT_BASE tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "multiassistant/ma/1.0") +#define MA_DEFAULT_CONFIG tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "multiassistant/ma/1.0/ma-config.xml") +#define MA_BASE tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.multiassistant"); +#define MA_CONFIG tzplatform_mkpath(tzplatform_getid("TZ_USER_HOME"), "share/.multiassistant/ma-config.xml") + +/************************************************************************************** + *** Definitions for DBus + *************************************************************************************/ +#define MA_CLIENT_SERVICE_NAME "org.tizen.multiassistant.maclient" +#define MA_CLIENT_SERVICE_OBJECT_PATH "/org/tizen/multiassistant/maclient" +#define MA_CLIENT_SERVICE_INTERFACE "org.tizen.multiassistant.maclient" + +#define MA_UI_CLIENT_SERVICE_NAME "org.tizen.multiassistant.mauiclient" +#define MA_UI_CLIENT_SERVICE_OBJECT_PATH "/org/tizen/multiassistant/mauiclient" +#define MA_UI_CLIENT_SERVICE_INTERFACE "org.tizen.multiassistant.mauiclient" + +#define MA_SERVER_SERVICE_NAME "org.tizen.multiassistant.maserver" +#define MA_SERVER_SERVICE_OBJECT_PATH "/org/tizen/multiassistant/maserver" +#define MA_SERVER_SERVICE_INTERFACE "org.tizen.multiassistant.maserver" + +/************************************************************************************** + *** Definitions for DBus methods + *************************************************************************************/ +#define MA_METHOD_HELLO "ma_method_hello" + +#define MA_METHOD_INITIALIZE "ma_method_initialize" +#define MA_METHOD_DEINITIALIZE "ma_method_deinitialize" +#define MA_METHOD_GET_RECORDING_AUDIO_FORMAT "ma_method_get_recording_audio_format" +#define MA_METHOD_SEND_ASR_RESULT "ma_method_send_asr_result" +#define MA_METHOD_SEND_RESULT "ma_method_send_result" + +#define MA_UI_METHOD_INITIALIZE "ma_ui_method_initialize" +#define MA_UI_METHOD_DEINITIALIZE "ma_ui_method_deinitialize" +#define MA_UI_METHOD_CHANGE_ASSISTANT "ma_ui_method_change_assistant" + +#define MAS_METHOD_HELLO "mas_method_hello" +#define MAS_METHOD_SEND_SPEECH_DATA "mas_method_send_speech_data" +#define MAS_METHOD_ERROR "mas_method_error" + +#define MAS_UI_METHOD_HELLO "mas_ui_method_hello" +#define MAS_UI_METHOD_SEND_ASR_RESULT "mas_ui_method_send_asr_result" +#define MAS_UI_METHOD_SEND_RESULT "mas_ui_method_send_result" +#define MAS_UI_METHOD_ERROR "mas_ui_method_error" + + +/************************************************************************************** + *** Definitions for ETC + *************************************************************************************/ +#define MA_RETRY_COUNT 5 + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __MA_DEFS_H__ */ + diff --git a/common/ma_main.h b/common/ma_main.h new file mode 100644 index 0000000..efceee8 --- /dev/null +++ b/common/ma_main.h @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __MA_MAIN_H__ +#define __MA_MAIN_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/************************************************************************************** + *** Definitions for log tags + *************************************************************************************/ +#define TAG_MAC "mac" /* Multi-assistant client log tag */ +#define TAG_MAUI "maui" /* Multi-assistant UI client log tag */ + +/************************************************************************************** + *** Structures for multi-assistant handle + *************************************************************************************/ +struct ma_s { + int handle; +}; + +typedef struct ma_s *ma_h; + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __MA_MAIN_H__ */ + diff --git a/doc/uix_ma_doc.h b/doc/uix_ma_doc.h new file mode 100644 index 0000000..f20b35f --- /dev/null +++ b/doc/uix_ma_doc.h @@ -0,0 +1,210 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __TIZEN_UIX_MULTI_ASSISTANT_DOC_H__ +#define __TIZEN_UIX_MULTI_ASSISTANT_DOC_H__ + + +/** + * @ingroup CAPI_UIX_FRAMEWORK + * @defgroup CAPI_UIX_MULTI_ASSISTANT_MODULE Multi assistant + * @brief The @ref CAPI_UIX_MULTI_ASSISTANT_MODULE provides functions for supporting users to use several assistants. + * @section CAPI_UIX_MULTI_ASSISTANT_MODULE_HEADER Required Header + * \#include
+ * + * @section CAPI_UIX_MULTI_ASSISTANT_MODULE_OVERVIEW Overview + * A main function of Voice Control API register command and gets notification for recognition result. + * Applications can add their own commands and be provided result when their command is recognized by user voice input. + * To use of Voice Control, use the following steps:
+ * 1. Initialize
+ * 2. Register callback functions for notifications
+ * 3. Connect to voice control service asynchronously. The state should be changed to Ready
+ * 4. Make command list as the following step and Step 4 is called repeatedly for each command which an application wants
+ * 4-1. Create command list handle
+ * 4-2. Create command handle
+ * 4-3. Set command and type for command handle
+ * 4-4. Add command handle to command list
+ * 5. Set command list for recognition
+ * 6. Set an invocation name for an application
+ * 7. Get recognition results
+ * 8. Request the dialogue
+ * 9. If an application wants to finish voice control,
+ * 9-1. Destroy command and command list handle
+ * 9-2. Deinitialize
+ * An application can obtain command handle from command list, and also get information from handle. + * The Voice Control API also notifies you (by callback mechanism) when the states of client and service are changed, + * command is recognized, current language is changed or error occurred. + * An application should register callback functions: vc_state_changed_cb(), vc_service_state_changed_cb(), vc_result_cb(), + * vc_current_language_changed_cb(), vc_error_cb(). + * + * @section CAPI_UIX_MULTI_ASSISTANT_MODULE_STATE_DIAGRAM State Diagram + * The following diagram shows the life cycle and the states of the Voice Control. + * + * @image html capi_uix_voice_control_state_diagram.png " " + * The following diagram shows the states of Voice Control service. + * + * @image html capi_uix_voice_control_service_state_diagram.png "" + * + * @section CAPI_UIX_MULTI_ASSISTANT_MODULE_STATE_TRANSITIONS State Transitions + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * +* +*
FUNCTIONPRE-STATEPOST-STATESYNC TYPE
vc_initialize()NoneInitializedSYNC
vc_deinitialize()InitializedNoneSYNC
vc_prepare()InitializedReadyASYNC
vc_unprepare()ReadyInitializedSYNC
+* +* @section CAPI_UIX_MULTI_ASSISTANT_MODULE_STATE_DEPENDENT_FUNCTION_CALLS State Dependent Function Calls +* The following table shows state-dependent function calls. +* It is forbidden to call functions listed below in wrong states. +* Violation of this rule may result in an unpredictable behavior. +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +* +*
FUNCTIONVALID STATESDESCRIPTION
vc_initialize()NoneAll functions must be called after vc_initialize()
vc_deinitialize()Initialized, ReadyThis function should be called when an application want to finalize voice control using
vc_prepare()InitializedThis function works asynchronously. If service start is failed, application gets the error callback.
vc_unprepare()Ready
vc_foreach_supported_languages()Initialized, Ready
vc_get_current_language()Initialized, Ready
vc_get_state()Initialized, Ready
vc_get_service_state()Initialized, Ready
vc_get_result()Ready
vc_get_system_command_list()Ready
vc_set_command_list()Ready
vc_unset_command_list()Ready
vc_set_invocation_name()Ready
vc_set_server_dialog()Ready
vc_request_dialog()Ready
+* vc_set_result_cb()
+* vc_unset_result_cb()
+* vc_set_state_changed_cb()
+* vc_unset_state_changed_cb()
+* vc_set_service_state_changed_cb()
+* vc_unset_service_state_changed_cb()
+* vc_set_current_language_changed_cb()
+* vc_unset_current_language_changed_cb()
+* vc_set_error_cb()
+* vc_unset_error_cb()
Initialized All callback function should be registered in Initialized state
+* +* @section CAPI_UIX_MULTI_ASSISTANT_MODULE_FEATURES Related Features +* This API is related with the following features:
+* - http://tizen.org/feature/microphone
+* - http://tizen.org/feature/multi_assistant
+* It is recommended to use features in your application for reliability.
+* You can check if the device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, and control your application's actions accordingly.
+* To ensure your application is running only on devices with specific features, please define the features in your manifest file using the manifest editor in the SDK.
+* More details on using features in your application can be found in the feature element description. +*/ + + +#endif /* __TIZEN_UIX_MULTI_ASSISTANT_DOC_H__ */ + diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt new file mode 100644 index 0000000..43d40c3 --- /dev/null +++ b/include/CMakeLists.txt @@ -0,0 +1,12 @@ +## configure pkgconfig files ## +CONFIGURE_FILE(multi-assistant.pc.in multi-assistant.pc @ONLY) +CONFIGURE_FILE(multi-assistant-ui.pc.in multi-assistant-ui.pc @ONLY) + +## Install pc files ## +INSTALL(FILES ${CMAKE_BINARY_DIR}/include/multi-assistant.pc DESTINATION ${LIBDIR}/pkgconfig) +INSTALL(FILES ${CMAKE_BINARY_DIR}/include/multi-assistant-ui.pc DESTINATION ${LIBDIR}/pkgconfig) + +## Install header files ## +INSTALL(FILES ${CMAKE_BINARY_DIR}/include/multi_assistant.h DESTINATION ${INCLUDEDIR}) +INSTALL(FILES ${CMAKE_BINARY_DIR}/include/multi_assistant_ui.h DESTINATION ${INCLUDEDIR}) +INSTALL(FILES ${CMAKE_BINARY_DIR}/include/multi_assistant_common.h DESTINATION ${INCLUDEDIR}) diff --git a/include/multi-assistant-ui.pc.in b/include/multi-assistant-ui.pc.in new file mode 100644 index 0000000..e1e2a06 --- /dev/null +++ b/include/multi-assistant-ui.pc.in @@ -0,0 +1,11 @@ +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@ +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: lib@PROJECT_NAME@_manager +Description: Multi assistant UI client library +Requires: glib-2.0 dbus-1 capi-base-common +Version: @VERSION@ +Libs: -L${libdir} -l@PROJECT_NAME@_ui +Cflags: -I${includedir} diff --git a/include/multi-assistant.pc.in b/include/multi-assistant.pc.in new file mode 100644 index 0000000..72b5f1f --- /dev/null +++ b/include/multi-assistant.pc.in @@ -0,0 +1,11 @@ +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@ +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: lib@PROJECT_NAME@ +Description: Multi assistant client library +Requires: glib-2.0 dbus-1 capi-base-common +Version: @VERSION@ +Libs: -L${libdir} -l@PROJECT_NAME@ +Cflags: -I${includedir} diff --git a/include/multi_assistant.h b/include/multi_assistant.h new file mode 100644 index 0000000..8f16f76 --- /dev/null +++ b/include/multi_assistant.h @@ -0,0 +1,348 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __TIZEN_UIFW_MULTI_ASSISTANT_H__ +#define __TIZEN_UIFW_MULTI_ASSISTANT_H__ + +#include + + +/** + * @defgroup CAPI_UIX_MULTI_ASSISTANT_CLIENT_MODULE Multi assistant client + * @ingroup CAPI_UIX_MULTI_ASSISTANT_MODULE + * @brief The @ref CAPI_UIX_MULTI_ASSISTANT_CLIENT_MODULE API provides functions for getting queries from multi assistant service and sending responses. + * @{ + */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + +/** + * @brief Initializes multi-assistant client. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_OPERATION_FAILED Operation failed + * @retval #MA_ERROR_OUT_OF_MEMORY Out of memory + * + * @post If this function is called, the state will be #MA_STATE_INITIALIZED. + * @see ma_deinitialize() + */ +int ma_initialize(void); + +/** + * @brief Deinitializes multi-assistant client. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @post If this function is called, the state will be #MA_STATE_NONE. + * @see ma_initialize() + */ +int ma_deinitialize(void); + +/** + * @brief Prepares multi-assistant client. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @post If this function is called, the state will be #MA_STATE_READY. + * @see ma_unprepare() + */ +int ma_prepare(void); + +/** + * @brief Unprepares multi-assistant client. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_READY. + * @post If this function is called, the state will be #MA_STATE_INITIALIZED. + * @see ma_prepare() + */ +int ma_unprepare(void); + +/** + * @brief Gets the current state of the multi-assistant client. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @param[out] state The current state + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + */ +int ma_get_state(ma_state_e* state); + +/** + * @brief Gets the current language of multi-assistant client. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @remarks The @a language should be released using free(). + * @param[out] language The current language + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + */ +int ma_get_current_language(char** language); + +/** + * @brief Gets the recording audio format. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @param[out] rate The audio sampling rate + * @param[out] channel The audio channel + * @param[out] audio_type The audio type + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MA_ERROR_OPERATION_FAILED Operation failed + * + * @pre The state should be #MA_STATE_READY. + */ +int ma_get_recording_audio_format(int* rate, ma_audio_channel_e* channel, ma_audio_type_e* audio_type); + +/** + * @brief Sets a state changed callback. + * @since_tizen 5.0 + * + * @param[in] callback The callback + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_state_changed_cb() + * @see ma_unset_state_changed_cb() + */ +int ma_set_state_changed_cb(ma_state_changed_cb callback, void* user_data); + +/** + * @brief Unsets a state changed callback. + * @since_tizen 5.0 + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_state_changed_cb() + * @see ma_set_state_changed_cb() + */ +int ma_unset_state_changed_cb(void); + +/** + * @brief Sets an error callback. + * @since_tizen 5.0 + * + * @param[in] callback The callback + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_error_cb() + * @see ma_unset_errord_cb() + */ +int ma_set_error_cb(ma_error_cb callback, void* user_data); + +/** + * @brief Unsets an error callback. + * @since_tizen 5.0 + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_error_cb() + * @see ma_set_error_cb() + */ +int ma_unset_error_cb(void); + +/** + * @brief Sets a language changed callback. + * @since_tizen 5.0 + * + * @param[in] callback The callback + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_language_changed_cb() + * @see ma_unset_language_changed_cb() + */ +int ma_set_language_changed_cb(ma_language_changed_cb callback, void* user_data); + +/** + * @brief Unsets a language changed callback. + * @since_tizen 5.0 + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_language_changed_cb() + * @see ma_set_language_changed_cb() + */ +int ma_unset_language_changed_cb(void); + +/** + * @brief Sets an audio streaming callback. + * @since_tizen 5.0 + * + * @param[in] callback The callback + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_audio_streaming_cb() + * @see ma_unset_audio_streaming_cb() + */ +int ma_set_audio_streaming_cb(ma_audio_streaming_cb callback, void* user_data); + +/** + * @brief Unsets an audio streaming callback. + * @since_tizen 5.0 + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_audio_streaming_cb() + * @see ma_set_audio_streaming_cb() + */ +int ma_unset_audio_streaming_cb(void); + +/** + * @brief Sends ASR(auto speech recognition) results to the multi-assistant service. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @param[in] event The ASR result event (e.g. #MA_ASR_RESULT_EVENT_FINAL) + * @param[in] asr_result The ASR result text + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + */ +int ma_send_asr_result(ma_asr_result_event_e event, const char* asr_result); + +/** + * @brief Sends results to the multi-assistant service. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @param[in] display_text The text shown on the display + * @param[in] utterance_text The utterance text + * @param[in] result_json The result data (JSON format) + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + */ +int ma_send_result(const char* display_text, const char* utterance_text, const char* result_json); + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __TIZEN_UIFW_MULTI_ASSISTANT_H__ */ diff --git a/include/multi_assistant_common.h b/include/multi_assistant_common.h new file mode 100644 index 0000000..13115cc --- /dev/null +++ b/include/multi_assistant_common.h @@ -0,0 +1,181 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __TIZEN_UIFW_MULTI_ASSISTANT_COMMON_H__ +#define __TIZEN_UIFW_MULTI_ASSISTANT_COMMON_H__ + +#include + +/** + * @addtogroup CAPI_UIX_MULTI_ASSISTANT_MODULE + * @{ + */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/** + * @brief Enumerations for multi-assistant error codes. + * @since_tizen 5.0 + */ +typedef enum { + MA_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ + MA_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of Memory */ + MA_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< I/O error */ + MA_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + MA_ERROR_TIMED_OUT = TIZEN_ERROR_TIMED_OUT, /**< No answer from service */ + MA_ERROR_RECORDER_BUSY = TIZEN_ERROR_RESOURCE_BUSY, /**< Busy recorder */ + MA_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ + MA_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Multi-assistant NOT supported */ + MA_ERROR_INVALID_STATE = TIZEN_ERROR_MULTI_ASSISTANT | 0x011, /**< Invalid state */ + MA_ERROR_INVALID_LANGUAGE = TIZEN_ERROR_MULTI_ASSISTANT | 0x012, /**< Invalid language */ + MA_ERROR_ENGINE_NOT_FOUND = TIZEN_ERROR_MULTI_ASSISTANT | 0x013, /**< No available engine */ + MA_ERROR_OPERATION_FAILED = TIZEN_ERROR_MULTI_ASSISTANT | 0x014, /**< Operation failed */ + MA_ERROR_SERVICE_RESET = TIZEN_ERROR_MULTI_ASSISTANT | 0x015, /**< Service daemon reset */ + MA_ERROR_NOT_SUPPORTED_FEATURE = TIZEN_ERROR_MULTI_ASSISTANT | 0x016 /**< Not supported feature of current engine */ +} ma_error_e; + +/** + * @brief Enumerations for multi-assistant client state. + * @since_tizen 5.0 + */ +typedef enum { + MA_STATE_NONE = 0, /**< 'None' state */ + MA_STATE_INITIALIZED = 1, /**< 'Initialized' state */ + MA_STATE_READY = 2 /**< 'Ready' state */ +} ma_state_e; + +/** + * @brief Enumerations for multi-assistant audio streaming events. + * @since_tizen 5.0 + */ +typedef enum { + MA_AUDIO_STREAMING_EVENT_FAIL = -1, /**< Failed */ + MA_AUDIO_STREAMING_EVENT_START = 1, /**< Start event */ + MA_AUDIO_STREAMING_EVENT_CONTINUE = 2, /**< Continue event */ + MA_AUDIO_STREAMING_EVENT_FINISH = 3 /**< Finish event */ +} ma_audio_streaming_event_e; + +/** + * @brief Enumerations for audio types. + * @since_tizen 5.0 + */ +typedef enum { + MA_AUDIO_TYPE_PCM_S16_LE = 0, /**< Signed 16bit audio type, Little endian */ + MA_AUDIO_TYPE_PCM_U8 /**< Unsigned 8bit audio type */ +} ma_audio_type_e; + +/** + * @brief Enumerations for audio channels. + * @since_tizen 5.0 + */ +typedef enum { + MA_AUDIO_CHANNEL_MONO = 0, /**< 1 channel, mono */ + MA_AUDIO_CHANNEL_STEREO = 1 /**< 2 channels, stereo */ +} ma_audio_channel_e; + +/** + * @brief Enumerations for ASR result events. + * @since_tizen 5.0 + */ +typedef enum { + MA_ASR_RESULT_EVENT_PARTIAL_RESULT = 0, /**< ASR result event for partial result */ + MA_ASR_RESULT_EVENT_FINAL_RESULT, /**< ASR result event for final result */ + MA_ASR_RESULT_EVENT_ERROR /**< ASR result event for error */ +} ma_asr_result_event_e; + + +/** + * @brief Called when the client state is changed. + * @since_tizen 5.0 + * + * @param[in] previous The previous state + * @param[in] current The current state + * @param[in] user_data The user data passed from the callback registration function + */ +typedef void (*ma_state_changed_cb)(ma_state_e previous, ma_state_e current, void* user_data); + +/** + * @brief Called when the error is occurred. + * @details The following error codes can be received: \n + * #MA_ERROR_NONE: Success \n + * #MA_ERROR_OUT_OF_MEMORY: Out of Memory \n + * #MA_ERROR_IO_ERROR: I/O error \n + * #MA_ERROR_INVALID_PARAMETER: Invalid parameter \n + * #MA_ERROR_TIMED_OUT: No answer from service \n + * #MA_ERROR_RECORDER_BUSY: Busy recorder \n + * #MA_ERROR_PERMISSION_DENIED: Permission denied \n + * #MA_ERROR_NOT_SUPPORTED: Multi-assistant NOT supported \n + * #MA_ERROR_INVALID_STATE: Invalid state \n + * #MA_ERROR_INVALID_LANGUAGE: Invalid language \n + * #MA_ERROR_ENGINE_NOT_FOUND: No available engine \n + * #MA_ERROR_OPERATION_FAILED: Operation failed \n + * #MA_ERROR_SERVICE_RESET: Service daemon reset \n + * #MA_ERROR_NOT_SUPPORTED_FEATURE: Not supported feature of current engine \n + * @since_tizen 5.0 + * + * @param[in] reason The error reason + * @param[in] user_data The user data passed from the callback registration function + */ +typedef void (*ma_error_cb)(ma_error_e reason, void* user_data); + +/** + * @brief Called when the default language is changed. + * @since_tizen 5.0 + * @remarks The @a previous can be used only in the callback. To use outside, make a copy. + * The @a current can be used only in the callback. To use outside, make a copy. + * + * @param[in] previous The previous language + * @param[in] current The current language + * @param[in] user_data The user data passed from the callback registration function + * + * @see ma_set_language_changed_cb() + * @see ma_unset_language_changed_cb() + */ +typedef void (*ma_language_changed_cb)(const char* previous, const char* current, void* user_data); + +/** + * @brief Called when the multi-assistant service sends audio streaming. + * @since_tizen 5.0 + * @remarks The @a buffer should not be released and can be used only in the callback. To use outside, make a copy. + * + * @param[in] event The audio streaming event + * @param[in] buffer The audio streaming data + * @param[in] len The length of the audio streaming data + * @param[in] user_data The user data passed from the callback registration function + * + * @see ma_set_audio_streaming_cb() + * @see ma_unset_audio_streaming_cb() + */ +typedef void (*ma_audio_streaming_cb)(ma_audio_streaming_event_e event, char* buffer, int len, void* user_data); + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __TIZEN_UIFW_MULTI_ASSISTANT_COMMON_H__ */ + diff --git a/include/multi_assistant_ui.h b/include/multi_assistant_ui.h new file mode 100644 index 0000000..5f8e1cc --- /dev/null +++ b/include/multi_assistant_ui.h @@ -0,0 +1,378 @@ +/** + * Copyright (c) 2011-2018 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __TIZEN_UIFW_MULTI_ASSISTANT_UI_H__ +#define __TIZEN_UIFW_MULTI_ASSISTANT_UI_H__ + +#include + +/** + * @addtogroup CAPI_UIX_MULTI_ASSISTANT_UI_MODULE + * @{ + */ + +/** + * @defgroup CAPI_UIX_MULTI_ASSISTANT_UI_MODULE Multi assistant UI + * @ingroup CAPI_UIX_MULTI_ASSISTANT_MODULE + * @brief The @ref CAPI_UIX_MULTI_ASSISTANT_UI_MODULE API provides functions for showing queries and responses sent from multi assistant service. + * @{ + */ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * @brief Called when the information of the assistants is requested. + * @since_tizen 5.0 + * @remarks The @a app_id can be used only in the callback. To use outside, make a copy. + * The @a name can be used only in the callback. To use outside, make a copy. + * The @a icon_path can be used only in the callback. To use outside, make a copy. + * The @a wakeup_list can be used only in the callback. To use outside, make a copy. + * The @a supported_lang can be used only in the callback. To use outside, make a copy. + * + * @param[in] app_id The app ID of the assistant + * @param[in] name The name of the assistant + * @param[in] icon_path The directory of the icon corresponding to the assistant + * @param[in] wakeup_list The list of wakeup words which invoke the assistant + * @param[in] cnt_wakeup The number of wakeup words + * @param[in] supported_lang The list of languages supported by the assistant + * @param[in] cnt_lang The number of languages supported by the assistant + * @param[in] user_data The user data passed from the callback registration function + * + * @see ma_ui_foreach_assistant_info() + */ +typedef int (*ma_ui_assistant_info_cb)(const char* app_id, const char* name, const char* icon_path, const char* wakeup_list[], int cnt_wakeup, const char* supported_lang[], int cnt_lang, void* user_data); + +/** + * @brief Called when the multi-assistant service sends the ASR results for showing at UI. + * @since_tizen 5.0 + * @remarks The @a asr_result can be used only in the callback. To use outside, make a copy. + * + * @param[in] event The ASR result event + * @param[in] asr_result The ASR result text + * @param[in] user_data The user data passed from the callback registration function + * + * @see ma_ui_set_asr_result_cb() + * @see ma_ui_unset_asr_result_cb() + */ +typedef void (*ma_ui_asr_result_cb)(ma_asr_result_event_e event, const char* asr_result, void* user_data); + +/** + * @brief Called when the multi-assistant service sends the results for showing at UI. + * @since_tizen 5.0 + * @remarks The @a display_text can be used only in the callback. To use outside, make a copy. + * The @a utterance_text can be used only in the callback. To use outside, make a copy. + * The @a result_json can be used only in the callback. To use outside, make a copy. + * + * @param[in] display_text The text shown on the display + * @param[in] utterance_text The utterance text + * @param[in] result_json The result data (JSON format) + * @param[in] user_data The user data passed from the callback registration function + * + * @see ma_ui_set_asr_result_cb() + * @see ma_ui_unset_asr_result_cb() + */ +typedef void (*ma_ui_result_cb)(const char* display_text, const char* utterance_text, const char* result_json, void* user_data); + + +/** + * @brief Initializes multi-assistant UI. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_OPERATION_FAILED Operation failed + * @retval #MA_ERROR_OUT_OF_MEMORY Out of memory + * + * @see ma_ui_deinitialize() + */ +int ma_ui_initialize(void); + +/** + * @brief Deinitializes multi-assistant UI. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @see ma_ui_initialize() + */ +int ma_ui_deinitialze(void); + +/** + * @brief Prepares multi-assistant UI. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @post If this function is called, the state will be #MA_STATE_READY. + * @see ma_ui_unprepare() + */ +int ma_ui_prepare(void); + +/** + * @brief Unprepares multi-assistant UI. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_READY. + * @post If this function is called, the state will be #MA_STATE_INITIALIZED. + * @see ma_ui_prepare() + */ +int ma_ui_unprepare(void); + +/** + * @brief Gets the current state of the multi-assistant UI. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @param[out] state The current state + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + */ +int ma_ui_get_state(ma_state_e* state); + +/** + * @brief Retreives the information for assistants. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @param[in] callback A callback for getting the information of the assistants + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see ma_ui_assistant_info_cb() + */ +int ma_ui_foreach_assistant_info(ma_ui_assistant_info_cb callback, void* user_data); + +/** + * @brief Sets the default assistant. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @param[in] app_id The app ID of the assistant + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + */ +int ma_ui_set_default_assistant(const char* app_id); + +/** + * @brief Changes the assistant. + * @since_tizen 5.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/recorder + * + * @param[in] app_id The app ID for the new assistant + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_PERMISSION_DENIED Permission denied + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + */ +int ma_ui_change_assistant(const char* app_id); + +/** + * @brief Sets a state changed callback. + * @since_tizen 5.0 + * + * @param[in] callback The callback + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_state_changed_cb() + * @see ma_unset_state_changed_cb() + */ +int ma_ui_set_state_changed_cb(ma_state_changed_cb callback, void* user_data); + +/** + * @brief Unsets a state changed callback. + * @since_tizen 5.0 + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_state_changed_cb() + * @see ma_ui_set_state_changed_cb() + */ +int ma_ui_unset_state_changed_cb(void); + +/** + * @brief Sets an error callback. + * @since_tizen 5.0 + * + * @param[in] callback The callback + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_error_cb() + * @see ma_ui_unset_error_cb() + */ +int ma_ui_set_error_cb(ma_error_cb callback, void* user_data); + +/** + * @brief Unsets an error callback. + * @since_tizen 5.0 + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + * @see ma_error_cb() + * @see ma_ui_set_error_cb() + */ +int ma_ui_unset_error_cb(void); + +/** + * @brief Sets a callback for getting ASR result. + * @since_tizen 5.0 + * + * @param[in] callback The callback function + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + */ +int ma_ui_set_asr_result_cb(ma_ui_asr_result_cb callback, void* user_data); + +/** + * @brief Unsets a callback for getting ASR result. + * @since_tizen 5.0 + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + */ +int ma_ui_unset_asr_result_cb(void); + +/** + * @brief Sets a callback for getting results. + * @since_tizen 5.0 + * + * @param[in] callback The callback function + * @param[in] user_data The user data passed to the callback function + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + */ +int ma_ui_set_result_cb(ma_ui_result_cb callback, void* user_data); + +/** + * @brief Unsets a callback for getting results. + * @since_tizen 5.0 + * + * @return @c 0 on success, otherwise a negative error value + * @retval #MA_ERROR_NONE Successful + * @retval #MA_ERROR_NOT_SUPPORTED Not supported + * @retval #MA_ERROR_INVALID_STATE Invalid state + * + * @pre The state should be #MA_STATE_INITIALIZED. + */ +int ma_ui_unset_result_cb(void); + + + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __TIZEN_UIFW_MULTI_ASSISTANT_UI_H__ */ + diff --git a/ma-config.xml b/ma-config.xml new file mode 100644 index 0000000..3b53ff2 --- /dev/null +++ b/ma-config.xml @@ -0,0 +1,6 @@ + + + com.samsung.tizen.bixby-assistant + com.samsung.tizen.bixby-assistant + en_US + diff --git a/ma-server.conf b/ma-server.conf new file mode 100644 index 0000000..d24d43c --- /dev/null +++ b/ma-server.conf @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/org.tizen.multiassistant.maclient.service b/org.tizen.multiassistant.maclient.service new file mode 100644 index 0000000..f8e5ef5 --- /dev/null +++ b/org.tizen.multiassistant.maclient.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.tizen.multiassistant.maclient +#Exec=/usr/bin/vc-daemon +Exec=/bin/sh -c "launch_app com.samsung.bixby-voice" +#Exec=/bin/sh -c "vc_getengine get system db/voice/vc/engine/default | awk '{print$5}' | xargs -t -i launch_app {}" diff --git a/org.tizen.multiassistant.mauiclient.service b/org.tizen.multiassistant.mauiclient.service new file mode 100644 index 0000000..d56d636 --- /dev/null +++ b/org.tizen.multiassistant.mauiclient.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.tizen.multiassistant.mauiclient +#Exec=/usr/bin/vc-daemon +Exec=/bin/sh -c "launch_app org.tizen.multi-assistant-panel" +#Exec=/bin/sh -c "vc_getengine get system db/voice/vc/engine/default | awk '{print$5}' | xargs -t -i launch_app {}" diff --git a/packaging/multi-assistant-devel.manifest b/packaging/multi-assistant-devel.manifest new file mode 100644 index 0000000..c00c25b --- /dev/null +++ b/packaging/multi-assistant-devel.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/multi-assistant.manifest b/packaging/multi-assistant.manifest new file mode 100644 index 0000000..c00c25b --- /dev/null +++ b/packaging/multi-assistant.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/multi-assistant.spec b/packaging/multi-assistant.spec new file mode 100644 index 0000000..f0add23 --- /dev/null +++ b/packaging/multi-assistant.spec @@ -0,0 +1,112 @@ +Name: multi-assistant +Summary: Multi Assistant client library and daemon +Version: 0.0.1 +Release: 1 +Group: Graphics & UI Framework/Voice Framework +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +Source1001: %{name}.manifest +Source1002: %{name}-devel.manifest +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +Requires: gawk +BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(capi-media-audio-io) +BuildRequires: pkgconfig(capi-media-sound-manager) +BuildRequires: pkgconfig(capi-system-info) +BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-session) +BuildRequires: pkgconfig(dbus-1) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(ecore-wayland) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(json-glib-1.0) +BuildRequires: pkgconfig(libgum) +BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(libxml-2.0) +BuildRequires: pkgconfig(pkgmgr-info) +BuildRequires: pkgconfig(pkgmgr-installer) +%if "%{tizen_profile_name}" == "tv" +BuildRequires: pkgconfig(capi-network-bluetooth) +BuildRequires: pkgconfig(capi-network-bluetooth-tv) +BuildRequires: pkgconfig(msfapi) +%endif +BuildRequires: pkgconfig(vconf) +BuildRequires: cmake + +%description +Multi assistant client library and daemon + + +%package devel +Summary: Multi assistant header files for MA development +Group: libdevel +Requires: %{name} = %{version}-%{release} + +%description devel +Multi assistant header files for MA development. + + +%package ui-devel +Summary: Multi assistant manager header files for MA development +Group: libdevel +Requires: %{name} = %{version}-%{release} + +%description ui-devel +Multi assistant manager header files for MA development. + + +%prep +%setup -q -n %{name}-%{version} +cp %{SOURCE1001} %{SOURCE1002} . + + +%build +%if "%{tizen_profile_name}" == "tv" +export CFLAGS="$CFLAGS -DTV_PRODUCT" +cmake . -DCMAKE_INSTALL_PREFIX=/usr -DLIBDIR=%{_libdir} -DBINDIR=%{_bindir} -DINCLUDEDIR=%{_includedir} \ + -DTZ_SYS_RO_SHARE=%TZ_SYS_RO_SHARE -D_TV_PRODUCT=TRUE -DTZ_SYS_BIN=%TZ_SYS_BIN +%else +cmake . -DCMAKE_INSTALL_PREFIX=/usr -DLIBDIR=%{_libdir} -DBINDIR=%{_bindir} -DINCLUDEDIR=%{_includedir} \ + -DTZ_SYS_RO_SHARE=%TZ_SYS_RO_SHARE -DTZ_SYS_BIN=%TZ_SYS_BIN +%endif +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} + +%make_install + +%post +/sbin/ldconfig + +mkdir -p %{_libdir}/multiassistant/ma + +%postun -p /sbin/ldconfig + +%files +%license LICENSE +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_libdir}/libma.so +%{_libdir}/libma_ui.so +%{TZ_SYS_RO_SHARE}/multiassistant/ma/1.0/ma-config.xml +%{TZ_SYS_RO_SHARE}/dbus-1/services/org.tizen.multiassistant* +/etc/dbus-1/session.d/ma-server.conf + +%files devel +%manifest %{name}-devel.manifest +%defattr(-,root,root,-) +%{_libdir}/pkgconfig/multi-assistant.pc +%{_includedir}/multi_assistant.h +%{_includedir}/multi_assistant_ui.h +%{_includedir}/multi_assistant_common.h + +%files ui-devel +%defattr(-,root,root,-) +%{_libdir}/pkgconfig/multi-assistant-ui.pc +%{_includedir}/multi_assistant_ui.h +%{_includedir}/multi_assistant_common.h + + diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt new file mode 100644 index 0000000..9b7e362 --- /dev/null +++ b/server/CMakeLists.txt @@ -0,0 +1,25 @@ +SET(SRCS +# mad_server.c +# mae.c +) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/common) +INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/include) + +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") +SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g -fPIE") +SET(CMAKE_C_FLAGS_RELEASE "-O2 -fPIE") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") + +## Executable ## +ADD_LIBRARY("${PROJECT_NAME}_engine" SHARED ${SRCS}) +TARGET_LINK_LIBRARIES("${PROJECT_NAME}_engine" -ldl ${pkgs_LDFLAGS}) + +## Install +INSTALL(TARGETS "${PROJECT_NAME}_engine" DESTINATION ${LIBDIR} COMPONENT RuntimeLibraries)