From: Ji-hoon Lee Date: Tue, 23 Oct 2018 02:21:14 +0000 (+0900) Subject: Read wakeup word information from xml file X-Git-Tag: submit/tizen/20181204.065424~11 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=07142dac9e5f4edeb063cfeced4cba543f01bb99;p=platform%2Fcore%2Fuifw%2Fwakeup-engine-default.git Read wakeup word information from xml file Change-Id: I0e90669cf153879ac14977c27050cdd0d95af526 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index df62d67..7c75002 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ pkg_check_modules(pkgs REQUIRED dbus-1 glib-2.0 message-port + libxml-2.0 ) @@ -61,7 +62,9 @@ LINK_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/inc) -SET(SRCS src/multi_assistant_service.c +SET(SRCS + src/multi_assistant_config.c + src/multi_assistant_service.c src/multi_assistant_service_plugin.c src/multi_assistant_dbus.c src/multi_assistant_dbus_server.c diff --git a/inc/multi_assistant_config.h b/inc/multi_assistant_config.h new file mode 100644 index 0000000..7d42902 --- /dev/null +++ b/inc/multi_assistant_config.h @@ -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. + */ + + +#ifndef __MULTI_ASSISTANT_CONFIG_H__ +#define __MULTI_ASSISTANT_CONFIG_H__ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MAX_WAKEUP_LIST_NUM 32 +#define MAX_SUPPORTED_LANGUAGE_NUM 128 + +/************************************************************************************** + *** Definitions for xml file + *************************************************************************************/ +#define MA_TAG_ASSISTANT_BASE "multi-assistant" +#define MA_TAG_ASSISTANT_NAME "name" +#define MA_TAG_ASSISTANT_ID "id" +#define MA_TAG_ASSISTANT_ICON_PATH "icon-path" +#define MA_TAG_ASSISTANT_LANGUAGE_SET "languages" +#define MA_TAG_ASSISTANT_LANGUAGE "lang" +#define MA_TAG_ASSISTANT_WAKEUP_WORD_SET "wakeup-words" +#define MA_TAG_ASSISTANT_WAKEUP_WORD "wakeup-word" + +/************************************************************************************** + *** Definitions for ETC + *************************************************************************************/ +#define MA_RETRY_COUNT 5 + +#define MA_ASSISTANT_INFO tzplatform_mkpath(TZ_USER_HOME, "share/.multiassistant/ma/1.0/assistant-info") + +typedef struct { + const char* app_id; + const char* name; + const char* icon_path; + const char* wakeup_list[MAX_WAKEUP_LIST_NUM]; + int cnt_wakeup; + const char* supported_lang[MAX_SUPPORTED_LANGUAGE_NUM]; + int cnt_lang; +} ma_assistant_info_s; + +typedef int (*mas_config_assistant_info_cb)(const char* appid, const char* name, const char* icon_path, const char* wakeup_list[], int cnt_wakeup, const char* supported_lang[], int cnt_lang, void* user_data); +int mas_config_get_assistant_info(mas_config_assistant_info_cb callback, void* user_data); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* __MULTI_ASSISTANT_CONFIG_H__ */ \ No newline at end of file diff --git a/packaging/org.tizen.multi-assistant-service.spec b/packaging/org.tizen.multi-assistant-service.spec index cf338bd..d359957 100644 --- a/packaging/org.tizen.multi-assistant-service.spec +++ b/packaging/org.tizen.multi-assistant-service.spec @@ -21,6 +21,7 @@ BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(message-port) +BuildRequires: pkgconfig(libxml-2.0) BuildRequires: boost-system BuildRequires: boost-thread diff --git a/src/multi_assistant_config.c b/src/multi_assistant_config.c new file mode 100644 index 0000000..fa47d3f --- /dev/null +++ b/src/multi_assistant_config.c @@ -0,0 +1,193 @@ +/** + * 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 "multi_assistant_config.h" +#include "multi_assistant_main.h" + +int mas_config_parse_assistant_info(mas_config_assistant_info_cb callback, const char *path, void* user_data) +{ + xmlDocPtr doc = NULL; + xmlNodePtr cur = NULL; + xmlChar *key; + + int loop; + int retry_count = 0; + + while (NULL == doc) { + doc = xmlParseFile(path); + if (NULL != doc) { + break; + } + + if (MA_RETRY_COUNT == retry_count++) { + MAS_LOGE("[ERROR] Fail to parse file error : %s", path); + xmlCleanupParser(); + return -1; + } + usleep(10000); + } + + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + MAS_LOGE("[ERROR] Empty document"); + xmlFreeDoc(doc); + return -1; + } + + if (xmlStrcmp(cur->name, (const xmlChar *) MA_TAG_ASSISTANT_BASE)) { + MAS_LOGE("[ERROR] The wrong type, root node is NOT %s", MA_TAG_ASSISTANT_BASE); + xmlFreeDoc(doc); + return -1; + } + + cur = cur->xmlChildrenNode; + if (cur == NULL) { + MAS_LOGE("[ERROR] Empty document"); + xmlFreeDoc(doc); + return -1; + } + + /* alloc assistant info */ + ma_assistant_info_s* temp; + temp = (ma_assistant_info_s*)calloc(1, sizeof(ma_assistant_info_s)); + if (NULL == temp) { + MAS_LOGE("[ERROR] Fail to allocate memory"); + xmlFreeDoc(doc); + return -1; + } + + temp->app_id = NULL; + temp->name = NULL; + temp->icon_path = NULL; + memset(temp->wakeup_list, 0x00, sizeof(temp->wakeup_list)); + temp->cnt_wakeup = 0; + memset(temp->supported_lang, 0x00, sizeof(temp->supported_lang)); + temp->cnt_lang = 0; + + while (cur != NULL) { + if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar *)MA_TAG_ASSISTANT_LANGUAGE_SET)) { + xmlNodePtr child_node = cur->xmlChildrenNode; + while (child_node != NULL) { + if (child_node->name && 0 == xmlStrcmp(child_node->name, (const xmlChar*)MA_TAG_ASSISTANT_LANGUAGE)) { + key = xmlNodeGetContent(child_node); + if (key) { + temp->supported_lang[temp->cnt_lang++] = strdup((const char*)key); + MAS_LOGD("Language : %s", key); + xmlFree(key); + } + } + + child_node = child_node->next; + } + } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar *)MA_TAG_ASSISTANT_WAKEUP_WORD_SET)) { + xmlNodePtr child_node = cur->xmlChildrenNode; + while (child_node != NULL) { + if (child_node->name && 0 == xmlStrcmp(child_node->name, (const xmlChar*)MA_TAG_ASSISTANT_WAKEUP_WORD)) { + key = xmlNodeGetContent(child_node); + if (key) { + temp->wakeup_list[temp->cnt_wakeup++] = strdup((const char*)key); + MAS_LOGD("Wakeup Word : %s", key); + xmlFree(key); + } + } + + child_node = child_node->next; + } + } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_NAME)) { + key = xmlNodeGetContent(cur); + if (key) { + temp->name = strdup((const char*)key); + MAS_LOGD("Name : %s", key); + xmlFree(key); + } + } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_ID)) { + key = xmlNodeGetContent(cur); + if (key) { + temp->app_id = strdup((const char*)key); + MAS_LOGD("ID : %s", key); + xmlFree(key); + } + } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_ICON_PATH)) { + key = xmlNodeGetContent(cur); + if (key) { + temp->icon_path = strdup((const char*)key); + MAS_LOGD("Icon Path : %s", key); + xmlFree(key); + } + } + + cur = cur->next; + } + + if (callback) { + callback(temp->app_id, temp->name, temp->icon_path, + temp->wakeup_list, temp->cnt_wakeup, temp->supported_lang, temp->cnt_lang, user_data); + } + + if (temp->app_id) { + free((void*)temp->app_id); + } + if (temp->name) { + free((void*)temp->name); + } + if (temp->icon_path) { + free((void*)temp->icon_path); + } + for (loop = 0; loop < temp->cnt_wakeup; loop++) { + if (temp->wakeup_list[loop]) { + free((void*)(temp->wakeup_list[loop])); + } + } + for (loop = 0; loop < temp->cnt_lang; loop++) { + if (temp->supported_lang[loop]) { + free((void*)(temp->supported_lang[loop])); + } + } + + free(temp); + xmlFreeDoc(doc); + + return 0; +} + +int mas_config_get_assistant_info(mas_config_assistant_info_cb callback, void* user_data) +{ + const char *suffix = ".xml"; + + DIR *d; + struct dirent *dir; + d = opendir(MA_ASSISTANT_INFO); + + if (d) { + while (NULL != (dir = readdir(d))) { + if (suffix && dir->d_name && strlen(suffix) <= strlen(dir->d_name)) { + if (0 == strcmp(dir->d_name + strlen(dir->d_name) - strlen(suffix), suffix)) { + char fullpath[_POSIX_PATH_MAX]; + snprintf(fullpath, _POSIX_PATH_MAX - 1, "%s/%s", MA_ASSISTANT_INFO, dir->d_name); + MAS_LOGD("Parsing file : %s\n", fullpath); + mas_config_parse_assistant_info(callback, fullpath, user_data); + } + } + } + closedir(d); + } + + return 0; +} \ No newline at end of file diff --git a/src/multi_assistant_service.c b/src/multi_assistant_service.c index 339b8ed..16011cc 100644 --- a/src/multi_assistant_service.c +++ b/src/multi_assistant_service.c @@ -32,23 +32,21 @@ #include "multi_assistant_service.h" #include "multi_assistant_service_plugin.h" #include "multi_assistant_dbus.h" +#include "multi_assistant_config.h" static const char *g_current_lang = "en_US"; static int g_local_port_id = -1; #define MAX_MACLIENT_INFO_NUM 16 +#define MAX_WAKEUP_WORDS_NUM 4 #define MAX_WAKEUP_WORD_LEN 255 typedef struct { Eina_Bool used; - const char wakeup_word[MAX_WAKEUP_WORD_LEN]; - const char appid[MAX_APPID_LEN]; + char appid[MAX_APPID_LEN]; + char wakeup_word[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN]; } ma_client_info; -static ma_client_info g_maclient_info[MAX_MACLIENT_INFO_NUM] = { - {EINA_TRUE, {"hi bixby"}, {"com.samsung.bixby-voice"}}, - {EINA_TRUE, {"alexa"}, {"com.samsung.alexa-voice"}}, - {EINA_TRUE, {"hi google"}, {"com.samsung.google-voice"}}, -}; +static ma_client_info g_maclient_info[MAX_MACLIENT_INFO_NUM]; typedef struct { int pid; @@ -363,7 +361,7 @@ int mas_ui_client_change_assistant(const char* appid) for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { if (g_maclient_info[loop].used && strlen(g_maclient_info[loop].appid) > 0 && - strlen(g_maclient_info[loop].wakeup_word) > 0) { + strlen(g_maclient_info[loop].wakeup_word[0]) > 0) { if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) { mas_launch_client_by_appid(g_maclient_info[loop].appid); } @@ -407,6 +405,49 @@ static void deinit_message_port(void) message_port_unregister_local_port(g_local_port_id); } +int __mas_assistant_info_cb(const char* appid, const char* name, + const char* icon_path, const char* wakeup_list[], int cnt_wakeup, + const char* supported_lang[], int cnt_lang, void* user_data) { + MAS_LOGD("__mas_assistant_info_cb called"); + + if (NULL == appid) { + MAS_LOGD("app_id NULL, returning"); + return -1; + } + + int index = -1; + int loop = 0; + while(-1 == index && loop < MAX_MACLIENT_INFO_NUM) { + if (EINA_FALSE == g_maclient_info[loop].used) { + index = loop; + } + loop++; + } + if (-1 != index) { + g_maclient_info[index].used = EINA_TRUE; + MAS_LOGD("app_id(%s)", appid); + strncpy(g_maclient_info[index].appid, appid, MAX_APPID_LEN); + g_maclient_info[index].appid[MAX_APPID_LEN - 1] = '\0'; + + for (loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) { + if (loop < cnt_wakeup && wakeup_list[loop]) { + MAS_LOGD("wakeup_list(%d)(%s)", loop, wakeup_list[loop]); + strncpy(g_maclient_info[index].wakeup_word[loop], wakeup_list[loop], MAX_WAKEUP_WORD_LEN); + g_maclient_info[index].wakeup_word[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0'; + } else { + strncpy(g_maclient_info[index].wakeup_word[loop], "", MAX_WAKEUP_WORD_LEN); + } + } + } else { + MAS_LOGD("Couldn't find an empty slot for storing assistant info"); + } + + MAS_LOGD("__mas_assistant_info_cb end"); + + return 0; +} + + static int init_wakeup(void) { MAS_LOGD("[Enter] init_wakeup "); @@ -426,17 +467,24 @@ static int init_wakeup(void) return -1; } - for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { - if (g_maclient_info[loop].used && - strlen(g_maclient_info[loop].appid) > 0 && - strlen(g_maclient_info[loop].wakeup_word) > 0) { - MAS_LOGD("Registering wakeup word %s for app %s", - g_maclient_info[loop].wakeup_word, g_maclient_info[loop].appid); - if (0 != multi_assistant_service_plugin_set_wakeup_word("en_US", g_maclient_info[loop].wakeup_word)) { - MAS_LOGE("Fail to stt wakeup word"); - return -1; + if (0 == mas_config_get_assistant_info(__mas_assistant_info_cb, NULL)) { + for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { + if (g_maclient_info[loop].used && + strlen(g_maclient_info[loop].appid) > 0) { + for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (strlen(g_maclient_info[loop].wakeup_word[inner_loop]) > 0) { + MAS_LOGD("Registering wakeup word %s for app %s", + g_maclient_info[loop].wakeup_word[inner_loop], g_maclient_info[loop].appid); + if (0 != multi_assistant_service_plugin_set_wakeup_word( + "en_US", g_maclient_info[loop].wakeup_word[inner_loop])) { + MAS_LOGE("Fail to stt wakeup word"); + } + } + } } } + } else { + MAS_LOGE("Fail to load assistant info"); } if (0 != multi_assistant_service_plugin_set_callbacks()) { @@ -484,10 +532,13 @@ static const char* __get_client_appid_by_wakeup_word(const char *wakeup_word) for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && appid == NULL; loop++) { if (g_maclient_info[loop].used && - strlen(g_maclient_info[loop].appid) > 0 && - strlen(g_maclient_info[loop].wakeup_word) > 0) { - if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word, MAX_WAKEUP_WORD_LEN)) { - appid = g_maclient_info[loop].appid; + strlen(g_maclient_info[loop].appid) > 0) { + for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (strlen(g_maclient_info[loop].wakeup_word[inner_loop]) > 0) { + if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) { + appid = g_maclient_info[loop].appid; + } + } } } } @@ -496,18 +547,21 @@ static const char* __get_client_appid_by_wakeup_word(const char *wakeup_word) if (NULL == appid) { for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && appid == NULL; loop++) { if (g_maclient_info[loop].used && - strlen(g_maclient_info[loop].appid) > 0 && - strlen(g_maclient_info[loop].wakeup_word) > 0) { - char comparand[MAX_WAKEUP_WORD_LEN]; - int comparand_index = 0; - for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) { - if (' ' != g_maclient_info[loop].wakeup_word[index]) { - comparand[comparand_index++] = g_maclient_info[loop].wakeup_word[index]; + strlen(g_maclient_info[loop].appid) > 0) { + for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (strlen(g_maclient_info[loop].wakeup_word[inner_loop]) > 0) { + char comparand[MAX_WAKEUP_WORD_LEN]; + int comparand_index = 0; + for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) { + if (' ' != g_maclient_info[loop].wakeup_word[inner_loop][index]) { + comparand[comparand_index++] = g_maclient_info[loop].wakeup_word[inner_loop][index]; + } + } + if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) { + appid = g_maclient_info[loop].appid; + } } } - if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) { - appid = g_maclient_info[loop].appid; - } } } } @@ -555,10 +609,13 @@ int mas_set_current_client_by_wakeup_word(const char *wakeup_word) for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { if (g_maclient_info[loop].used && - strlen(g_maclient_info[loop].appid) > 0 && - strlen(g_maclient_info[loop].wakeup_word) > 0) { - if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word, MAX_WAKEUP_WORD_LEN)) { - g_current_maclient_info = loop; + strlen(g_maclient_info[loop].appid) > 0) { + for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) { + if (strlen(g_maclient_info[loop].wakeup_word[inner_loop]) > 0) { + if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) { + g_current_maclient_info = loop; + } + } } } } @@ -572,7 +629,7 @@ int mas_set_current_client_by_appid(const char *appid) for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) { if (g_maclient_info[loop].used && strlen(g_maclient_info[loop].appid) > 0 && - strlen(g_maclient_info[loop].wakeup_word) > 0) { + strlen(g_maclient_info[loop].wakeup_word[0]) > 0) { if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) { g_current_maclient_info = loop; }