2 * Copyright 2020 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.1 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <libxml/parser.h>
18 #include <sys/types.h>
22 #include <app_preference.h>
24 #include "service_config.h"
25 #include "service_common.h"
27 int CServiceConfig::parse_assistant_info(service_config_assistant_info_cb callback,
28 const char *path, void* user_data)
31 xmlNodePtr cur = NULL;
38 doc = xmlParseFile(path);
43 if (MA_RETRY_COUNT == retry_count++) {
44 MAS_LOGE("[ERROR] Fail to parse file error : %s", path);
51 cur = xmlDocGetRootElement(doc);
53 MAS_LOGE("[ERROR] Empty document");
58 if (xmlStrcmp(cur->name, (const xmlChar *) MA_TAG_ASSISTANT_BASE)) {
59 MAS_LOGE("[ERROR] The wrong type, root node is NOT %s", MA_TAG_ASSISTANT_BASE);
64 cur = cur->xmlChildrenNode;
66 MAS_LOGE("[ERROR] Empty document");
71 /* alloc assistant info */
72 ma_assistant_info_s temp;
75 if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar *)MA_TAG_ASSISTANT_LANGUAGE_SET)) {
76 xmlNodePtr child_node = cur->xmlChildrenNode;
77 while (child_node != NULL) {
78 if (child_node->name && 0 == xmlStrcmp(child_node->name, (const xmlChar*)MA_TAG_ASSISTANT_LANGUAGE)) {
79 key = xmlNodeGetContent(child_node);
81 temp.supported_lang[temp.cnt_lang++] = strdup((const char*)key);
82 MAS_LOGD("Language : %s", key);
87 child_node = child_node->next;
89 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar *)MA_TAG_ASSISTANT_WAKEUP_WORD_SET)) {
90 xmlNodePtr child_node = cur->xmlChildrenNode;
91 while (child_node != NULL) {
92 if (child_node->name && 0 == xmlStrcmp(child_node->name, (const xmlChar*)MA_TAG_ASSISTANT_WAKEUP_WORD)) {
93 key = xmlNodeGetContent(child_node);
95 temp.wakeup_list[temp.cnt_wakeup] = strdup((const char*)key);
96 MAS_LOGD("Wakeup Word : %s", key);
99 xmlChar* prop = xmlNodeGetLang(child_node);
101 temp.wakeup_language[temp.cnt_wakeup] = strdup((const char*)prop);
102 MAS_LOGD("Wakeup Language for %s : %s", temp.wakeup_list[temp.cnt_wakeup], prop);
108 child_node = child_node->next;
110 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_NAME)) {
111 key = xmlNodeGetContent(cur);
113 temp.name = strdup((const char*)key);
114 MAS_LOGD("Name : %s", key);
117 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_APPID)) {
118 key = xmlNodeGetContent(cur);
120 temp.app_id = strdup((const char*)key);
121 MAS_LOGD("ID : %s", key);
124 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_ICON_PATH)) {
125 key = xmlNodeGetContent(cur);
127 temp.icon_path = strdup((const char*)key);
128 MAS_LOGD("Icon Path : %s", key);
131 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_WAKEUP_ENGINE_APPID)) {
132 key = xmlNodeGetContent(cur);
134 temp.wakeup_engine = strdup((const char*)key);
135 MAS_LOGD("Wakeup Engine : %s", key);
138 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_CUSTOM_UI)) {
139 key = xmlNodeGetContent(cur);
141 if (0 == xmlStrcasecmp(key, reinterpret_cast<const xmlChar*>("true"))) {
142 temp.custom_ui_option = true;
144 MAS_LOGD("Use custom UI : %d", temp.custom_ui_option);
147 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_VOICE_KEY_SUPPORT_MODE)) {
148 key = xmlNodeGetContent(cur);
150 if (xmlStrcmp(cur->name, (const xmlChar*)VOICE_KEY_SUPPORT_MODE_STRING_ALL)) {
151 temp.voice_key_support_mode = VOICE_KEY_SUPPORT_MODE_ALL;
152 } else if (xmlStrcmp(cur->name, (const xmlChar*)VOICE_KEY_SUPPORT_MODE_STRING_TAP_TO_TALK)) {
153 temp.voice_key_support_mode = VOICE_KEY_SUPPORT_MODE_TAP_TO_TALK;
154 } else if (xmlStrcmp(cur->name, (const xmlChar*)VOICE_KEY_SUPPORT_MODE_STRING_PUSH_TO_TALK)) {
155 temp.voice_key_support_mode = VOICE_KEY_SUPPORT_MODE_PUSH_TO_TALK;
157 temp.voice_key_support_mode = VOICE_KEY_SUPPORT_MODE_NONE;
159 MAS_LOGD("Voice key support mode : %s", cur->name);
162 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_VOICE_KEY_TAP_DURATION)) {
163 key = xmlNodeGetContent(cur);
165 temp.voice_key_tap_duration = atof((const char*)key);
166 MAS_LOGD("Voice key tap duration : %s", key);
175 callback(&temp, user_data);
179 free((void*)temp.app_id);
182 free((void*)temp.name);
184 if (temp.icon_path) {
185 free((void*)temp.icon_path);
187 for (loop = 0; loop < temp.cnt_wakeup; loop++) {
188 if (temp.wakeup_list[loop]) {
189 free((void*)(temp.wakeup_list[loop]));
192 for (loop = 0; loop < temp.cnt_lang; loop++) {
193 if (temp.supported_lang[loop]) {
194 free((void*)(temp.supported_lang[loop]));
197 if (temp.wakeup_engine) {
198 free((void*)temp.wakeup_engine);
206 int CServiceConfig::get_assistant_info(service_config_assistant_info_cb callback, void* user_data)
208 const char *suffix = ".xml";
212 d = opendir(MA_ASSISTANT_INFO);
215 while (NULL != (dir = readdir(d))) {
216 if (suffix && strlen(suffix) <= strlen(dir->d_name)) {
217 if (0 == strcmp(dir->d_name + strlen(dir->d_name) - strlen(suffix), suffix)) {
218 char fullpath[_POSIX_PATH_MAX];
219 snprintf(fullpath, _POSIX_PATH_MAX - 1, "%s/%s", MA_ASSISTANT_INFO, dir->d_name);
220 MAS_LOGD("Parsing file : %s\n", fullpath);
221 parse_assistant_info(callback, fullpath, user_data);
231 int CServiceConfig::add_custom_wake_word(const char* wake_word, const char* language,
232 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
233 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
235 if (nullptr == wake_word || nullptr == language) return -1;
238 for (int loop = 0;false == found && loop < MAX_WAKEUP_WORDS_NUM;loop++) {
239 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
240 0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {
241 LOGE("The wakeup word already exists!");
242 return -1; /* Already exists */
244 if (0 == strlen(wakeup_word_storage[loop])) {
245 strncpy(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN);
246 wakeup_word_storage[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0';
247 strncpy(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN);
248 wakeup_language_storage[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
253 LOGE("No empty slot found while trying to add new wake word!");
259 int CServiceConfig::remove_custom_wake_word(const char* wake_word, const char* language,
260 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
261 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
263 if (nullptr == wake_word || nullptr == language) return -1;
266 for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
267 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
268 0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {
269 for (int shift = loop;shift < MAX_WAKEUP_WORDS_NUM - 1;shift++) {
270 strncpy(wakeup_word_storage[shift],
271 wakeup_word_storage[shift + 1], MAX_WAKEUP_WORD_LEN);
272 wakeup_word_storage[shift][MAX_WAKEUP_WORD_LEN - 1] = '\0';
273 strncpy(wakeup_language_storage[shift],
274 wakeup_language_storage[shift + 1], MAX_SUPPORTED_LANGUAGE_LEN);
275 wakeup_language_storage[shift][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
277 memset(wakeup_word_storage[MAX_WAKEUP_WORDS_NUM - 1],
278 0x00, sizeof(char) * MAX_WAKEUP_WORD_LEN);
279 memset(wakeup_language_storage[MAX_WAKEUP_WORDS_NUM - 1],
280 0x00, sizeof(char) * MAX_SUPPORTED_LANGUAGE_LEN);
282 loop--; /* Just in case there are duplicated items */
286 if (!found) return -1;
290 int CServiceConfig::load_custom_wake_words(const char* app_id,
291 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
292 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
294 const char delimeter = '|';
296 /* Add 1 for additional pipe character */
297 char wakeup_words[MAX_WAKEUP_WORDS_NUM * (MAX_WAKEUP_WORD_LEN + 1)];
298 char wakeup_languages[MAX_WAKEUP_WORDS_NUM * (MAX_SUPPORTED_LANGUAGE_LEN + 1)];
299 memset(wakeup_words, 0x00, sizeof(wakeup_words));
300 memset(wakeup_languages, 0x00, sizeof(wakeup_languages));
302 bool existing = false;
303 preference_is_existing("custom_wakeup_words", &existing);
304 if (!existing) return -1;
305 preference_is_existing("custom_wakeup_languages", &existing);
306 if (!existing) return -1;
309 preference_get_string("custom_wakeup_words", &value);
310 if (NULL == value) return -1;
311 strncpy(wakeup_words, value, sizeof(wakeup_words) - 1);
312 wakeup_words[sizeof(wakeup_words) - 1] = '\0';
313 LOGD("Custom wakeup words loaded : %s", wakeup_words);
316 preference_get_string("custom_wakeup_languages", &value);
317 if (NULL == value) return -1;
318 strncpy(wakeup_languages, value, sizeof(wakeup_languages) - 1);
319 wakeup_languages[sizeof(wakeup_languages) - 1] = '\0';
320 LOGD("Custom wakeup languages loaded : %s", wakeup_languages);
323 char *word_start = wakeup_words;
324 char *language_start = wakeup_languages;
325 char *word_end = NULL;
326 char *language_end = NULL;
328 while (index < MAX_WAKEUP_WORDS_NUM) {
329 word_end = strchrnul(word_start, delimeter);
330 language_end = strchrnul(language_start, delimeter);
331 if ('\0' == *word_end || '\0' == *language_end) break;
333 *language_end = '\0';
334 if (0 == strlen(word_start)) break;
335 strncpy(wakeup_word_storage[index], word_start, MAX_WAKEUP_WORD_LEN - 1);
336 strncpy(wakeup_language_storage[index], language_start, MAX_SUPPORTED_LANGUAGE_LEN - 1);
337 word_start = word_end + 1;
338 language_start = language_end + 1;
339 LOGD("Added custom wakeup word : (%s) (%s)",
340 wakeup_word_storage[index], wakeup_language_storage[index]);
347 int CServiceConfig::save_custom_wake_words(const char* app_id,
348 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
349 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
351 const char* delimeter = "|";
352 /* Add 1 for additional pipe character */
353 char wakeup_words[MAX_WAKEUP_WORDS_NUM * (MAX_WAKEUP_WORD_LEN + 1)];
354 char wakeup_languages[MAX_WAKEUP_WORDS_NUM * (MAX_SUPPORTED_LANGUAGE_LEN + 1)];
355 memset(wakeup_words, 0x00, sizeof(wakeup_words));
356 memset(wakeup_languages, 0x00, sizeof(wakeup_languages));
357 for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
358 if (strlen(wakeup_word_storage[loop]) > 0) {
359 int wakeup_words_len = strlen(wakeup_words);
360 strncat(wakeup_words, wakeup_word_storage[loop],
361 sizeof(wakeup_words) - wakeup_words_len - 1);
362 strncat(wakeup_words, delimeter, strlen(delimeter));
363 int wakeup_languages_len = strlen(wakeup_languages);
364 strncat(wakeup_languages, wakeup_language_storage[loop],
365 sizeof(wakeup_languages) - wakeup_languages_len - 1);
366 strncat(wakeup_languages, delimeter, strlen(delimeter));
369 wakeup_words[sizeof(wakeup_words) - 1] = '\0';
370 wakeup_languages[sizeof(wakeup_languages) - 1] = '\0';
371 preference_set_string("custom_wakeup_words", wakeup_words);
372 preference_set_string("custom_wakeup_languages", wakeup_languages);
376 int CServiceConfig::get_custom_wake_word_num(
377 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
378 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
381 for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
382 if (0 < strlen(wakeup_word_storage[loop])) {
389 bool CServiceConfig::has_custom_wake_word(const char* wake_word, const char* language,
390 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
391 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
393 if (nullptr == wake_word || nullptr == language) return false;
395 for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
396 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
397 0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {