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