Change the name of variables moved into classes
[platform/core/uifw/multi-assistant-service.git] / src / service_main.cpp
1 /*
2  * Copyright 2018-2019 Samsung Electronics Co., Ltd
3  *
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
7  *
8  * http://floralicense.org/license/
9  *
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.
15  */
16
17 #include <tizen.h>
18 #include <service_app.h>
19 #include <app_manager.h>
20 #include <app.h>
21 #include <aul.h>
22 #include <aul_svc.h>
23 #include <malloc.h>
24 #include <Ecore.h>
25 #include <vconf.h>
26 #include <pkgmgr-info.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <glib.h>
32
33 #include "service_common.h"
34 #include "service_main.h"
35 #include "service_plugin.h"
36 #include "service_ipc_dbus.h"
37 #include "service_config.h"
38
39 static CServiceMain* g_service_main = nullptr;
40
41 bool CServiceMain::check_preprocessing_assistant_exists()
42 {
43         bool ret = false;
44
45         char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
46         if (vconf_str) {
47                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
48                         if (mClientInfo[loop].used &&
49                                 strncmp(vconf_str, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
50                                 if (mClientManager.check_client_validity_by_appid(std::string{vconf_str})) {
51                                         ret = true;
52                                 }
53                         }
54                 }
55                 free(vconf_str);
56                 vconf_str = NULL;
57         }
58
59         MAS_LOGD("result : %d", ret);
60
61         return ret;
62 }
63
64 bool CServiceMain::is_current_preprocessing_assistant(const char* appid)
65 {
66         if (NULL == appid) return false;
67
68         bool ret = false;
69
70         char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
71         if (vconf_str) {
72                 if (strncmp(vconf_str, appid, MAX_APPID_LEN) == 0) {
73                         ret = true;
74                 }
75                 free(vconf_str);
76                 vconf_str = NULL;
77         }
78
79         return ret;
80 }
81
82 int CServiceMain::mas_client_get_audio_format(int pid, int* rate, int* channel, int* audio_type)
83 {
84         MAS_LOGD("[Enter] pid(%d)", pid);
85
86         int ret = mServicePlugin.get_recording_audio_format(rate, channel, audio_type);
87         if (0 != ret){
88                 MAS_LOGE("[ERROR] Fail to get recording audio format, ret(%d)", ret);
89         }
90
91         return ret;
92 }
93
94 #define MAX_LOCAL_VARIABLE_STRING_LEN 256
95 int CServiceMain::mas_client_get_audio_source_type(int pid, char** type)
96 {
97         MAS_LOGD("[Enter] pid(%d)", pid);
98
99         if (NULL == type) return -1;
100
101         static char cached[MAX_LOCAL_VARIABLE_STRING_LEN] = {'\0'};
102         int ret = mServicePlugin.get_recording_audio_source_type(type);
103         if (0 != ret){
104                 MAS_LOGE("[ERROR] Fail to get recording audio source type, ret(%d)", ret);
105                 *type = cached;
106         } else if (*type) {
107                 strncpy(cached, *type, MAX_LOCAL_VARIABLE_STRING_LEN - 1);
108                 cached[MAX_LOCAL_VARIABLE_STRING_LEN - 1] = '\0';
109         }
110
111         return ret;
112 }
113
114 int CServiceMain::mas_client_send_preprocessing_information(int pid)
115 {
116         int ret = -1;
117         MAS_LOGD("[Enter] pid(%d)", pid);
118
119         char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
120         MAS_LOGD("preprocessing_assistant_appid : %s", vconf_str);
121         if (vconf_str) {
122                 ret = mServiceIpc.send_preprocessing_information(pid, vconf_str);
123                 free(vconf_str);
124                 vconf_str = NULL;
125         }
126
127         return ret;
128 }
129
130 int CServiceMain::mas_client_send_voice_key_status_change(int pid, ma_voice_key_status_e status)
131 {
132         int ret = -1;
133         MAS_LOGD("[Enter] pid(%d)", pid);
134
135         ret = mServiceIpc.voice_key_status_change(pid, status);
136         if (0 != ret) {
137                 MAS_LOGE("[ERROR] Fail to send voice key status changed information, ret(%d)", ret);
138         }
139         mLastVoiceKeyStatus = status;
140
141         return ret;
142 }
143
144 int CServiceMain::mas_client_send_asr_result(int pid, int event, const char* asr_result)
145 {
146         MAS_LOGD("[Enter] pid(%d), event(%d), asr_result(%s)", pid, event, asr_result);
147         int ret = mServiceIpc.masc_ui_dbus_send_asr_result(pid, event, asr_result);
148         if (0 != ret){
149                 MAS_LOGE("[ERROR] Fail to send asr result, ret(%d)", ret);
150         }
151
152         // if final event is , launch assistant app which is invoked with wakeup word.
153         /* TO_DO */
154         return ret;
155 }
156
157 int CServiceMain::mas_client_send_result(int pid, const char* display_text,
158         const char* utterance_text, const char* result_json)
159 {
160         MAS_LOGD("[Enter] pid(%d), display_text(%s), utterance_text(%s), result_json(%s)", pid, display_text, utterance_text, result_json);
161         int ret = mServiceIpc.masc_ui_dbus_send_result(pid, display_text, utterance_text, result_json);
162         if (0 != ret){
163                 MAS_LOGE("[ERROR] Fail to send result, ret(%d)", ret);
164         }
165
166         const char* pid_appid = NULL;
167         char buf[MAX_APPID_LEN] = {'\0', };
168         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
169                 buf[MAX_APPID_LEN - 1] = '\0';
170                 pid_appid = buf;
171         }
172         mServicePlugin.update_recognition_result(pid_appid, MA_RECOGNITION_RESULT_EVENT_SUCCESS);
173
174         return ret;
175 }
176
177 int CServiceMain::mas_client_send_recognition_result(int pid, int result)
178 {
179         MAS_LOGD("[Enter] pid(%d), result(%d)", pid, result);
180         int ret = mServiceIpc.masc_ui_dbus_send_recognition_result(pid, result);
181         if (0 != ret){
182                 MAS_LOGE("[ERROR] Fail to send recognition result, ret(%d)", ret);
183         }
184
185         const char* pid_appid = NULL;
186         char buf[MAX_APPID_LEN] = {'\0', };
187         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
188                 buf[MAX_APPID_LEN - 1] = '\0';
189                 pid_appid = buf;
190         }
191         mServicePlugin.update_recognition_result(pid_appid, result);
192
193         return ret;
194 }
195
196 int CServiceMain::mas_client_start_streaming_audio_data(int pid, int type)
197 {
198         int ret = -1;
199         switch(type) {
200                 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
201                         ret = mServicePlugin.start_streaming_utterance_data();
202                         mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED);
203                         break;
204                 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
205                         ret = mServicePlugin.start_streaming_previous_utterance_data();
206                         /* Preprocessing is not required for previous utterance streaming */
207                         break;
208                 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
209                         ret = mServicePlugin.start_streaming_follow_up_data();
210                         mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED);
211                         break;
212         }
213         return ret;
214 }
215
216 int CServiceMain::mas_client_stop_streaming_audio_data(int pid, int type)
217 {
218         int ret = -1;
219         switch(type) {
220                 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
221                         ret = mServicePlugin.stop_streaming_utterance_data();
222                         break;
223                 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
224                         ret = mServicePlugin.stop_streaming_previous_utterance_data();
225                         break;
226                 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
227                         ret = mServicePlugin.stop_streaming_follow_up_data();
228                         break;
229         }
230         return ret;
231 }
232
233 int CServiceMain::mas_client_update_voice_feedback_state(int pid, int state)
234 {
235         const char* pid_appid = NULL;
236         char buf[MAX_APPID_LEN] = {'\0', };
237         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
238                 buf[MAX_APPID_LEN - 1] = '\0';
239                 pid_appid = buf;
240         }
241         mServicePlugin.update_voice_feedback_state(pid_appid, state);
242         return 0;
243 }
244
245 int CServiceMain::mas_client_set_assistant_specific_command(int pid, const char *command)
246 {
247         const char* pid_appid = NULL;
248         char buf[MAX_APPID_LEN] = {'\0', };
249         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
250                 buf[MAX_APPID_LEN - 1] = '\0';
251                 pid_appid = buf;
252         }
253         mServicePlugin.set_assistant_specific_command(pid_appid, command);
254         return 0;
255 }
256
257 int CServiceMain::mas_client_set_background_volume(int pid, double ratio)
258 {
259         const char* pid_appid = NULL;
260         char buf[MAX_APPID_LEN] = {'\0', };
261         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
262                 buf[MAX_APPID_LEN - 1] = '\0';
263                 pid_appid = buf;
264         }
265         mServicePlugin.set_background_volume(pid_appid, ratio);
266         return 0;
267 }
268
269 int CServiceMain::mas_client_set_preprocessing_allow_mode(int pid, ma_preprocessing_allow_mode_e mode, const char* appid)
270 {
271         const char* pid_appid = NULL;
272         char buf[MAX_APPID_LEN] = {'\0', };
273         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
274                 buf[MAX_APPID_LEN - 1] = '\0';
275                 pid_appid = buf;
276         }
277
278         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
279                 if (mClientInfo[loop].used) {
280                         if (pid_appid && strncmp(pid_appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
281                                 mClientInfo[loop].preprocessing_allow_mode = mode;
282                                 if (appid) {
283                                         strncpy(mClientInfo[loop].preprocessing_allow_appid, appid, MAX_APPID_LEN);
284                                         mClientInfo[loop].preprocessing_allow_appid[MAX_APPID_LEN - 1] = '\0';
285                                 } else {
286                                         mClientInfo[loop].preprocessing_allow_appid[0] = '\0';
287                                 }
288                         }
289                 }
290         }
291
292         mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED);
293
294         return 0;
295 }
296
297 int CServiceMain::mas_client_send_preprocessing_result(int pid, bool result)
298 {
299         const char* pid_appid = NULL;
300         char buf[MAX_APPID_LEN] = {'\0', };
301         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
302                 buf[MAX_APPID_LEN - 1] = '\0';
303                 pid_appid = buf;
304         }
305         if (!is_current_preprocessing_assistant(pid_appid)) return -1;
306
307         const char *current_maclient_appid = NULL;
308         if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) {
309                 current_maclient_appid = mClientInfo[mCurrentClientInfo].appid;
310         }
311
312         if (result) {
313                 MAS_LOGD("Preprocessing succeeded, bring (%s) to foreground", pid_appid);
314                 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED);
315         } else {
316                 MAS_LOGD("Preprocessing failed, bring (%s) to foreground", current_maclient_appid);
317                 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED);
318         }
319
320         if (current_maclient_appid) {
321                 int pid = mClientManager.find_client_pid_by_appid(
322                         std::string{current_maclient_appid});
323                 mServiceIpc.send_preprocessing_result(pid, result);
324         }
325
326         return 0;
327 }
328
329 int CServiceMain::mas_client_set_wake_word_audio_require_flag(int pid, bool require)
330 {
331         const char* pid_appid = NULL;
332         char buf[MAX_APPID_LEN] = {'\0', };
333         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
334                 buf[MAX_APPID_LEN - 1] = '\0';
335                 pid_appid = buf;
336         }
337
338         mServicePlugin.set_wake_word_audio_require_flag(pid_appid, require);
339         return 0;
340 }
341
342 int CServiceMain::mas_client_set_assistant_language(int pid, const char* language)
343 {
344         const char* pid_appid = NULL;
345         char buf[MAX_APPID_LEN] = {'\0', };
346         int ret = aul_app_get_appid_bypid(pid, buf, sizeof(buf));
347         if (AUL_R_OK == ret) {
348                 buf[MAX_APPID_LEN - 1] = '\0';
349                 pid_appid = buf;
350         }
351
352         mServicePlugin.set_assistant_language(pid_appid, language);
353         return 0;
354 }
355
356 int CServiceMain::mas_client_add_wake_word(int pid, const char* wake_word, const char* language)
357 {
358         const char* pid_appid = NULL;
359         char buf[MAX_APPID_LEN] = {'\0', };
360         int ret = aul_app_get_appid_bypid(pid, buf, sizeof(buf));
361         if (AUL_R_OK == ret) {
362                 buf[MAX_APPID_LEN - 1] = '\0';
363                 pid_appid = buf;
364         }
365
366         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
367                 if (mClientInfo[loop].used &&
368                         0 == strncmp(buf, mClientInfo[loop].appid, MAX_APPID_LEN)) {
369                         ret = mServiceConfig.add_custom_wake_word(wake_word, language,
370                                 mClientInfo[loop].wakeup_word,
371                                 mClientInfo[loop].wakeup_language);
372                         if (0 == ret) {
373                                 mServiceConfig.save_custom_wake_words(pid_appid,
374                                         mClientInfo[loop].wakeup_word,
375                                         mClientInfo[loop].wakeup_language);
376                         } else {
377                                 LOGE("add new wake word failed!");
378                                 return -1;
379                         }
380                 }
381         }
382
383         mServicePlugin.add_assistant_wakeup_word(pid_appid, wake_word, language);
384         return 0;
385 }
386
387 int CServiceMain::mas_client_remove_wake_word(int pid, const char* wake_word, const char* language)
388 {
389         const char* pid_appid = NULL;
390         char buf[MAX_APPID_LEN] = {'\0', };
391         int ret = aul_app_get_appid_bypid(pid, buf, sizeof(buf));
392         if (AUL_R_OK == ret) {
393                 buf[MAX_APPID_LEN - 1] = '\0';
394                 pid_appid = buf;
395         }
396
397         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
398                 if (mClientInfo[loop].used &&
399                         0 == strncmp(buf, mClientInfo[loop].appid, MAX_APPID_LEN)) {
400                         ret = mServiceConfig.remove_custom_wake_word(wake_word, language,
401                                 mClientInfo[loop].wakeup_word,
402                                 mClientInfo[loop].wakeup_language);
403                         if (0 == ret) {
404                                 mServiceConfig.save_custom_wake_words(pid_appid,
405                                         mClientInfo[loop].wakeup_word,
406                                         mClientInfo[loop].wakeup_language);
407                         }
408                 }
409         }
410
411         mServicePlugin.remove_assistant_wakeup_word(pid_appid, wake_word, language);
412         return 0;
413 }
414
415 int CServiceMain::mas_ui_client_initialize(int pid)
416 {
417         MAS_LOGD("[Enter] pid(%d)", pid);
418
419         return 0;
420 }
421
422 int CServiceMain::mas_ui_client_deinitialize(int pid)
423 {
424         MAS_LOGD("[Enter] pid(%d)", pid);
425
426         return 0;
427 }
428
429 int CServiceMain::mas_ui_client_change_assistant(const char* appid)
430 {
431         MAS_LOGD("[Enter]");
432
433         if (NULL == appid) {
434                 MAS_LOGE("NULL parameter");
435                 return -1;
436         }
437
438         bool use_custom_ui = mas_get_client_custom_ui_option_by_appid(appid);
439         mServiceIpc.masc_ui_dbus_enable_common_ui(!use_custom_ui);
440
441         mas_set_current_client_by_appid(appid);
442         int pid = mas_get_client_pid_by_appid(appid);
443         if (pid != -1) {
444                 mas_bring_client_to_foreground(appid);
445                 mas_client_send_preprocessing_information(pid);
446                 if (MA_VOICE_KEY_STATUS_PRESSED == mLastVoiceKeyStatus) {
447                         mas_client_send_voice_key_status_change(pid, mLastVoiceKeyStatus);
448                 }
449
450                 mServiceIpc.active_state_change(pid, MA_ACTIVE_STATE_ACTIVE);
451                 MAS_LOGD("MA Client with appid %s exists, requesting speech data", (appid ? appid : "NULL"));
452                 /*
453                 int ret = mServicePlugin.start_streaming_utterance_data();
454                 if (0 != ret) {
455                         MAS_LOGE("[ERROR] Fail to start streaming utterance data(%d)", ret);
456                 }
457                 */
458         } else {
459                 // Appropriate MA Client not available, trying to launch new one
460                 MAS_LOGD("MA Client with appid %s does not exist, launching client", (appid ? appid : "NULL"));
461
462                 /* The appid parameter might not exist after this function call, so we use appid string in our mClientInfo */
463                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
464                         if (mClientInfo[loop].used &&
465                                 0 < strlen(mClientInfo[loop].appid) &&
466                                 0 < strlen(mClientInfo[loop].wakeup_word[0])) {
467                                 if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
468                                         mas_launch_client_by_appid(mClientInfo[loop].appid, CLIENT_LAUNCH_MODE_ACTIVATION);
469                                 }
470                         }
471                 }
472         }
473
474         return 0;
475 }
476
477 static int mas_assistant_info_cb(ma_assistant_info_s* info, void* user_data) {
478         int ret = -1;
479         CServiceMain* service_main = static_cast<CServiceMain*>(user_data);
480         if (service_main) {
481                 ret = service_main->add_assistant_info(info);
482         }
483         return ret;
484 }
485
486 int CServiceMain::add_assistant_info(ma_assistant_info_s* info) {
487         MAS_LOGD("__mas_assistant_info_cb called");
488
489         if (NULL == info) {
490                 MAS_LOGE("info NULL, returning");
491                 return -1;
492         }
493         if (NULL == info->app_id) {
494                 MAS_LOGE("app_id NULL, returning");
495                 return -1;
496         }
497
498         int index = -1;
499         int loop = 0;
500         while(-1 == index && loop < MAX_MACLIENT_INFO_NUM) {
501                 if (false == mClientInfo[loop].used) {
502                         index = loop;
503                 }
504                 loop++;
505         }
506         if (-1 != index) {
507                 mClientInfo[index].used = true;
508                 mClientInfo[index].preprocessing_allow_mode = MA_PREPROCESSING_ALLOW_NONE;
509                 mClientInfo[index].preprocessing_allow_appid[0] = '\0';
510                 MAS_LOGD("app_id(%s)", info->app_id);
511                 strncpy(mClientInfo[index].appid, info->app_id, MAX_APPID_LEN);
512                 mClientInfo[index].appid[MAX_APPID_LEN - 1] = '\0';
513
514                 if (is_current_preprocessing_assistant(mClientInfo[index].appid)) {
515                         mCurrentPreprocessingClientInfo = index;
516                 }
517
518                 for (loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
519                         if (loop < info->cnt_wakeup && info->wakeup_list[loop]) {
520                                 MAS_LOGD("wakeup_list(%d)(%s)(%s)", loop, info->wakeup_list[loop], info->wakeup_language[loop]);
521                                 strncpy(mClientInfo[index].wakeup_word[loop], info->wakeup_list[loop], MAX_WAKEUP_WORD_LEN);
522                                 mClientInfo[index].wakeup_word[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0';
523                                 if (info->wakeup_language[loop]) {
524                                         strncpy(mClientInfo[index].wakeup_language[loop], info->wakeup_language[loop], MAX_SUPPORTED_LANGUAGE_LEN);
525                                         mClientInfo[index].wakeup_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
526                                 } else {
527                                         strncpy(mClientInfo[index].wakeup_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
528                                 }
529                         } else {
530                                 strncpy(mClientInfo[index].wakeup_word[loop], "", MAX_WAKEUP_WORD_LEN);
531                         }
532                 }
533
534                 for (loop = 0;loop < MAX_SUPPORTED_LANGUAGES_NUM;loop++) {
535                         if (loop < info->cnt_lang && info->supported_lang[loop]) {
536                                 MAS_LOGD("supported_lang(%d)(%s)", loop, info->supported_lang[loop]);
537                                 strncpy(mClientInfo[index].supported_language[loop], info->supported_lang[loop], MAX_SUPPORTED_LANGUAGE_LEN);
538                                 mClientInfo[index].supported_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
539                         } else {
540                                 strncpy(mClientInfo[index].supported_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
541                         }
542                 }
543
544                 MAS_LOGD("wakeup_engine(%s)", info->wakeup_engine);
545                 if (info->wakeup_engine) {
546                         strncpy(mClientInfo[index].wakeup_engine, info->wakeup_engine, MAX_APPID_LEN);
547                         mClientInfo[index].wakeup_engine[MAX_APPID_LEN - 1] = '\0';
548                 } else {
549                         mClientInfo[index].wakeup_engine[0] = '\0';
550                         MAS_LOGW("Wakeup engine information not provided for : %s", info->app_id);
551                 }
552                 mClientInfo[index].custom_ui_option = info->custom_ui_option;
553
554                 MAS_LOGD("voice_key_support_mode(%d)", info->voice_key_support_mode);
555                 mClientInfo[index].voice_key_support_mode = info->voice_key_support_mode;
556                 MAS_LOGD("voice_key_tap_duration(%f)", info->voice_key_tap_duration);
557                 mClientInfo[index].voice_key_tap_duration = info->voice_key_tap_duration;
558         } else {
559                 MAS_LOGD("Couldn't find an empty slot for storing assistant info");
560         }
561
562         MAS_LOGD("__mas_assistant_info_cb end");
563
564         return 0;
565 }
566
567 static void active_state_changed_cb(keynode_t* key, void* data)
568 {
569         int vconf_value = 0;
570         if (vconf_get_bool(MULTI_ASSISTANT_SETTINGS_ACTIVATED, &vconf_value) == 0) {
571                 MAS_LOGD("multi-assistant active state : %d\n", vconf_value);
572
573                 CServicePlugin *plugin = nullptr;
574                 if (g_service_main) {
575                         plugin = g_service_main->get_service_plugin();
576                 }
577                 if (plugin) {
578                         if (vconf_value) {
579                                 plugin->activate();
580                         } else {
581                                 plugin->deactivate();
582                         }
583                 } else {
584                         MAS_LOGE("Could not change plugin state : %p %p", g_service_main, plugin);
585                 }
586         }
587 }
588
589 int CServiceMain::initialize_service_plugin(void)
590 {
591         if (0 != mServicePlugin.initialize()) {
592                 MAS_LOGE("Fail to ws intialize");
593                 return -1;
594         }
595
596         if (0 != mServicePlugin.set_language(mCurrentLanguage.c_str())) {
597                 MAS_LOGE("Fail to ws set language");
598                 return -1;
599         }
600
601         if (0 == mServiceConfig.get_assistant_info(mas_assistant_info_cb, this)) {
602                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
603                         int inner_loop;
604                         if (mClientInfo[loop].used &&
605                                 0 < strlen(mClientInfo[loop].appid)) {
606                                 mServiceConfig.load_custom_wake_words(mClientInfo[loop].appid,
607                                         mClientInfo[loop].wakeup_word, mClientInfo[loop].wakeup_language);
608                                 if (0 < strlen(mClientInfo[loop].wakeup_engine)) {
609                                         mServicePlugin.set_assistant_wakeup_engine(
610                                                 mClientInfo[loop].appid,
611                                                 mClientInfo[loop].wakeup_engine);
612                                 }
613                                 for (inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
614                                         if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
615                                                 MAS_LOGD("Registering wakeup word %s for app %s",
616                                                         mClientInfo[loop].wakeup_word[inner_loop], mClientInfo[loop].appid);
617                                                 if (0 != mServicePlugin.add_assistant_wakeup_word(
618                                                         mClientInfo[loop].appid,
619                                                         mClientInfo[loop].wakeup_word[inner_loop],
620                                                         mClientInfo[loop].wakeup_language[inner_loop])) {
621                                                         MAS_LOGE("Fail to add assistant's wakeup word");
622                                                 }
623                                         }
624                                 }
625                                 for (inner_loop = 0; inner_loop < MAX_SUPPORTED_LANGUAGE_NUM; inner_loop++) {
626                                         if (0 < strlen(mClientInfo[loop].supported_language[inner_loop])) {
627                                                 MAS_LOGD("Adding language %s for app %s",
628                                                         mClientInfo[loop].supported_language[inner_loop], mClientInfo[loop].appid);
629                                                 if (0 != mServicePlugin.add_assistant_language(
630                                                         mClientInfo[loop].appid,
631                                                         mClientInfo[loop].supported_language[inner_loop])) {
632                                                         MAS_LOGE("Fail to add assistant's language");
633                                                 }
634                                         }
635                                 }
636                         }
637                 }
638         } else {
639                 MAS_LOGE("Fail to load assistant info");
640         }
641
642         if (0 != mServicePlugin.set_callbacks()) {
643                 MAS_LOGE("Fail to set callbacks");
644                 return -1;
645         }
646
647         return 0;
648 }
649
650 int CServiceMain::deinitialize_service_plugin(void)
651 {
652         MAS_LOGI("[ENTER]");
653         if (0 != mServicePlugin.deactivate()) {
654                 MAS_LOGE("Fail to deactivate");
655         }
656         if (0 != mServicePlugin.deinitialize()) {
657                 MAS_LOGE("Fail to deinitialize");
658         }
659         MAS_LOGI("[END]");
660         return 0;
661 }
662
663 int CServiceMain::process_activated_setting()
664 {
665         if (0 == vconf_notify_key_changed(MULTI_ASSISTANT_SETTINGS_ACTIVATED, active_state_changed_cb, NULL)) {
666                 /* Activate / deactivate according to the vconf key setting */
667                 active_state_changed_cb(NULL, NULL);
668         } else {
669 #ifdef ENABLE_MULTI_ASSISTANT_BY_DEFAULT
670                 /* Multi-assistant needs to be enabled by default, unless disabled explicitly */
671                 mServicePlugin.activate();
672                 const char *default_assistant = NULL;
673                 if (0 == mServicePlugin.get_default_assistant(&default_assistant)) {
674                         if (NULL == default_assistant) {
675                                 if (mClientInfo[0].used) {
676                                         default_assistant = mClientInfo[0].appid;
677                                         MAS_LOGW("No default assistant, setting %s as default", default_assistant);
678                                         mServicePlugin.set_default_assistant(default_assistant);
679                                 } else {
680                                         MAS_LOGE("No default assistant, and no assistant installed");
681                                 }
682                         }
683                 }
684 #endif
685         }
686         return 0;
687 }
688
689 int CServiceMain::mas_get_current_client_pid()
690 {
691         int ret = -1;
692         if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) {
693                 const char *appid = mClientInfo[mCurrentClientInfo].appid;
694                 if (appid) {
695                         ret = mClientManager.find_client_pid_by_appid(std::string{appid});
696                 }
697         }
698         return ret;
699 }
700
701 int CServiceMain::mas_get_current_preprocessing_client_pid()
702 {
703         int ret = -1;
704         if (mCurrentPreprocessingClientInfo >= 0 && mCurrentPreprocessingClientInfo < MAX_MACLIENT_INFO_NUM) {
705                 const char *appid = mClientInfo[mCurrentPreprocessingClientInfo].appid;
706                 if (appid) {
707                         ret = mClientManager.find_client_pid_by_appid(std::string{appid});
708                 }
709         }
710         return ret;
711 }
712
713 int CServiceMain::mas_get_client_pid_by_appid(const char *appid)
714 {
715         int ret = -1;
716
717         if (appid) {
718                 ret = mClientManager.find_client_pid_by_appid(std::string{appid});
719         }
720
721         int status = aul_app_get_status_bypid(ret);
722         if (-1 != ret && 0 > status) {
723                 MAS_LOGE("The PID for %s was %d, but it seems to be terminated : %d",
724                         (appid ? appid : "NULL"), ret, status);
725                 on_deinitialize(ret);
726                 ret = -1;
727         }
728
729         return ret;
730 }
731
732 bool CServiceMain::mas_get_client_custom_ui_option_by_appid(const char *appid)
733 {
734         bool ret = false;
735         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
736                 if (mClientInfo[loop].used &&
737                         0 < strlen(mClientInfo[loop].appid) &&
738                         0 < strlen(mClientInfo[loop].wakeup_word[0])) {
739                         if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
740                                 ret = mClientInfo[loop].custom_ui_option;
741                         }
742                 }
743         }
744         return ret;
745 }
746
747 int CServiceMain::mas_get_client_pid_by_wakeup_word(const char *wakeup_word)
748 {
749         const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
750         return mas_get_client_pid_by_appid(appid);
751 }
752
753 const char* CServiceMain::mas_get_client_appid_by_wakeup_word(const char *wakeup_word)
754 {
755         int loop;
756         const char *appid = NULL;
757
758         if (NULL == wakeup_word) return NULL;
759
760         for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
761                 if (mClientInfo[loop].used &&
762                         0 < strlen(mClientInfo[loop].appid)) {
763                         for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
764                                 if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
765                                         if (0 == strncmp(wakeup_word, mClientInfo[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
766                                                 appid = mClientInfo[loop].appid;
767                                         }
768                                 }
769                         }
770                 }
771         }
772
773         /* Perform extended search, by eliminating blank characters */
774         if (NULL == appid) {
775                 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
776                         if (mClientInfo[loop].used &&
777                                 0 < strlen(mClientInfo[loop].appid)) {
778                                 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
779                                         if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
780                                                 char comparand[MAX_WAKEUP_WORD_LEN];
781                                                 int comparand_index = 0;
782                                                 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
783                                                         if (' ' != mClientInfo[loop].wakeup_word[inner_loop][index]) {
784                                                                 comparand[comparand_index++] = mClientInfo[loop].wakeup_word[inner_loop][index];
785                                                         }
786                                                 }
787                                                 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
788                                                         appid = mClientInfo[loop].appid;
789                                                 }
790                                         }
791                                 }
792                         }
793                 }
794         }
795
796         return appid;
797 }
798
799 int CServiceMain::mas_set_current_client_by_wakeup_word(const char *wakeup_word)
800 {
801         int loop;
802         int ret = -1;
803         int prev_selection = mCurrentClientInfo;
804
805         for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
806                 if (mClientInfo[loop].used &&
807                         0 < strlen(mClientInfo[loop].appid)) {
808                         for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
809                                 if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
810                                         if (0 == strncmp(wakeup_word, mClientInfo[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
811                                                 mCurrentClientInfo = loop;
812                                                 ret = 0;
813                                         }
814                                 }
815                         }
816                 }
817         }
818         /* Perform extended search, by eliminating blank characters */
819         if (ret == -1) {
820                 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
821                         if (mClientInfo[loop].used &&
822                                 0 < strlen(mClientInfo[loop].appid)) {
823                                 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
824                                         if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
825                                                 char comparand[MAX_WAKEUP_WORD_LEN];
826                                                 int comparand_index = 0;
827                                                 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
828                                                         if (' ' != mClientInfo[loop].wakeup_word[inner_loop][index]) {
829                                                                 comparand[comparand_index++] = mClientInfo[loop].wakeup_word[inner_loop][index];
830                                                         }
831                                                 }
832                                                 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
833                                                         mCurrentClientInfo = loop;
834                                                         ret = 0;
835                                                 }
836                                         }
837                                 }
838                         }
839                 }
840         }
841
842         if (mCurrentClientInfo != prev_selection) {
843                 if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) {
844                         int pid = mas_get_client_pid_by_appid(mClientInfo[prev_selection].appid);
845                         mServiceIpc.active_state_change(pid, MA_ACTIVE_STATE_INACTIVE);
846                 }
847         }
848
849         return ret;
850 }
851
852 int CServiceMain::mas_set_current_client_by_appid(const char *appid)
853 {
854         int ret = -1;
855         int prev_selection = mCurrentClientInfo;
856
857         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
858                 if (mClientInfo[loop].used &&
859                         0 < strlen(mClientInfo[loop].appid) &&
860                         0 < strlen(mClientInfo[loop].wakeup_word[0])) {
861                         if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
862                                 mCurrentClientInfo = loop;
863                                 ret = 0;
864                         }
865                 }
866         }
867
868         if (mCurrentClientInfo != prev_selection) {
869                 if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) {
870                         int pid = mas_get_client_pid_by_appid(mClientInfo[prev_selection].appid);
871                         mServiceIpc.active_state_change(pid, MA_ACTIVE_STATE_INACTIVE);
872                 }
873         }
874
875         return ret;
876 }
877
878 int CServiceMain::mas_launch_client_by_appid(const char *appid, CLIENT_LAUNCH_MODE launch_mode)
879 {
880         if (NULL == appid || 0 == strlen(appid)) {
881                 MAS_LOGE("appid invalid, failed launching MA Client");
882                 return -1;
883         }
884
885         if (CLIENT_LAUNCH_MODE_PRELAUNCH == launch_mode) {
886                 if (1 == aul_app_is_running(appid)) {
887                         MAS_LOGE("appid %s is already running, no need for a prelaunch", appid);
888                         return -1;
889                 }
890         }
891
892         bundle *b = NULL;
893         b = bundle_create();
894         if (NULL == b) {
895                 MAS_LOGE("Failed creating bundle for aul operation");
896                 return -1;
897         }
898
899         int result = aul_svc_set_background_launch(b,
900                 (CLIENT_LAUNCH_MODE_PRELAUNCH == launch_mode ? TRUE : FALSE));
901         if (result < AUL_R_OK) {
902                 MAS_LOGE("ERROR : aul_svc_set_background_launch failed. app_id [%s] bundle[%p] result[%d : %s]",
903                         appid, b, result, get_error_message(result));
904         }
905
906         result = aul_launch_app_async(appid, b);
907         if (result < AUL_R_OK) {
908                 MAS_LOGE("ERROR : aul_launch_app_async failed. app_id [%s] bundle[%p] result[%d : %s]",
909                         appid, b, result, get_error_message(result));
910         }
911
912         if (CLIENT_LAUNCH_MODE_ACTIVATION == launch_mode) {
913                 bool found = false;
914                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
915                         if (mClientInfo[loop].used &&
916                                 0 < strlen(mClientInfo[loop].appid)) {
917                                 if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
918                                         mWakeupClientAppId = mClientInfo[loop].appid;
919                                         found = true;
920                                 }
921                         }
922                 }
923                 MAS_LOGD("mWakeupClientAppId : %s, %d", mWakeupClientAppId.c_str(), found);
924         }
925
926         if (b) bundle_free(b);
927         b = NULL;
928
929         return result;
930 }
931
932 int CServiceMain::mas_bring_client_to_foreground(const char* appid)
933 {
934         /* Bring MA client to foreground - is there a better way other than launching? */
935         if (NULL == appid || 0 == strlen(appid)) {
936                 MAS_LOGE("appid invalid, failed launching MA Client");
937                 return -1;
938         }
939
940         bundle *b = NULL;
941         b = bundle_create();
942         if (NULL == b) {
943                 MAS_LOGE("Failed creating bundle for aul operation");
944                 return -1;
945         }
946
947         int result = aul_launch_app(appid, b);
948         if (result < AUL_R_OK) {
949                 MAS_LOGE("ERROR : aul_launch_app failed. app_id [%s] bundle[%p] result[%d : %s]",
950                         appid, b, result, get_error_message(result));
951         }
952
953         if (b) bundle_free(b);
954         b = NULL;
955
956         return result;
957 }
958
959 int CServiceMain::mas_launch_client_by_wakeup_word(const char *wakeup_word)
960 {
961         const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
962         return mas_launch_client_by_appid(appid, CLIENT_LAUNCH_MODE_ACTIVATION);
963 }
964
965 int CServiceMain::mas_prelaunch_default_assistant()
966 {
967         /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */
968         int prelaunch_mode;
969         int res = vconf_get_bool(WAKEUP_SETTINGS_KEY_PRELAUNCH_MODE, &prelaunch_mode);
970         if (0 == res && 0 != prelaunch_mode) {
971                 const char *default_assistant = NULL;
972                 if (0 == mServicePlugin.get_default_assistant(&default_assistant)) {
973                         if (0 == aul_app_is_running(default_assistant)) {
974                                 MAS_LOGD("prelaunching default_assistant_appid : %s", default_assistant);
975                                 mas_launch_client_by_appid(default_assistant, CLIENT_LAUNCH_MODE_PRELAUNCH);
976                         }
977                 }
978         }
979         return 0;
980 }
981
982 int CServiceMain::mas_update_voice_key_support_mode()
983 {
984         /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */
985         bool successful = false;
986         const char *default_assistant = NULL;
987         if (0 == mServicePlugin.get_default_assistant(&default_assistant)) {
988                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
989                         if (mClientInfo[loop].used) {
990                                 if (default_assistant &&
991                                         strncmp(default_assistant, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
992                                         float duration = mClientInfo[loop].voice_key_tap_duration;
993                                         if (0.0f < duration) {
994                                                 mServicePlugin.set_voice_key_tap_duration(duration);
995                                         } else {
996                                                 mServicePlugin.unset_voice_key_tap_duration();
997                                         }
998                                         mServicePlugin.set_voice_key_support_mode(
999                                                 mClientInfo[loop].voice_key_support_mode);
1000                                         successful = true;
1001                                 }
1002                         }
1003                 }
1004         }
1005
1006         if (!successful) {
1007                 mServicePlugin.unset_voice_key_tap_duration();
1008                 mServicePlugin.set_voice_key_support_mode(VOICE_KEY_SUPPORT_MODE_NONE);
1009         }
1010         return 0;
1011 }
1012
1013 ma_preprocessing_allow_mode_e CServiceMain::get_preprocessing_allow_mode(const char* appid)
1014 {
1015         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
1016                 if (appid && mClientInfo[loop].used) {
1017                         if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
1018                                 return mClientInfo[loop].preprocessing_allow_mode;
1019                         }
1020                 }
1021         }
1022         return MA_PREPROCESSING_ALLOW_NONE;
1023 }
1024
1025 /* This might need to be read from settings in the future, but using macro for now */
1026 //#define BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1027
1028 int CServiceMain::mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT event)
1029 {
1030         const char* current_maclient_appid = NULL;
1031         const char* preprocessing_allow_appid = NULL;
1032         if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) {
1033                 current_maclient_appid = mClientInfo[mCurrentClientInfo].appid;
1034                 preprocessing_allow_appid = mClientInfo[mCurrentClientInfo].preprocessing_allow_appid;
1035         }
1036         ma_preprocessing_allow_mode_e mode = get_preprocessing_allow_mode(current_maclient_appid);
1037
1038         switch (event) {
1039                 case PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED:
1040                 {
1041 #ifndef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1042                         /* If there is no need to bring preprocessing assistant to front,
1043                                 current_maclient should always be brought to front */
1044                         mas_bring_client_to_foreground(current_maclient_appid);
1045 #endif
1046                         mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED;
1047                         if (check_preprocessing_assistant_exists()) {
1048                                 if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode ||
1049                                         MA_PREPROCESSING_ALLOW_ALL == mode) {
1050                                         if (is_current_preprocessing_assistant(preprocessing_allow_appid)) {
1051                                                 mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED;
1052                                         }
1053                                 }
1054                         } else {
1055 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1056                                 /* If preprocessing assistant does not exist, there is no way to enable
1057                                         preprocessing assistant, so bring current maclient to front right away */
1058                                 mas_bring_client_to_foreground(current_maclient_appid);
1059 #endif
1060                         }
1061                 }
1062                 break;
1063                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED:
1064                 {
1065                         mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED;
1066                         /* Enable preprocessing mode only if the preprocessing assistant exists */
1067                         if (check_preprocessing_assistant_exists()) {
1068                                 if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode ||
1069                                         MA_PREPROCESSING_ALLOW_ALL == mode) {
1070                                         if (is_current_preprocessing_assistant(preprocessing_allow_appid)) {
1071                                                 mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED;
1072                                         }
1073                                 }
1074                         }
1075                 }
1076                 break;
1077                 case PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED:
1078                 {
1079                         if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED == mCurrentPreprocessingState) {
1080                                 mCurrentPreprocessingState = PREPROCESSING_STATE_PREPROCESSING_UTTERANCE;
1081                         } else if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED == mCurrentPreprocessingState) {
1082                                 /* If preprocessing assistant does not exist, the current_maclient
1083                                         would have been brought to front already on wakeup event */
1084 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1085                                 if (check_preprocessing_assistant_exists()) {
1086                                         mas_bring_client_to_foreground(current_maclient_appid);
1087                                 }
1088 #endif
1089                                 mCurrentPreprocessingState = PREPROCESSING_STATE_NONE;
1090                         }
1091                 }
1092                 break;
1093                 case PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED:
1094                 {
1095                         mCurrentPreprocessingState = PREPROCESSING_STATE_NONE;
1096                         if (check_preprocessing_assistant_exists()) {
1097                                 if (MA_PREPROCESSING_ALLOW_FOLLOW_UP == mode ||
1098                                         MA_PREPROCESSING_ALLOW_ALL == mode) {
1099                                         mCurrentPreprocessingState = PREPROCESSING_STATE_PREPROCESSING_FOLLOW_UP;
1100                                 }
1101                         }
1102                 }
1103                 break;
1104                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED:
1105                 {
1106 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1107                         if (PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED == mCurrentPreprocessingState ||
1108                                 PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED == mCurrentPreprocessingState) {
1109                                 char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
1110                                 MAS_LOGD("preprocessing_assistant_appid : %s", vconf_str);
1111                                 if (vconf_str) {
1112                                         mas_bring_client_to_foreground(vconf_str);
1113                                         free(vconf_str);
1114                                         vconf_str = NULL;
1115                                 }
1116                         }
1117 #endif
1118                         mCurrentPreprocessingState = PREPROCESSING_STATE_NONE;
1119                 }
1120                 break;
1121                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED:
1122                 {
1123 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1124                         if (PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED == mCurrentPreprocessingState ||
1125                                 PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED == mCurrentPreprocessingState) {
1126                                 mas_bring_client_to_foreground(current_maclient_appid);
1127                         }
1128 #endif
1129                         mCurrentPreprocessingState = PREPROCESSING_STATE_NONE;
1130                 }
1131                 break;
1132         }
1133         return 0;
1134 }
1135
1136 int CServiceMain::mas_set_current_service_state(ma_service_state_e state)
1137 {
1138         mCurrentServiceState = state;
1139
1140         ma_client_s *data = NULL;
1141
1142         int count = mClientManager.get_client_num();
1143         int i;
1144
1145         for (i = 0; i < count; i++) {
1146                 int pid = mClientManager.find_client_pid_by_index(i);
1147
1148                 if (-1 != pid) {
1149                         int ret = mServiceIpc.service_state_change(pid, state);
1150                         if (0 != ret) {
1151                                 MAS_LOGE("[ERROR] Fail to set service state change to %d, ret(%d)", pid, ret);
1152                         }
1153                 }
1154         }
1155         return 0;
1156 }
1157
1158 ma_service_state_e CServiceMain::mas_get_current_service_state()
1159 {
1160         return mCurrentServiceState;
1161 }
1162
1163 bool CServiceMain::is_valid_wakeup_engine(const char* appid)
1164 {
1165         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM;loop++) {
1166                 if (mClientInfo[loop].used) {
1167                         LOGD("comparing appid : %s %s", mClientInfo[loop].wakeup_engine, appid);
1168                         if (0 == strncmp(mClientInfo[loop].wakeup_engine, appid, MAX_APPID_LEN)) {
1169                                 return true;
1170                         }
1171                 }
1172         }
1173         return false;
1174 }
1175
1176 int pkg_app_list_cb(const pkgmgrinfo_appinfo_h handle, void *user_data)
1177 {
1178         if (nullptr == g_service_main) return -1;
1179
1180         char *appid = NULL;
1181
1182         int ret = pkgmgrinfo_appinfo_get_appid(handle, &appid);
1183         if (PMINFO_R_OK == ret && NULL != appid) {
1184                 int *result = (int*)user_data;
1185                 if (result) {
1186                         bool exists = g_service_main->is_valid_wakeup_engine(appid);
1187                         if (exists) {
1188                                 *result = 1;
1189                         }
1190                 }
1191         } else {
1192                 LOGE("pkgmgrinfo_appinfo_get_appid failed! error code=%d", ret);
1193         }
1194
1195         return 0;
1196 }
1197
1198 /*
1199 INFO: Package install/update/uninstall scenario
1200 Install and Uninstall are obviously simple.
1201    Install: just INSTALL
1202    Uninstall: just UNINSTALL
1203 Update package (change the source codes and Run As again), there are four scenarios:
1204 1. UPDATE
1205    Source code change
1206 2. UNINSTALL -> INSTALL
1207    This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Check "Enable Project specific settings"
1208    and change Application ID in tizen-manifest.xml file and Run As.
1209 3. UPDATE -> INSTALL
1210    This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Uncheck "Enable Project specific settings"
1211    and change Application ID in tizen-manifest.xml file and Run As.
1212    At UPDATE event, pkgid (package parameter) is invalid...
1213 4. UPDATE
1214    Exceptionally, only UPDATE can be called when Application ID in tizen-manifest.xml file is changed.
1215    At UPDATE event, pkgid (package parameter) is valid, and only appid is changed; the previous appid is invalid.
1216 */
1217 static void _package_manager_event_cb(const char *type, const char *package, package_manager_event_type_e event_type, package_manager_event_state_e event_state, int progress, package_manager_error_e error, void *user_data)
1218 {
1219         CServiceMain* service_main = static_cast<CServiceMain*>(user_data);
1220
1221         int ret = 0;
1222         uid_t uid = getuid();
1223         pkgmgrinfo_pkginfo_h handle = NULL;
1224         static bool in_progress = false;
1225         bool should_exit = false;
1226
1227         if (!package || !type)
1228                 return;
1229
1230         if (PACKAGE_MANAGER_EVENT_TYPE_UPDATE != event_type &&
1231                 PACKAGE_MANAGER_EVENT_TYPE_INSTALL != event_type &&
1232                 PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL != event_type)
1233                 return;
1234
1235         if (PACKAGE_MANAGER_EVENT_STATE_STARTED != event_state &&
1236                 PACKAGE_MANAGER_EVENT_STATE_COMPLETED != event_state)
1237                 return;
1238
1239         bool user = false;
1240         MAS_LOGD("type=%s package=%s event_type=%d event_state=%d progress=%d error=%d",
1241                 type, package, event_type, event_state, progress, error);
1242         ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
1243         if (ret != PMINFO_R_OK || NULL == handle) {
1244                 MAS_LOGW("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", package, ret, getuid());
1245                 /* Try to get in user packages */
1246                 user = true;
1247                 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(package, uid, &handle);
1248                 if (ret != PMINFO_R_OK || NULL == handle) {
1249                         MAS_LOGW("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", package, ret, getuid());
1250                         return;
1251                 }
1252         }
1253
1254         if (user) {
1255                 /* Try to get in user packages */
1256                 pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret, uid);
1257         }  else {
1258                 /* Try to get in global packages */
1259                 pkgmgrinfo_appinfo_get_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret);
1260         }
1261         if (1 == ret) {
1262                 if (PACKAGE_MANAGER_EVENT_STATE_STARTED == event_state) {
1263                         MAS_LOGI("processing PACKAGE_MANAGER_EVENT_STATE_STARTED event : %d", event_type);
1264                         if (false == in_progress) {
1265                                 in_progress = true;
1266                                 if (service_main) {
1267                                         service_main->deinitialize_service_plugin();
1268                                 } else {
1269                                         MAS_LOGE("service_main is NULL");
1270                                 }
1271                         }
1272                 } else if (PACKAGE_MANAGER_EVENT_STATE_COMPLETED == event_state) {
1273                         MAS_LOGI("processing PACKAGE_MANAGER_EVENT_STATE_COMPLETED event : %d", event_type);
1274                         if (false == in_progress) {
1275                                 if (service_main) {
1276                                         service_main->deinitialize_service_plugin();
1277                                 } else {
1278                                         MAS_LOGE("service_main is NULL");
1279                                 }
1280                         }
1281                         /*
1282                         if (service_main) {
1283                                 service_main->initialize_service_plugin();
1284                                 service_main->process_activated_setting();
1285                         } else {
1286                                 MAS_LOGE("service_main is NULL");
1287                         }
1288                         */
1289                         should_exit = true;
1290                         in_progress = false;
1291                 }
1292         }
1293
1294         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1295
1296         if (should_exit) {
1297                 LOGI("Now restarting multi-assistant-service for reloading updated modules");
1298                 service_app_exit();
1299         }
1300
1301         return;
1302 }
1303
1304 bool CServiceMain::app_create(void *data)
1305 {
1306         // Todo: add your code here.
1307         MAS_LOGD("[Enter] Service app create");
1308
1309         g_service_main = this;
1310
1311         mClientManager.set_application_manager(&mApplicationManager);
1312
1313         mServiceIpc.set_client_manager(&mClientManager);
1314         mServiceIpc.set_service_ipc_observer(this);
1315
1316         mServicePlugin.set_service_ipc(&mServiceIpc);
1317         mServicePlugin.set_service_main(this);
1318
1319         int ret = mServiceIpc.open_connection();
1320         if (0 != ret) {
1321                 MAS_LOGE("[ERROR] Fail to open connection");
1322         }
1323
1324         initialize_service_plugin();
1325
1326         process_activated_setting();
1327
1328         mas_prelaunch_default_assistant();
1329         mas_update_voice_key_support_mode();
1330
1331         /* For the case of preprocessing assistant, it always have to be launched beforehand */
1332         char *vconf_str;
1333         vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
1334         if (vconf_str) {
1335                 MAS_LOGD("prelaunching preprocessing_assistant_appid : %s", vconf_str);
1336                 mas_launch_client_by_appid(vconf_str, CLIENT_LAUNCH_MODE_PRELAUNCH);
1337                 free(vconf_str);
1338                 vconf_str = NULL;
1339         }
1340
1341         if (!mPackageManagerHandle) {
1342                 int ret = package_manager_create(&mPackageManagerHandle);
1343                 if (ret == PACKAGE_MANAGER_ERROR_NONE) {
1344                         ret = package_manager_set_event_cb(mPackageManagerHandle, _package_manager_event_cb, this);
1345                         if (ret == PACKAGE_MANAGER_ERROR_NONE) {
1346                                 LOGD("package_manager_set_event_cb succeeded.");
1347                         } else {
1348                                 LOGE("package_manager_set_event_cb failed(%d)", ret);
1349                         }
1350                 } else {
1351                         LOGE("package_manager_create failed(%d)", ret);
1352                 }
1353         }
1354
1355         return true;
1356 }
1357
1358 void CServiceMain::app_terminate(void *data)
1359 {
1360         MAS_LOGI("[ENTER]");
1361         if (mPackageManagerHandle) {
1362                 package_manager_unset_event_cb(mPackageManagerHandle);
1363                 package_manager_destroy(mPackageManagerHandle);
1364                 mPackageManagerHandle = NULL;
1365         }
1366
1367         deinitialize_service_plugin();
1368
1369         vconf_ignore_key_changed(MULTI_ASSISTANT_SETTINGS_ACTIVATED, active_state_changed_cb);
1370
1371         int ret = mServiceIpc.close_connection();
1372         if (0 != ret) {
1373                 MAS_LOGE("[ERROR] Fail to close connection");
1374         }
1375
1376         g_service_main = nullptr;
1377
1378         MAS_LOGI("[END]");
1379         return;
1380 }
1381
1382 int CServiceMain::on_initialize(int pid) {
1383         MAS_LOGD("[Enter] pid(%d)", pid);
1384
1385         char appid[MAX_APPID_LEN] = {'\0', };
1386         if (AUL_R_OK == aul_app_get_appid_bypid(pid, appid, sizeof(appid))) {
1387                 appid[MAX_APPID_LEN - 1] = '\0';
1388
1389                 MAS_LOGD("appid for pid %d is : %s", pid, (appid ? appid : "Unknown"));
1390
1391                 /* Remove existing client that has same appid, if there's any */
1392                 mClientManager.destroy_client_by_appid(appid);
1393
1394                 /* And remove a client that has same pid also */
1395                 mClientManager.destroy_client_by_pid(pid);
1396
1397                 mClientManager.create_client(pid, appid);
1398
1399                 const char *current_maclient_appid = NULL;
1400                 if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) {
1401                         current_maclient_appid = mClientInfo[mCurrentClientInfo].appid;
1402                 }
1403
1404                 mas_client_send_preprocessing_information(pid);
1405                 if (MA_VOICE_KEY_STATUS_PRESSED == mLastVoiceKeyStatus) {
1406                         mas_client_send_voice_key_status_change(pid, mLastVoiceKeyStatus);
1407                 }
1408                 if (current_maclient_appid && 0 == strncmp(current_maclient_appid, appid, MAX_APPID_LEN)) {
1409                         MAS_LOGD("MA client with current maclient appid connected!");
1410
1411                         if (0 == mWakeupClientAppId.compare(appid)) {
1412                                 mWakeupClientAppId.clear();
1413                                 mServiceIpc.active_state_change(pid, MA_ACTIVE_STATE_ACTIVE);
1414                                 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED);
1415                         } else {
1416                                 MAS_LOGE("[ERROR] mWakeupClientAppId and appid differ : %s %s",
1417                                         mWakeupClientAppId.c_str(), appid);
1418                         }
1419                 } else {
1420                         MAS_LOGD("MA client connected, but its appid does not match with current maclient");
1421                 }
1422
1423                 mServiceIpc.service_state_change(pid, mas_get_current_service_state());
1424         } else {
1425                 MAS_LOGE("[ERROR] Fail to retrieve appid");
1426         }
1427
1428         return 0;
1429 }
1430
1431 int CServiceMain::on_deinitialize(int pid) {
1432         MAS_LOGD("[Enter] pid(%d)", pid);
1433         mClientManager.destroy_client_by_pid(pid);
1434         return 0;
1435 }
1436
1437 int CServiceMain::on_get_audio_format(int pid, int& rate, int& channel, int& audio_type) {
1438         int main_rate, main_channel, main_audio_type;
1439         int ret = mas_client_get_audio_format(pid,
1440                 &main_rate, &main_channel, &main_audio_type);
1441         rate = main_rate;
1442         channel = main_channel;
1443         audio_type = main_audio_type;
1444         return ret;
1445 }
1446
1447 int CServiceMain::on_get_audio_source_type(int pid, std::string& type) {
1448         char *main_type = nullptr;
1449         int ret = mas_client_get_audio_source_type(pid, &main_type);
1450         if (0 == ret && main_type) {
1451                 type = std::string{main_type};
1452         }
1453         return ret;
1454 }
1455
1456 int CServiceMain::on_send_asr_result(int pid, int event, std::string asr_result) {
1457         return mas_client_send_asr_result(pid, event, asr_result.c_str());
1458 }
1459
1460 int CServiceMain::on_send_result(int pid, std::string display_text,
1461         std::string utterance_text, std::string result_json) {
1462         return mas_client_send_result(pid,
1463                 display_text.c_str(), utterance_text.c_str(), result_json.c_str());
1464 }
1465
1466 int CServiceMain::on_send_recognition_result(int pid, int result) {
1467         return mas_client_send_recognition_result(pid, result);
1468 }
1469
1470 int CServiceMain::on_start_streaming_audio_data(int pid, int type) {
1471         return mas_client_start_streaming_audio_data(pid, type);
1472 }
1473
1474 int CServiceMain::on_stop_streaming_audio_data(int pid, int type) {
1475         return mas_client_stop_streaming_audio_data(pid, type);
1476 }
1477
1478 int CServiceMain::on_update_voice_feedback_state(int pid, int state) {
1479         return mas_client_update_voice_feedback_state(pid, state);
1480 }
1481
1482 int CServiceMain::on_send_assistant_specific_command(int pid, std::string command) {
1483         return mas_client_set_assistant_specific_command(pid, command.c_str());
1484 }
1485
1486 int CServiceMain::on_set_background_volume(int pid, double ratio) {
1487         return mas_client_set_background_volume(pid, ratio);
1488 }
1489
1490 int CServiceMain::on_set_preprocessing_allow_mode(int pid, int mode, std::string app_id) {
1491         return mas_client_set_preprocessing_allow_mode(pid,
1492                 static_cast<ma_preprocessing_allow_mode_e>(mode), app_id.c_str());
1493 }
1494
1495 int CServiceMain::on_send_preprocessing_result(int pid, int result) {
1496         return mas_client_send_preprocessing_result(pid, result);
1497 }
1498
1499 int CServiceMain::on_set_wake_word_audio_require_flag(int pid, int require) {
1500         return mas_client_set_wake_word_audio_require_flag(pid, require);
1501 }
1502
1503 int CServiceMain::on_set_assistant_language(int pid, std::string language) {
1504         return mas_client_set_assistant_language(pid, language.c_str());
1505 }
1506
1507 int CServiceMain::on_add_wake_word(int pid, std::string wake_word, std::string language) {
1508         return mas_client_add_wake_word(pid, wake_word.c_str(), language.c_str());
1509 }
1510
1511 int CServiceMain::on_remove_wake_word(int pid, std::string wake_word, std::string language) {
1512         return mas_client_remove_wake_word(pid, wake_word.c_str(), language.c_str());
1513 }
1514
1515 int CServiceMain::on_ui_initialize(int pid)
1516 {
1517         return mas_ui_client_initialize(pid);
1518 }
1519
1520 int CServiceMain::on_ui_deinitialize(int pid)
1521 {
1522         return mas_ui_client_deinitialize(pid);
1523 }
1524
1525 int CServiceMain::on_ui_change_assistant(std::string app_id)
1526 {
1527         return mas_ui_client_change_assistant(app_id.c_str());
1528 }