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