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