2 * Copyright 2018 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.
18 #include <service_app.h>
19 #include <app_manager.h>
31 #include "multi_assistant_main.h"
32 #include "multi_assistant_service.h"
33 #include "multi_assistant_service_plugin.h"
34 #include "multi_assistant_dbus.h"
35 #include "multi_assistant_config.h"
36 #include "multi_assistant_common.h"
38 static const char *g_current_lang = "en_US";
40 #define MULTI_ASSISTANT_SETTINGS_ACTIVATED "db/multi-assistant/activated"
41 #define WAKEUP_SETTINGS_KEY_DEFAULT_ASSISTANT_APPID "db/multi-assistant/default_assistant_appid"
42 #define WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID "db/multi-assistant/preprocessing_assistant_appid"
43 #define WAKEUP_SETTINGS_KEY_PRELAUNCH_MODE "db/multi-assistant/prelaunch_mode"
45 #define MAX_MACLIENT_INFO_NUM 16
46 #define MAX_WAKEUP_WORDS_NUM 255
47 #define MAX_WAKEUP_WORD_LEN 32
48 #define MAX_SUPPORTED_LANGUAGES_NUM 255
49 #define MAX_SUPPORTED_LANGUAGE_LEN 16
52 char appid[MAX_APPID_LEN];
53 char wakeup_word[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN];
54 char wakeup_language[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN];
55 char wakeup_engine[MAX_APPID_LEN];
56 char supported_language[MAX_SUPPORTED_LANGUAGES_NUM][MAX_SUPPORTED_LANGUAGE_LEN];
57 bool custom_ui_option;
59 ma_preprocessing_allow_mode_e preprocessing_allow_mode;
60 char preprocessing_allow_appid[MAX_APPID_LEN];
63 static ma_client_info g_maclient_info[MAX_MACLIENT_INFO_NUM];
67 char appid[MAX_APPID_LEN];
70 static int g_current_maclient_info = 0;
71 static int g_current_preprocessing_maclient_info = -1;
72 static const char *g_wakeup_maclient_appid = NULL;
74 static PREPROCESSING_STATE g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
77 static GSList* g_client_list = NULL;
79 int ma_client_create(ma_client_s *info)
82 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
86 ma_client_s* data = NULL;
88 data = (ma_client_s*)calloc(1, sizeof(ma_client_s));
90 MAS_LOGE("[ERROR] Fail to allocate memory"); //LCOV_EXCL_LINE
91 return -1;// MA_ERROR_OUT_OF_MEMORY;
96 g_client_list = g_slist_append(g_client_list, data);
101 int ma_client_destroy(ma_client_s *client)
103 if (NULL == client) {
104 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
105 return -1;// MA_ERROR_OPERATION_FAILED;
108 g_client_list = g_slist_remove(g_client_list, client);
116 ma_client_s* ma_client_find_by_appid(const char *appid)
119 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
123 ma_client_s *data = NULL;
125 int count = g_slist_length(g_client_list);
128 for (i = 0; i < count; i++) {
129 data = g_slist_nth_data(g_client_list, i);
132 if (0 == strncmp(data->appid, appid, MAX_APPID_LEN)) {
138 MAS_LOGE("[ERROR] client Not found");
143 ma_client_s* ma_client_find_by_pid(int pid)
145 ma_client_s *data = NULL;
147 int count = g_slist_length(g_client_list);
150 for (i = 0; i < count; i++) {
151 data = g_slist_nth_data(g_client_list, i);
154 if (data->pid == pid) {
160 MAS_LOGE("[ERROR] client Not found");
165 bool check_preprocessing_assistant_exists()
169 char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
171 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
172 if (g_maclient_info[loop].used) {
173 if (strncmp(vconf_str, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
174 ma_client_s* client = ma_client_find_by_appid(vconf_str);
175 if (client && client->pid > 0) {
185 MAS_LOGD("result : %d", ret);
190 bool is_current_preprocessing_assistant(const char* appid)
192 if (NULL == appid) return false;
196 char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
198 if (strncmp(vconf_str, appid, MAX_APPID_LEN) == 0) {
208 int mas_client_initialize(int pid)
210 MAS_LOGD("[Enter] pid(%d)", pid);
212 char appid[MAX_APPID_LEN] = {'\0',};
213 if (AUL_R_OK == aul_app_get_appid_bypid(pid, appid, sizeof(appid))) {
214 appid[MAX_APPID_LEN - 1] = '\0';
216 MAS_LOGD("appid for pid %d is : %s", pid, (appid ? appid : "Unknown"));
218 /* Remove existing client that has same appid, if there's any */
219 ma_client_s *old_client = NULL;
220 old_client = ma_client_find_by_appid(appid);
222 ma_client_destroy(old_client);
226 /* And remove a client that has same pid also */
227 old_client = ma_client_find_by_pid(pid);
229 ma_client_destroy(old_client);
233 ma_client_s new_client;
234 new_client.pid = pid;
235 strncpy(new_client.appid, appid, MAX_APPID_LEN);
236 new_client.appid[MAX_APPID_LEN - 1] = '\0';
237 ma_client_create(&new_client);
239 const char *current_maclient_appid = NULL;
240 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
241 current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
244 mas_client_send_preprocessing_information(pid);
245 if (current_maclient_appid && 0 == strncmp(current_maclient_appid, appid, MAX_APPID_LEN)) {
246 MAS_LOGD("MA client with current maclient appid connected!");
248 if (g_wakeup_maclient_appid && strncmp(g_wakeup_maclient_appid, appid, MAX_APPID_LEN) == 0) {
249 g_wakeup_maclient_appid = NULL;
250 mas_client_activate(pid);
251 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_ACTIVE_ASSISTANT_LAUNCHED);
253 MAS_LOGE("[ERROR] g_wakeup_maclient_appid and appid differ : %s %s",
254 (g_wakeup_maclient_appid ? g_wakeup_maclient_appid : "NULL"), appid);
257 MAS_LOGD("MA client connected, but its appid does not match with current maclient");
260 MAS_LOGE("[ERROR] Fail to retrieve appid");
266 int mas_client_deinitialize(int pid)
268 MAS_LOGD("[Enter] pid(%d)", pid);
269 ma_client_s *client = ma_client_find_by_pid(pid);
271 ma_client_destroy(client);
277 int mas_client_get_audio_format(int pid, int* rate, int* channel, int* audio_type)
279 MAS_LOGD("[Enter] pid(%d)", pid);
281 int ret = multi_assistant_service_plugin_get_recording_audio_format(rate, channel, audio_type);
283 MAS_LOGE("[ERROR] Fail to get recording audio format, ret(%d)", ret);
289 int mas_client_get_audio_source_type(int pid, char** type)
291 MAS_LOGD("[Enter] pid(%d)", pid);
293 int ret = multi_assistant_service_plugin_get_recording_audio_source_type(type);
295 MAS_LOGE("[ERROR] Fail to get recording audio source type, ret(%d)", ret);
301 int mas_client_send_preprocessing_information(int pid)
304 MAS_LOGD("[Enter] pid(%d)", pid);
306 char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
307 MAS_LOGD("preprocessing_assistant_appid : %s", vconf_str);
308 ret = masc_dbus_send_preprocessing_information(pid, vconf_str);
315 int mas_client_activate(int pid)
318 MAS_LOGD("[Enter] pid(%d)", pid);
320 ret = masc_dbus_active_state_change(pid, MA_ACTIVE_STATE_ACTIVE);
325 int mas_client_deactivate(int pid)
328 MAS_LOGD("[Enter] pid(%d)", pid);
330 ret = masc_dbus_active_state_change(pid, MA_ACTIVE_STATE_INACTIVE);
335 int mas_client_send_asr_result(int pid, int event, char* asr_result)
337 MAS_LOGD("[Enter] pid(%d), event(%d), asr_result(%s)", pid, event, asr_result);
338 int ret = masc_ui_dbus_send_asr_result(pid, event, asr_result);
340 MAS_LOGE("[ERROR] Fail to send asr result, ret(%d)", ret);
343 // if final event is , launch assistant app which is invoked with wakeup word.
348 int mas_client_send_result(int pid, char* display_text, char* utterance_text, char* result_json)
350 MAS_LOGD("[Enter] pid(%d), display_text(%s), utterance_text(%s), result_json(%s)", pid, display_text, utterance_text, result_json);
351 int ret = masc_ui_dbus_send_result(pid, display_text, utterance_text, result_json);
353 MAS_LOGE("[ERROR] Fail to send result, ret(%d)", ret);
356 const char* pid_appid = NULL;
357 char buf[MAX_APPID_LEN] = {'\0',};
358 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
359 buf[MAX_APPID_LEN - 1] = '\0';
362 multi_assistant_service_plugin_update_recognition_result(pid_appid, MA_RECOGNITION_RESULT_EVENT_SUCCESS);
367 int mas_client_send_recognition_result(int pid, int result)
369 MAS_LOGD("[Enter] pid(%d), result(%d)", pid, result);
370 int ret = masc_ui_dbus_send_recognition_result(pid, result);
372 MAS_LOGE("[ERROR] Fail to send recognition result, ret(%d)", ret);
375 const char* pid_appid = NULL;
376 char buf[MAX_APPID_LEN] = {'\0',};
377 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
378 buf[MAX_APPID_LEN - 1] = '\0';
381 multi_assistant_service_plugin_update_recognition_result(pid_appid, result);
386 int mas_client_start_streaming_audio_data(int pid, int type)
390 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
391 ret = multi_assistant_service_plugin_start_streaming_utterance_data();
392 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED);
394 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
395 ret = multi_assistant_service_plugin_start_streaming_previous_utterance_data();
396 /* Preprocessing is not required for previous utterance streaming */
398 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
399 ret = multi_assistant_service_plugin_start_streaming_follow_up_data();
400 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED);
406 int mas_client_stop_streaming_audio_data(int pid, int type)
410 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
411 ret = multi_assistant_service_plugin_stop_streaming_utterance_data();
413 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
414 ret = multi_assistant_service_plugin_stop_streaming_previous_utterance_data();
416 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
417 ret = multi_assistant_service_plugin_stop_streaming_follow_up_data();
423 int mas_client_update_voice_feedback_state(int pid, int state)
425 const char* pid_appid = NULL;
426 char buf[MAX_APPID_LEN] = {'\0',};
427 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
428 buf[MAX_APPID_LEN - 1] = '\0';
431 multi_assistant_service_plugin_update_voice_feedback_state(pid_appid, state);
435 int mas_client_send_assistant_specific_command(int pid, const char *command)
437 const char* pid_appid = NULL;
438 char buf[MAX_APPID_LEN] = {'\0',};
439 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
440 buf[MAX_APPID_LEN - 1] = '\0';
443 multi_assistant_service_plugin_send_assistant_specific_command(pid_appid, command);
447 int mas_client_set_background_volume(int pid, double ratio)
449 const char* pid_appid = NULL;
450 char buf[MAX_APPID_LEN] = {'\0',};
451 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
452 buf[MAX_APPID_LEN - 1] = '\0';
455 multi_assistant_service_plugin_set_background_volume(pid_appid, ratio);
459 int mas_client_set_preprocessing_allow_mode(int pid, int mode, const char* appid)
461 const char* pid_appid = NULL;
462 char buf[MAX_APPID_LEN] = {'\0',};
463 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
464 buf[MAX_APPID_LEN - 1] = '\0';
468 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
469 if (g_maclient_info[loop].used) {
470 if (pid_appid && strncmp(pid_appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
471 g_maclient_info[loop].preprocessing_allow_mode = mode;
473 strncpy(g_maclient_info[loop].preprocessing_allow_appid, appid, MAX_APPID_LEN);
474 g_maclient_info[loop].preprocessing_allow_appid[MAX_APPID_LEN - 1] = '\0';
476 g_maclient_info[loop].preprocessing_allow_appid[0] = '\0';
482 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED);
487 int mas_client_send_preprocessing_result(int pid, bool result)
489 const char* pid_appid = NULL;
490 char buf[MAX_APPID_LEN] = {'\0',};
491 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
492 buf[MAX_APPID_LEN - 1] = '\0';
495 if (!is_current_preprocessing_assistant(pid_appid)) return -1;
497 const char *current_maclient_appid = NULL;
498 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
499 current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
503 MAS_LOGD("Preprocessing succeeded, bring (%s) to foreground", pid_appid);
504 mas_bring_client_to_foreground(pid_appid);
505 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED);
507 MAS_LOGD("Preprocessing failed, bring (%s) to foreground", current_maclient_appid);
508 mas_bring_client_to_foreground(current_maclient_appid);
509 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED);
512 ma_client_s* client = ma_client_find_by_appid(current_maclient_appid);
514 masc_dbus_send_preprocessing_result(client->pid, result);
520 int mas_client_set_wake_word_audio_require_flag(int pid, bool require)
522 const char* pid_appid = NULL;
523 char buf[MAX_APPID_LEN] = {'\0',};
524 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
525 buf[MAX_APPID_LEN - 1] = '\0';
529 multi_assistant_service_plugin_set_wake_word_audio_require_flag(pid_appid, require);
533 int mas_ui_client_initialize(int pid)
535 MAS_LOGD("[Enter] pid(%d)", pid);
540 int mas_ui_client_deinitialize(int pid)
542 MAS_LOGD("[Enter] pid(%d)", pid);
547 int mas_ui_client_change_assistant(const char* appid)
552 MAS_LOGE("NULL parameter");
556 bool use_custom_ui = mas_get_client_custom_ui_option_by_appid(appid);
557 masc_ui_dbus_enable_common_ui(!use_custom_ui);
559 mas_set_current_client_by_appid(appid);
560 int pid = mas_get_client_pid_by_appid(appid);
562 mas_bring_client_to_foreground(appid);
563 mas_client_send_preprocessing_information(pid);
564 mas_client_activate(pid);
565 MAS_LOGD("MA Client with appid %s exists, requesting speech data", (appid ? appid : "NULL"));
567 int ret = multi_assistant_service_plugin_start_streaming_utterance_data();
569 MAS_LOGE("[ERROR] Fail to start streaming utterance data(%d)", ret);
573 // Appropriate MA Client not available, trying to launch new one
574 MAS_LOGD("MA Client with appid %s does not exist, launching client", (appid ? appid : "NULL"));
576 /* The appid parameter might not exist after this function call, so we use appid string in our g_maclient_info */
577 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
578 if (g_maclient_info[loop].used &&
579 0 < strlen(g_maclient_info[loop].appid) &&
580 0 < strlen(g_maclient_info[loop].wakeup_word[0])) {
581 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
582 mas_launch_client_by_appid(g_maclient_info[loop].appid, CLIENT_LAUNCH_MODE_ACTIVATION);
591 int __mas_assistant_info_cb(const char* appid, const char* name, const char* icon_path,
592 const char* wakeup_list[], const char* wakeup_language[], int cnt_wakeup,
593 const char* supported_lang[], int cnt_lang, const char* wakeup_engine,
594 bool custom_ui_option, void* user_data) {
595 MAS_LOGD("__mas_assistant_info_cb called");
598 MAS_LOGD("app_id NULL, returning");
604 while(-1 == index && loop < MAX_MACLIENT_INFO_NUM) {
605 if (false == g_maclient_info[loop].used) {
611 g_maclient_info[index].used = true;
612 g_maclient_info[index].preprocessing_allow_mode = MA_PREPROCESSING_ALLOW_NONE;
613 g_maclient_info[index].preprocessing_allow_appid[0] = '\0';
614 MAS_LOGD("app_id(%s)", appid);
615 strncpy(g_maclient_info[index].appid, appid, MAX_APPID_LEN);
616 g_maclient_info[index].appid[MAX_APPID_LEN - 1] = '\0';
618 if (is_current_preprocessing_assistant(g_maclient_info[index].appid)) {
619 g_current_preprocessing_maclient_info = index;
622 for (loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
623 if (loop < cnt_wakeup && wakeup_list[loop]) {
624 MAS_LOGD("wakeup_list(%d)(%s)(%s)", loop, wakeup_list[loop], wakeup_language[loop]);
625 strncpy(g_maclient_info[index].wakeup_word[loop], wakeup_list[loop], MAX_WAKEUP_WORD_LEN);
626 g_maclient_info[index].wakeup_word[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0';
627 if (wakeup_language[loop]) {
628 strncpy(g_maclient_info[index].wakeup_language[loop], wakeup_language[loop], MAX_SUPPORTED_LANGUAGE_LEN);
629 g_maclient_info[index].wakeup_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
631 strncpy(g_maclient_info[index].wakeup_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
634 strncpy(g_maclient_info[index].wakeup_word[loop], "", MAX_WAKEUP_WORD_LEN);
638 for (loop = 0;loop < MAX_SUPPORTED_LANGUAGES_NUM;loop++) {
639 if (loop < cnt_lang && supported_lang[loop]) {
640 MAS_LOGD("supported_lang(%d)(%s)", loop, supported_lang[loop]);
641 strncpy(g_maclient_info[index].supported_language[loop], supported_lang[loop], MAX_SUPPORTED_LANGUAGE_LEN);
642 g_maclient_info[index].supported_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
644 strncpy(g_maclient_info[index].supported_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
648 MAS_LOGD("wakeup_engine(%s)", wakeup_engine);
650 strncpy(g_maclient_info[index].wakeup_engine, wakeup_engine, MAX_APPID_LEN);
651 g_maclient_info[index].wakeup_engine[MAX_APPID_LEN - 1] = '\0';
653 g_maclient_info[index].wakeup_engine[0] = '\0';
654 MAS_LOGW("Wakeup engine information not provided for : %s", appid);
656 g_maclient_info[index].custom_ui_option = custom_ui_option;
658 MAS_LOGD("Couldn't find an empty slot for storing assistant info");
661 MAS_LOGD("__mas_assistant_info_cb end");
666 static void mas_active_state_changed_cb(keynode_t* key, void* data)
669 if (vconf_get_bool(MULTI_ASSISTANT_SETTINGS_ACTIVATED, &vconf_value) == 0) {
670 MAS_LOGD("multi-assistant active state : %d\n", vconf_value);
673 multi_assistant_service_plugin_activate();
675 multi_assistant_service_plugin_deactivate();
680 static int init_wakeup(void)
682 MAS_LOGD("[Enter] init_wakeup");
684 int ret = mas_dbus_open_connection();
686 MAS_LOGE("[ERROR] Fail to open connection");
689 if (0 != multi_assistant_service_plugin_initialize()) {
690 MAS_LOGE("Fail to ws intialize");
694 if (0 != multi_assistant_service_plugin_set_language(g_current_lang)) {
695 MAS_LOGE("Fail to ws set language");
699 if (0 == mas_config_get_assistant_info(__mas_assistant_info_cb, NULL)) {
700 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
702 if (g_maclient_info[loop].used &&
703 0 < strlen(g_maclient_info[loop].appid)) {
704 if (0 < strlen(g_maclient_info[loop].wakeup_engine)) {
705 multi_assistant_service_plugin_set_assistant_wakeup_engine(
706 g_maclient_info[loop].appid,
707 g_maclient_info[loop].wakeup_engine);
709 for (inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
710 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
711 MAS_LOGD("Registering wakeup word %s for app %s",
712 g_maclient_info[loop].wakeup_word[inner_loop], g_maclient_info[loop].appid);
713 if (0 != multi_assistant_service_plugin_add_assistant_wakeup_word(
714 g_maclient_info[loop].appid,
715 g_maclient_info[loop].wakeup_word[inner_loop],
716 g_maclient_info[loop].wakeup_language[inner_loop])) {
717 MAS_LOGE("Fail to add assistant's wakeup word");
721 for (inner_loop = 0; inner_loop < MAX_SUPPORTED_LANGUAGE_NUM; inner_loop++) {
722 if (0 < strlen(g_maclient_info[loop].supported_language[inner_loop])) {
723 MAS_LOGD("Adding language %s for app %s",
724 g_maclient_info[loop].supported_language[inner_loop], g_maclient_info[loop].appid);
725 if (0 != multi_assistant_service_plugin_add_assistant_language(
726 g_maclient_info[loop].appid,
727 g_maclient_info[loop].supported_language[inner_loop])) {
728 MAS_LOGE("Fail to add assistant's language");
735 MAS_LOGE("Fail to load assistant info");
738 if (0 != multi_assistant_service_plugin_set_callbacks()) {
739 MAS_LOGE("Fail to set callbacks");
743 if (0 == vconf_notify_key_changed(MULTI_ASSISTANT_SETTINGS_ACTIVATED, mas_active_state_changed_cb, NULL)) {
744 /* Activate / deactivate according to the vconf key setting */
745 mas_active_state_changed_cb(NULL, NULL);
747 /* Multi-assistant needs to be enabled by default, unless disabled explicitly */
748 multi_assistant_service_plugin_activate();
749 vconf_set_bool(MULTI_ASSISTANT_SETTINGS_ACTIVATED, 1);
750 vconf_notify_key_changed(MULTI_ASSISTANT_SETTINGS_ACTIVATED, mas_active_state_changed_cb, NULL);
753 /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */
755 int res = vconf_get_bool(WAKEUP_SETTINGS_KEY_PRELAUNCH_MODE, &prelaunch_mode);
756 if (0 == res && 0 != prelaunch_mode) {
758 vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_DEFAULT_ASSISTANT_APPID);
760 MAS_LOGD("prelaunching default_assistant_appid : %s", vconf_str);
761 mas_launch_client_by_appid(vconf_str, CLIENT_LAUNCH_MODE_PRELAUNCH);
767 /* For the case of preprocessing assistant, it always have to be launched beforehand */
769 vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
771 MAS_LOGD("prelaunching preprocessing_assistant_appid : %s", vconf_str);
772 mas_launch_client_by_appid(vconf_str, CLIENT_LAUNCH_MODE_PRELAUNCH);
780 static void deinit_wakeup(void)
782 MAS_LOGD("[Enter] deinit_wakeup ");
784 /* if (NULL != g_current_lang) {
785 free(g_current_lang);
786 g_current_lang = NULL;
790 vconf_ignore_key_changed(MULTI_ASSISTANT_SETTINGS_ACTIVATED, mas_active_state_changed_cb);
792 int ret = mas_dbus_close_connection();
794 MAS_LOGE("[ERROR] Fail to close connection");
797 if (0 != multi_assistant_service_plugin_deinitialize()) {
798 MAS_LOGE("Fail to ws deinitialize");
802 int mas_get_current_client_pid()
805 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
806 const char *appid = g_maclient_info[g_current_maclient_info].appid;
807 ma_client_s* client = ma_client_find_by_appid(appid);
815 int mas_get_current_preprocessing_client_pid()
818 if (g_current_preprocessing_maclient_info >= 0 && g_current_preprocessing_maclient_info < MAX_MACLIENT_INFO_NUM) {
819 const char *appid = g_maclient_info[g_current_preprocessing_maclient_info].appid;
820 ma_client_s* client = ma_client_find_by_appid(appid);
828 int mas_get_client_pid_by_appid(const char *appid)
833 ma_client_s *client = NULL;
834 client = ma_client_find_by_appid(appid);
840 int status = aul_app_get_status_bypid(ret);
841 if (-1 != ret && 0 > status) {
842 MAS_LOGE("The PID for %s was %d, but it seems to be terminated : %d",
843 (appid ? appid : "NULL"), ret, status);
844 mas_client_deinitialize(ret);
851 bool mas_get_client_custom_ui_option_by_appid(const char *appid)
854 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
855 if (g_maclient_info[loop].used &&
856 0 < strlen(g_maclient_info[loop].appid) &&
857 0 < strlen(g_maclient_info[loop].wakeup_word[0])) {
858 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
859 ret = g_maclient_info[loop].custom_ui_option;
866 int mas_get_client_pid_by_wakeup_word(const char *wakeup_word)
868 const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
869 return mas_get_client_pid_by_appid(appid);
872 const char* mas_get_client_appid_by_wakeup_word(const char *wakeup_word)
875 const char *appid = NULL;
877 if (NULL == wakeup_word) return NULL;
879 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
880 if (g_maclient_info[loop].used &&
881 0 < strlen(g_maclient_info[loop].appid)) {
882 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
883 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
884 if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
885 appid = g_maclient_info[loop].appid;
892 /* Perform extended search, by eliminating blank characters */
894 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
895 if (g_maclient_info[loop].used &&
896 0 < strlen(g_maclient_info[loop].appid)) {
897 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
898 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
899 char comparand[MAX_WAKEUP_WORD_LEN];
900 int comparand_index = 0;
901 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
902 if (' ' != g_maclient_info[loop].wakeup_word[inner_loop][index]) {
903 comparand[comparand_index++] = g_maclient_info[loop].wakeup_word[inner_loop][index];
906 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
907 appid = g_maclient_info[loop].appid;
918 int mas_set_current_client_by_wakeup_word(const char *wakeup_word)
922 int prev_selection = g_current_maclient_info;
924 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
925 if (g_maclient_info[loop].used &&
926 0 < strlen(g_maclient_info[loop].appid)) {
927 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
928 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
929 if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
930 g_current_maclient_info = loop;
937 /* Perform extended search, by eliminating blank characters */
939 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
940 if (g_maclient_info[loop].used &&
941 0 < strlen(g_maclient_info[loop].appid)) {
942 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
943 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
944 char comparand[MAX_WAKEUP_WORD_LEN];
945 int comparand_index = 0;
946 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
947 if (' ' != g_maclient_info[loop].wakeup_word[inner_loop][index]) {
948 comparand[comparand_index++] = g_maclient_info[loop].wakeup_word[inner_loop][index];
951 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
952 g_current_maclient_info = loop;
961 if (g_current_maclient_info != prev_selection) {
962 if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) {
963 mas_client_deactivate(mas_get_client_pid_by_appid(g_maclient_info[prev_selection].appid));
970 int mas_set_current_client_by_appid(const char *appid)
973 int prev_selection = g_current_maclient_info;
975 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
976 if (g_maclient_info[loop].used &&
977 0 < strlen(g_maclient_info[loop].appid) &&
978 0 < strlen(g_maclient_info[loop].wakeup_word[0])) {
979 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
980 g_current_maclient_info = loop;
986 if (g_current_maclient_info != prev_selection) {
987 if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) {
988 mas_client_deactivate(mas_get_client_pid_by_appid(g_maclient_info[prev_selection].appid));
995 int mas_launch_client_by_appid(const char *appid, CLIENT_LAUNCH_MODE launch_mode)
997 if (NULL == appid || 0 == strlen(appid)) {
998 MAS_LOGE("appid invalid, failed launching MA Client");
1003 b = bundle_create();
1005 MAS_LOGE("Failed creating bundle for aul operation");
1009 int result = aul_svc_set_background_launch(b, TRUE);
1010 if (result < AUL_R_OK) {
1011 MAS_LOGE("ERROR : aul_svc_set_background_launch failed. app_id [%s] bundle[%p] result[%d : %s]",
1012 appid, b, result, get_error_message(result));
1015 result = aul_launch_app(appid, b);
1016 if (result < AUL_R_OK) {
1017 MAS_LOGE("ERROR : aul_launch_app failed. app_id [%s] bundle[%p] result[%d : %s]",
1018 appid, b, result, get_error_message(result));
1021 if (CLIENT_LAUNCH_MODE_ACTIVATION == launch_mode) {
1023 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
1024 if (g_maclient_info[loop].used &&
1025 0 < strlen(g_maclient_info[loop].appid)) {
1026 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
1027 g_wakeup_maclient_appid = g_maclient_info[loop].appid;
1032 MAS_LOGD("g_wakeup_maclient_appid : %s, %d", g_wakeup_maclient_appid, found);
1035 if (b) bundle_free(b);
1041 int mas_bring_client_to_foreground(const char* appid)
1043 /* Bring MA client to foreground - is there a better way other than launching? */
1044 if (NULL == appid || 0 == strlen(appid)) {
1045 MAS_LOGE("appid invalid, failed launching MA Client");
1050 b = bundle_create();
1052 MAS_LOGE("Failed creating bundle for aul operation");
1056 int result = aul_launch_app(appid, b);
1057 if (result < AUL_R_OK) {
1058 MAS_LOGE("ERROR : aul_launch_app failed. app_id [%s] bundle[%p] result[%d : %s]",
1059 appid, b, result, get_error_message(result));
1062 if (b) bundle_free(b);
1068 int mas_launch_client_by_wakeup_word(const char *wakeup_word)
1070 const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
1071 return mas_launch_client_by_appid(appid, CLIENT_LAUNCH_MODE_ACTIVATION);
1075 int mas_process_voice_key_event(bool pressed)
1078 multi_assistant_service_plugin_process_event(MA_PLUGIN_EVENT_VOICE_KEY_PRESSED, NULL, 0);
1080 multi_assistant_service_plugin_process_event(MA_PLUGIN_EVENT_VOICE_KEY_RELEASED, NULL, 0);
1085 ma_preprocessing_allow_mode_e get_preprocessing_allow_mode(const char* appid)
1087 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
1088 if (appid && g_maclient_info[loop].used) {
1089 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
1090 return g_maclient_info[loop].preprocessing_allow_mode;
1094 return MA_PREPROCESSING_ALLOW_NONE;
1097 int mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT event)
1099 const char* current_maclient_appid = NULL;
1100 const char* preprocessing_allow_appid = NULL;
1101 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
1102 current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
1103 preprocessing_allow_appid = g_maclient_info[g_current_maclient_info].preprocessing_allow_appid;
1105 ma_preprocessing_allow_mode_e mode = get_preprocessing_allow_mode(current_maclient_appid);
1108 case PREPROCESSING_STATE_EVENT_WAKEUP:
1109 case PREPROCESSING_STATE_EVENT_ACTIVE_ASSISTANT_LAUNCHED:
1111 if (!check_preprocessing_assistant_exists()) {
1112 mas_bring_client_to_foreground(current_maclient_appid);
1114 g_current_preprocessing_state = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED;
1115 if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode ||
1116 MA_PREPROCESSING_ALLOW_ALL == mode) {
1117 if (is_current_preprocessing_assistant(preprocessing_allow_appid)) {
1118 g_current_preprocessing_state = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED;
1123 case PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED:
1125 g_current_preprocessing_state = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED;
1126 if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode ||
1127 MA_PREPROCESSING_ALLOW_ALL == mode) {
1128 if (is_current_preprocessing_assistant(preprocessing_allow_appid)) {
1129 g_current_preprocessing_state = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED;
1134 case PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED:
1136 if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED == g_current_preprocessing_state) {
1137 g_current_preprocessing_state = PREPROCESSING_STATE_PREPROCESSING_UTTERANCE;
1138 } else if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED == g_current_preprocessing_state) {
1139 mas_bring_client_to_foreground(current_maclient_appid);
1140 g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1144 case PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED:
1146 if (MA_PREPROCESSING_ALLOW_FOLLOW_UP == mode ||
1147 MA_PREPROCESSING_ALLOW_ALL == mode) {
1148 g_current_preprocessing_state = PREPROCESSING_STATE_PREPROCESSING_FOLLOW_UP;
1152 case PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED:
1154 g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1157 case PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED:
1159 mas_bring_client_to_foreground(current_maclient_appid);
1160 g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1167 bool service_app_create(void *data)
1169 // Todo: add your code here.
1171 MAS_LOGD("[Enter] Service app create");
1173 if (0 != init_wakeup()) {
1174 MAS_LOGE("Fail to init wakeup service");
1181 void service_app_terminate(void *data)
1183 // Todo: add your code here.
1188 void service_app_control(app_control_h app_control, void *data)
1190 // Todo: add your code here.
1195 service_app_lang_changed(app_event_info_h event_info, void *user_data)
1197 /*APP_EVENT_LANGUAGE_CHANGED*/
1202 service_app_region_changed(app_event_info_h event_info, void *user_data)
1204 /*APP_EVENT_REGION_FORMAT_CHANGED*/
1208 service_app_low_battery(app_event_info_h event_info, void *user_data)
1210 /*APP_EVENT_LOW_BATTERY*/
1214 service_app_low_memory(app_event_info_h event_info, void *user_data)
1216 /*APP_EVENT_LOW_MEMORY*/
1219 int main(int argc, char* argv[])
1222 service_app_lifecycle_callback_s event_callback;
1223 app_event_handler_h handlers[5] = {NULL, };
1225 event_callback.create = service_app_create;
1226 event_callback.terminate = service_app_terminate;
1227 event_callback.app_control = service_app_control;
1229 service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, service_app_low_battery, &ad);
1230 service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, service_app_low_memory, &ad);
1231 service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, service_app_lang_changed, &ad);
1232 service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, service_app_region_changed, &ad);
1234 return service_app_main(argc, argv, &event_callback, ad);