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);
169 } else if (cur->name && 0 == xmlStrcmp(cur->name, (const xmlChar*)MA_TAG_ASSISTANT_AUDIO_DATA_PROCESSOR)) {
170 key = xmlNodeGetContent(cur);
172 temp.audio_data_processing_appid = std::string{reinterpret_cast<char*>(key)};
181 callback(&temp, user_data);
185 free((void*)temp.app_id);
188 free((void*)temp.name);
190 if (temp.icon_path) {
191 free((void*)temp.icon_path);
193 for (loop = 0; loop < temp.cnt_wakeup; loop++) {
194 if (temp.wakeup_list[loop]) {
195 free((void*)(temp.wakeup_list[loop]));
198 for (loop = 0; loop < temp.cnt_lang; loop++) {
199 if (temp.supported_lang[loop]) {
200 free((void*)(temp.supported_lang[loop]));
203 if (temp.wakeup_engine) {
204 free((void*)temp.wakeup_engine);
212 int CServiceConfig::get_assistant_info(service_config_assistant_info_cb callback, void* user_data)
214 const char *suffix = ".xml";
218 d = opendir(MA_ASSISTANT_INFO);
221 while (NULL != (dir = readdir(d))) {
222 if (suffix && strlen(suffix) <= strlen(dir->d_name)) {
223 if (0 == strcmp(dir->d_name + strlen(dir->d_name) - strlen(suffix), suffix)) {
224 char fullpath[_POSIX_PATH_MAX];
225 snprintf(fullpath, _POSIX_PATH_MAX - 1, "%s/%s", MA_ASSISTANT_INFO, dir->d_name);
226 MAS_LOGD("Parsing file : %s\n", fullpath);
227 parse_assistant_info(callback, fullpath, user_data);
237 int CServiceConfig::add_custom_wake_word(const char* wake_word, const char* language,
238 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
239 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
241 if (nullptr == wake_word || nullptr == language) return -1;
244 for (int loop = 0;false == found && loop < MAX_WAKEUP_WORDS_NUM;loop++) {
245 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
246 0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {
247 LOGE("The wakeup word already exists!");
248 return -1; /* Already exists */
250 if (0 == strlen(wakeup_word_storage[loop])) {
251 strncpy(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN);
252 wakeup_word_storage[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0';
253 strncpy(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN);
254 wakeup_language_storage[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
259 LOGE("No empty slot found while trying to add new wake word!");
265 int CServiceConfig::remove_custom_wake_word(const char* wake_word, const char* language,
266 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
267 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
269 if (nullptr == wake_word || nullptr == language) return -1;
272 for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
273 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
274 0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {
275 for (int shift = loop;shift < MAX_WAKEUP_WORDS_NUM - 1;shift++) {
276 strncpy(wakeup_word_storage[shift],
277 wakeup_word_storage[shift + 1], MAX_WAKEUP_WORD_LEN);
278 wakeup_word_storage[shift][MAX_WAKEUP_WORD_LEN - 1] = '\0';
279 strncpy(wakeup_language_storage[shift],
280 wakeup_language_storage[shift + 1], MAX_SUPPORTED_LANGUAGE_LEN);
281 wakeup_language_storage[shift][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
283 memset(wakeup_word_storage[MAX_WAKEUP_WORDS_NUM - 1],
284 0x00, sizeof(char) * MAX_WAKEUP_WORD_LEN);
285 memset(wakeup_language_storage[MAX_WAKEUP_WORDS_NUM - 1],
286 0x00, sizeof(char) * MAX_SUPPORTED_LANGUAGE_LEN);
288 loop--; /* Just in case there are duplicated items */
292 if (!found) return -1;
296 int CServiceConfig::load_custom_wake_words(const char* app_id,
297 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
298 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
300 const char delimeter = '|';
302 /* Add 1 for additional pipe character */
303 char wakeup_words[MAX_WAKEUP_WORDS_NUM * (MAX_WAKEUP_WORD_LEN + 1)];
304 char wakeup_languages[MAX_WAKEUP_WORDS_NUM * (MAX_SUPPORTED_LANGUAGE_LEN + 1)];
305 memset(wakeup_words, 0x00, sizeof(wakeup_words));
306 memset(wakeup_languages, 0x00, sizeof(wakeup_languages));
308 bool existing = false;
309 preference_is_existing("custom_wakeup_words", &existing);
310 if (!existing) return -1;
311 preference_is_existing("custom_wakeup_languages", &existing);
312 if (!existing) return -1;
314 char* custom_wakeup_words = NULL;
315 preference_get_string("custom_wakeup_words", &custom_wakeup_words);
316 if (NULL == custom_wakeup_words) return -1;
317 strncpy(wakeup_words, custom_wakeup_words, sizeof(wakeup_words) - 1);
318 wakeup_words[sizeof(wakeup_words) - 1] = '\0';
319 LOGD("Custom wakeup words loaded : %s", wakeup_words);
320 free(custom_wakeup_words);
321 custom_wakeup_words = NULL;
323 char* custom_wakeup_languages = NULL;
324 preference_get_string("custom_wakeup_languages", &custom_wakeup_languages);
325 if (NULL == custom_wakeup_languages) return -1;
326 strncpy(wakeup_languages, custom_wakeup_languages, sizeof(wakeup_languages) - 1);
327 wakeup_languages[sizeof(wakeup_languages) - 1] = '\0';
328 LOGD("Custom wakeup languages loaded : %s", wakeup_languages);
329 free(custom_wakeup_languages);
330 custom_wakeup_languages = NULL;
332 char *word_start = wakeup_words;
333 char *language_start = wakeup_languages;
334 char *word_end = NULL;
335 char *language_end = NULL;
337 while (index < MAX_WAKEUP_WORDS_NUM) {
338 word_end = strchrnul(word_start, delimeter);
339 language_end = strchrnul(language_start, delimeter);
340 if ('\0' == *word_end || '\0' == *language_end) break;
342 *language_end = '\0';
343 if (0 == strlen(word_start)) break;
344 strncpy(wakeup_word_storage[index], word_start, MAX_WAKEUP_WORD_LEN - 1);
345 strncpy(wakeup_language_storage[index], language_start, MAX_SUPPORTED_LANGUAGE_LEN - 1);
346 word_start = word_end + 1;
347 language_start = language_end + 1;
348 LOGD("Added custom wakeup word : (%s) (%s)",
349 wakeup_word_storage[index], wakeup_language_storage[index]);
356 int CServiceConfig::save_custom_wake_words(const char* app_id,
357 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
358 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
360 const char* delimeter = "|";
361 /* Add 1 for additional pipe character */
362 char wakeup_words[MAX_WAKEUP_WORDS_NUM * (MAX_WAKEUP_WORD_LEN + 1)];
363 char wakeup_languages[MAX_WAKEUP_WORDS_NUM * (MAX_SUPPORTED_LANGUAGE_LEN + 1)];
364 memset(wakeup_words, 0x00, sizeof(wakeup_words));
365 memset(wakeup_languages, 0x00, sizeof(wakeup_languages));
366 for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
367 if (strlen(wakeup_word_storage[loop]) > 0) {
368 int wakeup_words_len = strlen(wakeup_words);
369 strncat(wakeup_words, wakeup_word_storage[loop],
370 sizeof(wakeup_words) - wakeup_words_len - 1);
371 strncat(wakeup_words, delimeter, strlen(delimeter));
372 int wakeup_languages_len = strlen(wakeup_languages);
373 strncat(wakeup_languages, wakeup_language_storage[loop],
374 sizeof(wakeup_languages) - wakeup_languages_len - 1);
375 strncat(wakeup_languages, delimeter, strlen(delimeter));
378 wakeup_words[sizeof(wakeup_words) - 1] = '\0';
379 wakeup_languages[sizeof(wakeup_languages) - 1] = '\0';
380 preference_set_string("custom_wakeup_words", wakeup_words);
381 preference_set_string("custom_wakeup_languages", wakeup_languages);
385 int CServiceConfig::get_custom_wake_word_num(
386 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
387 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
390 for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
391 if (0 < strlen(wakeup_word_storage[loop])) {
398 bool CServiceConfig::has_custom_wake_word(const char* wake_word, const char* language,
399 char wakeup_word_storage[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN],
400 char wakeup_language_storage[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN])
402 if (nullptr == wake_word || nullptr == language) return false;
404 for (int loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
405 if (0 == strncmp(wakeup_word_storage[loop], wake_word, MAX_WAKEUP_WORD_LEN) &&
406 0 == strncmp(wakeup_language_storage[loop], language, MAX_SUPPORTED_LANGUAGE_LEN)) {