Send change assistant request to panel on wakeup event
[platform/core/uifw/multi-assistant-service.git] / src / multi_assistant_service.c
1 /*
2  * Copyright 2018  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <tizen.h>
18 #include <service_app.h>
19 #include <app_manager.h>
20 #include <app.h>
21 #include <aul.h>
22 #include <malloc.h>
23 #include <Ecore.h>
24 #include <message_port.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <glib.h>
30
31 #include "multi_assistant_main.h"
32 #include "multi_assistant_service.h"
33 #include "multi_assistant_service_plugin.h"
34 #include "multi_assistant_dbus.h"
35 #include "multi_assistant_config.h"
36
37 static const char *g_current_lang = "en_US";
38 static int g_local_port_id = -1;
39
40 #define MAX_MACLIENT_INFO_NUM 16
41 #define MAX_WAKEUP_WORDS_NUM 4
42 #define MAX_WAKEUP_WORD_LEN 255
43 typedef struct {
44         Eina_Bool used;
45         char appid[MAX_APPID_LEN];
46         char wakeup_word[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN];
47 } ma_client_info;
48
49 static ma_client_info g_maclient_info[MAX_MACLIENT_INFO_NUM];
50
51 typedef struct {
52         int pid;
53         char appid[MAX_APPID_LEN];
54 } ma_client_s;
55
56 static int g_current_maclient_info = 0;
57 static const char *g_wakeup_maclient_appid = NULL;
58
59 /* client list */
60 static GSList* g_client_list = NULL;
61
62 static int g_temp_speech_data_requested = 0;
63 void ma_client_set_temp_speech_data_requested(int val)
64 {
65         g_temp_speech_data_requested = val;
66 }
67 int ma_client_get_temp_speech_data_requested()
68 {
69         return g_temp_speech_data_requested;
70 }
71
72 int ma_client_create(ma_client_s *info)
73 {
74         if (NULL == info) {
75                 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
76                 return -1;
77         }
78
79         ma_client_s* data = NULL;
80
81         data = (ma_client_s*)calloc(1, sizeof(ma_client_s));
82         if (NULL == data) {
83                 MAS_LOGE("[ERROR] Fail to allocate memory"); //LCOV_EXCL_LINE
84                 return -1;// MA_ERROR_OUT_OF_MEMORY;
85         }
86
87         *data = *info;
88
89         g_client_list = g_slist_append(g_client_list, data);
90
91         return 0;
92 }
93
94 int ma_client_destroy(ma_client_s *client)
95 {
96         if (NULL == client) {
97                 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
98                 return -1;// MA_ERROR_OPERATION_FAILED;
99         }
100
101         g_client_list =  g_slist_remove(g_client_list, client);
102
103         free(client);
104         client = NULL;
105
106         return 0;
107 }
108
109 ma_client_s* ma_client_find_by_appid(const char *appid)
110 {
111         if (NULL == appid) {
112                 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
113                 return NULL;
114         }
115
116         ma_client_s *data = NULL;
117
118         int count = g_slist_length(g_client_list);
119         int i;
120
121         for (i = 0; i < count; i++) {
122                 data = g_slist_nth_data(g_client_list, i);
123
124                 if (NULL != data) {
125                         if (0 == strncmp(data->appid, appid, MAX_APPID_LEN)) {
126                                 return data;
127                         }
128                 }
129         }
130
131         MAS_LOGE("[ERROR] client Not found");
132
133         return NULL;
134 }
135
136 ma_client_s* ma_client_find_by_pid(int pid)
137 {
138         ma_client_s *data = NULL;
139
140         int count = g_slist_length(g_client_list);
141         int i;
142
143         for (i = 0; i < count; i++) {
144                 data = g_slist_nth_data(g_client_list, i);
145
146                 if (NULL != data) {
147                         if (data->pid == pid) {
148                                 return data;
149                         }
150                 }
151         }
152
153         MAS_LOGE("[ERROR] client Not found");
154
155         return NULL;
156 }
157
158 int mas_client_initialize(int pid)
159 {
160         MAS_LOGD("[Enter] pid(%d)", pid);
161
162         char appid[MAX_APPID_LEN] = {'\0',};
163         if (AUL_R_OK == aul_app_get_appid_bypid(pid, appid, sizeof(appid))) {
164                 appid[MAX_APPID_LEN - 1] = '\0';
165
166                 MAS_LOGD("appid for pid %d is : %s", pid, (appid ? appid : "Unknown"));
167
168                 /* Remove existing client that has same appid, if there's any */
169                 ma_client_s *old_client = NULL;
170                 old_client = ma_client_find_by_appid(appid);
171                 if (old_client) {
172                         ma_client_destroy(old_client);
173                         old_client = NULL;
174                 }
175
176                 /* And remove a client that has same pid also */
177                 old_client = ma_client_find_by_pid(pid);
178                 if (old_client) {
179                         ma_client_destroy(old_client);
180                         old_client = NULL;
181                 }
182
183                 ma_client_s new_client;
184                 new_client.pid = pid;
185                 strncpy(new_client.appid, appid, MAX_APPID_LEN);
186                 new_client.appid[MAX_APPID_LEN - 1] = '\0';
187                 ma_client_create(&new_client);
188
189                 const char *current_maclient_appid = NULL;
190                 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
191                         current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
192                 }
193
194                 if (current_maclient_appid && 0 == strncmp(current_maclient_appid, appid, MAX_APPID_LEN)) {
195                         MAS_LOGD("MA client with current maclient appid connected!");
196
197                         if (g_wakeup_maclient_appid && strncmp(g_wakeup_maclient_appid, appid, MAX_APPID_LEN) == 0) {
198                                 g_wakeup_maclient_appid = NULL;
199                                 mas_client_request_speech_data(pid);
200                         } else {
201                                 MAS_LOGE("[ERROR] g_wakeup_maclient_appid and appid differ : %s %s",
202                                         (g_wakeup_maclient_appid ? g_wakeup_maclient_appid : "NULL"), appid);
203                         }
204                 } else {
205                         MAS_LOGD("MA client connected, but its appid does not match with current maclient");
206                 }
207         } else {
208                 MAS_LOGE("[ERROR] Fail to retrieve appid");
209         }
210
211         return 0;
212 }
213
214 int mas_client_deinitialize(int pid)
215 {
216         MAS_LOGD("[Enter] pid(%d)", pid);
217         ma_client_s *client = ma_client_find_by_pid(pid);
218         if (client) {
219                 ma_client_destroy(client);
220                 client = NULL;
221         }
222         return 0;
223 }
224
225 int mas_client_get_audio_format(int pid, int* rate, int* channel, int* audio_type)
226 {
227         MAS_LOGD("[Enter] pid(%d)", pid);
228
229         int ret = multi_assistant_service_plugin_get_recording_audio_format(rate, channel, audio_type);
230         if (0 != ret){
231                 MAS_LOGE("[ERROR] Fail to get recording audio format, ret(%d)", ret);
232         }
233
234         return ret;
235 }
236
237 int mas_client_request_speech_data(int pid)
238 {
239         int ret = -1;
240         MAS_LOGD("[Enter] pid(%d)", pid);
241
242         char appid[MAX_APPID_LEN] = {'\0',};
243         if (AUL_R_OK == aul_app_get_appid_bypid(pid, appid, sizeof(appid))) {
244                 appid[MAX_APPID_LEN - 1] = '\0';
245                 const char *current_maclient_appid = NULL;
246                 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
247                         current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
248                 }
249
250                 if (current_maclient_appid && 0 == strncmp(current_maclient_appid, appid, MAX_APPID_LEN)) {
251                         MAS_LOGD("appid %s matches with current MA Client, requesting speech data", appid);
252                         ma_client_set_temp_speech_data_requested(1);
253                         ret = wakeup_service_request_speech_data();
254                         if (0 != ret) {
255                                 MAS_LOGE("[ERROR] Fail to request speech data(%d)", ret);
256                         }
257                 } else {
258                         MAS_LOGE("appid %s does not match with current MA Client", appid);
259                 }
260         }
261
262         return ret;
263 }
264
265 int mas_client_send_asr_result(int pid, int event, char* asr_result)
266 {
267         MAS_LOGD("[Enter] pid(%d), event(%d), asr_result(%s)", pid, event, asr_result);
268         int ret = masc_ui_dbus_send_asr_result(pid, event, asr_result);
269         if (0 != ret){
270                 MAS_LOGE("[ERROR] Fail to send asr result, ret(%d)", ret);
271         }
272
273         // if final event is , launch assistant app which is invoked with wakeup word.
274         /* TO_DO */
275         return ret;
276 }
277
278 Eina_Bool __start_recording(void *data)
279 {
280         (void)data;
281
282         MAS_LOGD("[Enter] Start Recording again");
283         int ret = multi_assistant_service_plugin_start_recording();
284         if (0 != ret) {
285                 MAS_LOGE("[ERROR] Fail to start recording, ret(%d)", ret);
286         }
287         return EINA_FALSE;
288 }
289
290 int mas_client_send_result(int pid, char* display_text, char* utterance_text, char* result_json)
291 {
292         MAS_LOGD("[Enter] pid(%d), display_text(%s), utterance_text(%s), result_json(%s)", pid, display_text, utterance_text, result_json);
293         int ret = masc_ui_dbus_send_result(pid, display_text, utterance_text, result_json);
294         if (0 != ret){
295                 MAS_LOGE("[ERROR] Fail to send result, ret(%d)", ret);
296         }
297
298         ecore_timer_add(0, __start_recording, NULL);
299
300         return ret;
301 }
302
303 int mas_ui_client_initialize(int pid)
304 {
305         MAS_LOGD("[Enter] pid(%d)", pid);
306
307         return 0;
308 }
309
310 int mas_ui_client_deinitialize(int pid)
311 {
312         MAS_LOGD("[Enter] pid(%d)", pid);
313
314         return 0;
315 }
316
317 int mas_ui_client_change_assistant(const char* appid)
318 {
319         MAS_LOGD("[Enter]");
320
321         if (NULL == appid) {
322                 MAS_LOGE("NULL parameter");
323                 return -1;
324         }
325
326         /* We are going to terminate existing clients for testing purpose */
327         int pid = mas_get_current_client_pid();
328         if (pid != -1) {
329                 ma_client_s *client = ma_client_find_by_pid(pid);
330                 if (client && strncmp(appid, client->appid, MAX_APPID_LEN) != 0) {
331                         int ret = aul_terminate_pid(pid);
332                         if (ret != AUL_R_OK) {
333                                 MAS_LOGW("aul_terminate_pid for pid %d returned %d", pid, ret);
334                         }
335                 }
336         }
337
338         mas_set_current_client_by_appid(appid);
339         if (mas_get_client_pid_by_appid(appid) != -1) {
340                 MAS_LOGD("MA Client with appid %s exists, requesting speech data", (appid ? appid : "NULL"));
341                 ma_client_set_temp_speech_data_requested(1);
342                 int ret = wakeup_service_request_speech_data();
343                 if (0 != ret) {
344                         MAS_LOGE("[ERROR] Fail to request speech data(%d)", ret);
345                 }
346         } else {
347                 // Appropriate MA Client not available, trying to launch new one
348                 MAS_LOGD("MA Client with appid %s does not exist, launching client", (appid ? appid : "NULL"));
349
350                 /* The appid parameter might not exist after this function call, so we use appid string in our g_maclient_info */
351                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
352                         if (g_maclient_info[loop].used &&
353                                 0 < strlen(g_maclient_info[loop].appid) &&
354                                 0 < strlen(g_maclient_info[loop].wakeup_word[0])) {
355                                 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
356                                         mas_launch_client_by_appid(g_maclient_info[loop].appid);
357                                 }
358                         }
359                 }
360         }
361
362         return 0;
363 }
364
365 /* for message port - receiver */
366 void __message_port_cb(int local_port_id, const char* remote_app_id, const char* remote_port, bool trusted_remote_port, bundle* message, void* user_data)
367 {
368         char *command = NULL;
369         bundle_get_str(message, "command", &command);
370
371         MAS_LOGD("Message from %s, command: %s", remote_app_id, command);
372
373         if (!strncmp(command, "start", strlen(command))) {
374                 multi_assistant_service_plugin_start_recording();
375         } else if (!strncmp(command, "cancel", strlen(command))) {
376                 multi_assistant_service_plugin_cancel_recording();
377         } else {
378                 MAS_LOGE("[ERROR] command is wrong, command(%s)", command);
379         }
380 }
381
382 static void init_message_port(void)
383 {
384         MAS_LOGD("[Enter] init_message_port");
385
386         g_local_port_id = message_port_register_local_port("multi_assistant_service_message_port", __message_port_cb, NULL);
387         if (g_local_port_id < 0)
388                 MAS_LOGE("[ERROR] message port register error: %d", g_local_port_id);
389         else
390                 MAS_LOGD("[DEBUG] port id: %d", g_local_port_id);
391 }
392
393 static void deinit_message_port(void)
394 {
395         message_port_unregister_local_port(g_local_port_id);
396 }
397
398 int __mas_assistant_info_cb(const char* appid, const char* name,
399                 const char* icon_path, const char* wakeup_list[], int cnt_wakeup,
400                 const char* supported_lang[], int cnt_lang, void* user_data) {
401         MAS_LOGD("__mas_assistant_info_cb called");
402
403         if (NULL == appid) {
404                 MAS_LOGD("app_id NULL, returning");
405                 return -1;
406         }
407
408         int index = -1;
409         int loop = 0;
410         while(-1 == index && loop < MAX_MACLIENT_INFO_NUM) {
411                 if (EINA_FALSE == g_maclient_info[loop].used) {
412                         index = loop;
413                 }
414                 loop++;
415         }
416         if (-1 != index) {
417                 g_maclient_info[index].used = EINA_TRUE;
418                 MAS_LOGD("app_id(%s)", appid);
419                 strncpy(g_maclient_info[index].appid, appid, MAX_APPID_LEN);
420                 g_maclient_info[index].appid[MAX_APPID_LEN - 1] = '\0';
421
422                 for (loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
423                         if (loop < cnt_wakeup && wakeup_list[loop]) {
424                                 MAS_LOGD("wakeup_list(%d)(%s)", loop, wakeup_list[loop]);
425                                 strncpy(g_maclient_info[index].wakeup_word[loop], wakeup_list[loop], MAX_WAKEUP_WORD_LEN);
426                                 g_maclient_info[index].wakeup_word[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0';
427                         } else {
428                                 strncpy(g_maclient_info[index].wakeup_word[loop], "", MAX_WAKEUP_WORD_LEN);
429                         }
430                 }
431         } else {
432                 MAS_LOGD("Couldn't find an empty slot for storing assistant info");
433         }
434
435         MAS_LOGD("__mas_assistant_info_cb end");
436
437         return 0;
438 }
439
440
441 static int init_wakeup(void)
442 {
443         MAS_LOGD("[Enter] init_wakeup ");
444
445         int ret = mas_dbus_open_connection();
446         if (0 != ret) {
447                 MAS_LOGE("[ERROR] Fail to open connection");
448         }
449
450         if (0 != multi_assistant_service_plugin_initialize()) {
451                 MAS_LOGE("Fail to ws intialize");
452                 return -1;
453         }
454
455         if (0 != multi_assistant_service_plugin_set_language(g_current_lang)) {
456                 MAS_LOGE("Fail to ws set language");
457                 return -1;
458         }
459
460         if (0 == mas_config_get_assistant_info(__mas_assistant_info_cb, NULL)) {
461                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
462                         if (g_maclient_info[loop].used &&
463                                 0 < strlen(g_maclient_info[loop].appid)) {
464                                 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
465                                         if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
466                                                 MAS_LOGD("Registering wakeup word %s for app %s",
467                                                         g_maclient_info[loop].wakeup_word[inner_loop], g_maclient_info[loop].appid);
468                                                 if (0 != multi_assistant_service_plugin_set_wakeup_word(
469                                                         "en_US", g_maclient_info[loop].wakeup_word[inner_loop])) {
470                                                         MAS_LOGE("Fail to stt wakeup word");
471                                                 }
472                                         }
473                                 }
474                         }
475                 }
476         } else {
477                 MAS_LOGE("Fail to load assistant info");
478         }
479
480         if (0 != multi_assistant_service_plugin_set_callbacks()) {
481                 MAS_LOGE("Fail to set callbacks");
482                 return -1;
483         }
484
485         if (0 != multi_assistant_service_plugin_start_recording()) {
486                 MAS_LOGE("Fail to ws start recording");
487                 return -1;
488         }
489
490         init_message_port();
491
492         return 0;
493 }
494
495 static void deinit_wakeup(void)
496 {
497         MAS_LOGD("[Enter] deinit_wakeup ");
498
499 /*      if (NULL != g_current_lang) {
500                 free(g_current_lang);
501                 g_current_lang = NULL;
502         }
503 */
504         deinit_message_port();
505
506         int ret = mas_dbus_close_connection();
507         if (0 != ret) {
508                 MAS_LOGE("[ERROR] Fail to close connection");
509         }
510
511         if (0 != multi_assistant_service_plugin_deinitialize()) {
512                 MAS_LOGE("Fail to ws deinitialize");
513         }
514 }
515
516 int mas_get_current_client_pid()
517 {
518         int ret = -1;
519         if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
520                 const char *current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
521                 ma_client_s* client = ma_client_find_by_appid(current_maclient_appid);
522                 if (client) {
523                         ret = client->pid;
524                 }
525         }
526         return ret;
527 }
528
529 int mas_get_client_pid_by_appid(const char *appid)
530 {
531         int ret = -1;
532
533         if (appid) {
534                 ma_client_s *client = NULL;
535                 client = ma_client_find_by_appid(appid);
536                 if (client) {
537                         ret = client->pid;
538                 }
539         }
540
541         return ret;
542 }
543
544 int mas_get_client_pid_by_wakeup_word(const char *wakeup_word)
545 {
546         const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
547         return mas_get_client_pid_by_appid(appid);
548 }
549
550 const char* mas_get_client_appid_by_wakeup_word(const char *wakeup_word)
551 {
552         int loop;
553         const char *appid = NULL;
554
555         if (NULL == wakeup_word) return NULL;
556
557         for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
558                 if (g_maclient_info[loop].used &&
559                         0 < strlen(g_maclient_info[loop].appid)) {
560                         for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
561                                 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
562                                         if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
563                                                 appid = g_maclient_info[loop].appid;
564                                         }
565                                 }
566                         }
567                 }
568         }
569
570         /* Perform extended search, by eliminating blank characters */
571         if (NULL == appid) {
572                 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
573                         if (g_maclient_info[loop].used &&
574                                 0 < strlen(g_maclient_info[loop].appid)) {
575                                 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
576                                         if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
577                                                 char comparand[MAX_WAKEUP_WORD_LEN];
578                                                 int comparand_index = 0;
579                                                 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
580                                                         if (' ' != g_maclient_info[loop].wakeup_word[inner_loop][index]) {
581                                                                 comparand[comparand_index++] = g_maclient_info[loop].wakeup_word[inner_loop][index];
582                                                         }
583                                                 }
584                                                 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
585                                                         appid = g_maclient_info[loop].appid;
586                                                 }
587                                         }
588                                 }
589                         }
590                 }
591         }
592
593         return appid;
594 }
595
596 int mas_set_current_client_by_wakeup_word(const char *wakeup_word)
597 {
598         int loop;
599         int ret = -1;
600
601         for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
602                 if (g_maclient_info[loop].used &&
603                         0 < strlen(g_maclient_info[loop].appid)) {
604                         for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
605                                 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
606                                         if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
607                                                 g_current_maclient_info = loop;
608                                                 ret = 0;
609                                         }
610                                 }
611                         }
612                 }
613         }
614         /* Perform extended search, by eliminating blank characters */
615         if (ret == -1) {
616                 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
617                         if (g_maclient_info[loop].used &&
618                                 0 < strlen(g_maclient_info[loop].appid)) {
619                                 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
620                                         if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
621                                                 char comparand[MAX_WAKEUP_WORD_LEN];
622                                                 int comparand_index = 0;
623                                                 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
624                                                         if (' ' != g_maclient_info[loop].wakeup_word[inner_loop][index]) {
625                                                                 comparand[comparand_index++] = g_maclient_info[loop].wakeup_word[inner_loop][index];
626                                                         }
627                                                 }
628                                                 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
629                                                         g_current_maclient_info = loop;
630                                                         ret = 0;
631                                                 }
632                                         }
633                                 }
634                         }
635                 }
636         }
637
638         return ret;
639 }
640
641 int mas_set_current_client_by_appid(const char *appid)
642 {
643         int ret = -1;
644
645         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
646                 if (g_maclient_info[loop].used &&
647                         0 < strlen(g_maclient_info[loop].appid) &&
648                         0 < strlen(g_maclient_info[loop].wakeup_word[0])) {
649                         if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
650                                 g_current_maclient_info = loop;
651                         }
652                 }
653         }
654         return ret;
655 }
656
657 int mas_launch_client_by_appid(const char *appid)
658 {
659         app_control_h app_control;
660         int ret = 0;
661
662         if (NULL == appid || 0 == strlen(appid)) {
663                 MAS_LOGE("appid invalid, failed launching MA Client");
664                 return -1;
665         }
666
667         ret = app_control_create(&app_control);
668         if (APP_CONTROL_ERROR_NONE != ret) {
669                 MAS_LOGW("app_control_create returned %08x", ret);
670                 return -1;
671         }
672
673         ret = app_control_set_operation(app_control, APP_CONTROL_OPERATION_DEFAULT);
674         if (APP_CONTROL_ERROR_NONE != ret) {
675                 MAS_LOGW("app_control_set_operation returned %08x", ret);
676                 app_control_destroy(app_control);
677                 return -1;
678         }
679
680         /* These extra data key/value should be defined somewhere in multi-assistant framework */
681         ret = app_control_add_extra_data(app_control, "request_speech_data", "true");
682         if (APP_CONTROL_ERROR_NONE != ret) {
683                 MAS_LOGW("app_control_add_extra_data returned %08x", ret);
684                 app_control_destroy(app_control);
685                 return -1;
686         }
687
688         ret = app_control_set_app_id(app_control, appid);
689         if (APP_CONTROL_ERROR_NONE != ret) {
690                 MAS_LOGW("app_control_set_app_id returned %08x", ret);
691                 app_control_destroy(app_control);
692                 return -1;
693         }
694
695         ret = app_control_send_launch_request(app_control, NULL, NULL);
696         if (APP_CONTROL_ERROR_NONE != ret) {
697                 MAS_LOGW ("app_control_send_launch_request returned %08x, app_id=%s", ret, appid);
698         }
699         app_control_destroy (app_control);
700
701         if (APP_CONTROL_ERROR_NONE == ret) {
702                 g_wakeup_maclient_appid = appid;
703                 MAS_LOGD("g_wakeup_maclient_appid : %s", appid);
704         }
705
706         return ret;
707 }
708
709 int mas_launch_client_by_wakeup_word(const char *wakeup_word)
710 {
711         const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
712         return mas_launch_client_by_appid(appid);
713 }
714
715 bool service_app_create(void *data)
716 {
717         // Todo: add your code here.
718
719         MAS_LOGD("[Enter] Service app create");
720
721         if (0 != init_wakeup()) {
722                 MAS_LOGE("Fail to init wakeup service");
723                 return false;
724         }
725
726         return true;
727 }
728
729 void service_app_terminate(void *data)
730 {
731         // Todo: add your code here.
732         deinit_wakeup();
733         return;
734 }
735
736 void service_app_control(app_control_h app_control, void *data)
737 {
738         // Todo: add your code here.
739         return;
740 }
741
742 static void
743 service_app_lang_changed(app_event_info_h event_info, void *user_data)
744 {
745         /*APP_EVENT_LANGUAGE_CHANGED*/
746         return;
747 }
748
749 static void
750 service_app_region_changed(app_event_info_h event_info, void *user_data)
751 {
752         /*APP_EVENT_REGION_FORMAT_CHANGED*/
753 }
754
755 static void
756 service_app_low_battery(app_event_info_h event_info, void *user_data)
757 {
758         /*APP_EVENT_LOW_BATTERY*/
759 }
760
761 static void
762 service_app_low_memory(app_event_info_h event_info, void *user_data)
763 {
764         /*APP_EVENT_LOW_MEMORY*/
765 }
766
767 int main(int argc, char* argv[])
768 {
769         char ad[50] = {0,};
770         service_app_lifecycle_callback_s event_callback;
771         app_event_handler_h handlers[5] = {NULL, };
772
773         event_callback.create = service_app_create;
774         event_callback.terminate = service_app_terminate;
775         event_callback.app_control = service_app_control;
776
777         service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, service_app_low_battery, &ad);
778         service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, service_app_low_memory, &ad);
779         service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, service_app_lang_changed, &ad);
780         service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, service_app_region_changed, &ad);
781
782         return service_app_main(argc, argv, &event_callback, ad);
783 }