Merge with Tizen 2.3
[platform/core/uifw/tts.git] / server / ttsd_dbus.c
1 /*
2 *  Copyright (c) 2011-2014 Samsung Electronics Co., Ltd All Rights Reserved 
3 *  Licensed under the Apache License, Version 2.0 (the "License");
4 *  you may not use this file except in compliance with the License.
5 *  You may obtain a copy of the License at
6 *  http://www.apache.org/licenses/LICENSE-2.0
7 *  Unless required by applicable law or agreed to in writing, software
8 *  distributed under the License is distributed on an "AS IS" BASIS,
9 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 *  See the License for the specific language governing permissions and
11 *  limitations under the License.
12 */
13
14 #include <dbus/dbus.h>
15 #include <dirent.h>
16 #include <dlfcn.h>
17 #include <Ecore.h>
18
19 #include "tts_config_mgr.h"
20 #include "ttsd_main.h"
21 #include "ttsd_dbus_server.h"
22 #include "ttsd_dbus.h"
23 #include "ttsd_server.h"
24
25
26 static DBusConnection* g_conn;
27
28 static int g_waiting_time = 3000;
29
30 static char *g_service_name;
31 static char *g_service_object;
32 static char *g_service_interface;
33
34 const char* __ttsd_get_error_code(ttsd_error_e err)
35 {
36         switch(err) {
37         case TTSD_ERROR_NONE:                   return "TTS_ERROR_NONE";
38         case TTSD_ERROR_OUT_OF_MEMORY:          return "TTS_ERROR_OUT_OF_MEMORY";
39         case TTSD_ERROR_IO_ERROR:               return "TTS_ERROR_IO_ERROR";
40         case TTSD_ERROR_INVALID_PARAMETER:      return "TTS_ERROR_INVALID_PARAMETER";
41         case TTSD_ERROR_OUT_OF_NETWORK:         return "TTS_ERROR_OUT_OF_NETWORK";
42         case TTSD_ERROR_INVALID_STATE:          return "TTS_ERROR_INVALID_STATE";
43         case TTSD_ERROR_INVALID_VOICE:          return "TTS_ERROR_INVALID_VOICE";
44         case TTSD_ERROR_ENGINE_NOT_FOUND:       return "TTS_ERROR_ENGINE_NOT_FOUND";
45         case TTSD_ERROR_TIMED_OUT:              return "TTS_ERROR_TIMED_OUT";
46         case TTSD_ERROR_OPERATION_FAILED:       return "TTS_ERROR_OPERATION_FAILED";
47         case TTSD_ERROR_AUDIO_POLICY_BLOCKED:   return "TTS_ERROR_AUDIO_POLICY_BLOCKED";
48         default:
49                 return "Invalid error code";
50         }
51
52         return NULL;
53 }
54
55 int ttsdc_send_hello(int pid, int uid)
56 {
57         if (NULL == g_conn) { 
58                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Dbus connection is not available" );
59                 return -1;
60         }
61
62         char service_name[64];
63         memset(service_name, 0, 64);
64         snprintf(service_name, 64, "%s%d", TTS_CLIENT_SERVICE_NAME, pid);
65
66         char target_if_name[64];
67         snprintf(target_if_name, sizeof(target_if_name), "%s%d", TTS_CLIENT_SERVICE_INTERFACE, pid);
68
69         DBusMessage* msg;
70
71         /* create a message & check for errors */
72         msg = dbus_message_new_method_call(
73                 service_name, 
74                 TTS_CLIENT_SERVICE_OBJECT_PATH, 
75                 target_if_name, 
76                 TTSD_METHOD_HELLO);
77
78         if (NULL == msg) { 
79                 SECURE_SLOG(LOG_ERROR, get_tag(), "<<<< [Dbus ERROR] Fail to create hello message : uid(%d)", uid); 
80                 return -1;
81         } else {
82                 SECURE_SLOG(LOG_DEBUG, get_tag(), "<<<< [Dbus] Send hello message : uid(%d)", uid);
83         }
84
85         dbus_message_append_args(msg, DBUS_TYPE_INT32, &uid, DBUS_TYPE_INVALID);
86
87         DBusError err;
88         dbus_error_init(&err);
89
90         DBusMessage* result_msg;
91         int result = -1;
92
93         result_msg = dbus_connection_send_with_reply_and_block(g_conn, msg, g_waiting_time, &err);
94         dbus_message_unref(msg);
95         if (dbus_error_is_set(&err)) {
96                 SLOG(LOG_ERROR, get_tag(), "[ERROR] Send error (%s)", err.message);
97                 dbus_error_free(&err);
98         }
99
100         if (NULL != result_msg) {
101                 dbus_message_get_args(result_msg, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
102
103                 if (dbus_error_is_set(&err)) { 
104                         SLOG(LOG_ERROR, get_tag(), ">>>> [Dbus] Get arguments error (%s)", err.message);
105                         dbus_error_free(&err); 
106                         result = -1;
107                 }
108
109                 dbus_message_unref(result_msg);
110         } else {
111                 SLOG(LOG_DEBUG, get_tag(), ">>>> [Dbus] Result message is NULL. Client is not available");
112                 result = 0;
113         }
114
115         return result;
116 }
117
118 int ttsdc_send_message(int pid, int uid, int data, const char *method)
119 {
120         char* send_filename;
121         send_filename = tts_config_get_message_path((int)ttsd_get_mode(), pid);
122
123         if (NULL == send_filename) {
124                 SLOG(LOG_ERROR, get_tag(), "[Message ERROR] Fail to get message file path");
125                 return -1;
126         }
127
128         FILE* fp;
129         fp = fopen(send_filename, "a+");
130
131         if (NULL != send_filename) {
132                 free(send_filename);
133         }
134
135         if (NULL == fp) {
136                 SLOG(LOG_ERROR, get_tag(), "[File message ERROR] Fail to open message file");
137                 return -1;
138         }
139         SECURE_SLOG(LOG_DEBUG, get_tag(), "[File message] Write send file - %s, uid=%d, send_data=%d", method, uid, data);
140
141         fprintf(fp, "%s %d %d\n", method, uid, data);
142
143         fclose(fp);
144
145         return 0;
146 }
147
148 int ttsdc_send_utt_start_message(int pid, int uid, int uttid)
149 {
150         return ttsdc_send_message(pid, uid, uttid, TTSD_METHOD_UTTERANCE_STARTED);
151 }
152
153 int ttsdc_send_utt_finish_message(int pid, int uid, int uttid) 
154 {
155         return ttsdc_send_message(pid, uid, uttid, TTSD_METHOD_UTTERANCE_COMPLETED);
156 }
157
158 int ttsdc_send_set_state_message(int pid, int uid, int state)
159 {
160         return ttsdc_send_message(pid, uid, state, TTSD_METHOD_SET_STATE);
161 }
162
163 int ttsdc_send_error_message(int pid, int uid, int uttid, int reason)
164 {
165         if (NULL == g_conn) { 
166                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Dbus connection is not available" );
167                 return -1;
168         }
169
170         char service_name[64];
171         memset(service_name, 0, 64);
172         snprintf(service_name, 64, "%s%d", TTS_CLIENT_SERVICE_NAME, pid);
173
174         char target_if_name[128];
175         snprintf(target_if_name, sizeof(target_if_name), "%s%d", TTS_CLIENT_SERVICE_INTERFACE, pid);
176
177         DBusMessage* msg;
178
179         msg = dbus_message_new_method_call(
180                 service_name, 
181                 TTS_CLIENT_SERVICE_OBJECT_PATH, 
182                 target_if_name, 
183                 TTSD_METHOD_ERROR);
184
185         if (NULL == msg) { 
186                 SECURE_SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail to create error message : uid(%d)", uid); 
187                 return -1;
188         }
189
190         dbus_message_append_args( msg, 
191                 DBUS_TYPE_INT32, &uid, 
192                 DBUS_TYPE_INT32, &uttid, 
193                 DBUS_TYPE_INT32, &reason, 
194                 DBUS_TYPE_INVALID);
195         
196         if (!dbus_connection_send(g_conn, msg, NULL)) {
197                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] <<<< error message : Out Of Memory !"); 
198         } else {
199                 SECURE_SLOG(LOG_DEBUG, get_tag(), "<<<< Send error signal : uid(%d), reason(%s), uttid(%d)", 
200                         uid, __ttsd_get_error_code(reason), uttid);
201                 dbus_connection_flush(g_conn);
202         }
203
204         dbus_message_unref(msg);
205
206         return 0;
207 }
208
209 static Eina_Bool listener_event_callback(void* data, Ecore_Fd_Handler *fd_handler)
210 {
211         DBusConnection* conn = (DBusConnection*)data;
212
213         if (NULL == conn)       return ECORE_CALLBACK_RENEW;
214
215         dbus_connection_read_write_dispatch(conn, 50);
216
217         DBusMessage* msg = NULL;
218         msg = dbus_connection_pop_message(conn);
219
220         if (true != dbus_connection_get_is_connected(conn)) {
221                 SLOG(LOG_ERROR, get_tag(), "[ERROR] Connection is disconnected");
222                 return ECORE_CALLBACK_RENEW;
223         }
224
225         /* loop again if we haven't read a message */
226         if (NULL == msg) {
227                 return ECORE_CALLBACK_RENEW;
228         }
229
230         /* client event */
231         if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_HELLO)) {
232                 ttsd_dbus_server_hello(conn, msg);
233
234         } else if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_INITIALIZE)) {
235                 ttsd_dbus_server_initialize(conn, msg);
236         
237         } else if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_FINALIZE)) {
238                 ttsd_dbus_server_finalize(conn, msg);
239         
240         } else if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_GET_SUPPORT_VOICES)) {
241                 ttsd_dbus_server_get_support_voices(conn, msg);
242
243         } else if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_GET_CURRENT_VOICE)) {
244                 ttsd_dbus_server_get_current_voice(conn, msg);
245
246         } else if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_ADD_QUEUE)) {
247                 ttsd_dbus_server_add_text(conn, msg);
248
249         } else if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_PLAY)) {
250                 ttsd_dbus_server_play(conn, msg);
251         
252         } else if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_STOP)) {
253                 ttsd_dbus_server_stop(conn, msg);
254
255         } else if (dbus_message_is_method_call(msg, g_service_interface, TTS_METHOD_PAUSE)) {
256                 ttsd_dbus_server_pause(conn, msg);
257
258         } else {
259                 /* Invalid method */
260         }
261
262         /* free the message */
263         dbus_message_unref(msg);
264
265         return ECORE_CALLBACK_RENEW;
266 }
267
268 int ttsd_dbus_open_connection()
269 {
270         DBusError err;
271         dbus_error_init(&err);
272
273         int ret;
274
275         /* connect to the bus and check for errors */
276         g_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
277
278         if (dbus_error_is_set(&err)) { 
279                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail dbus_bus_get : %s", err.message);
280                 dbus_error_free(&err); 
281         }
282
283         if (NULL == g_conn) { 
284                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail to get dbus connection" );
285                 return -1;
286         }
287
288         if (TTSD_MODE_SCREEN_READER == ttsd_get_mode()) {
289                 g_service_name = (char*)calloc(strlen(TTS_SR_SERVER_SERVICE_NAME) + 1, sizeof(char));
290                 g_service_object = (char*)calloc(strlen(TTS_SR_SERVER_SERVICE_OBJECT_PATH) + 1, sizeof(char));
291                 g_service_interface = (char*)calloc(strlen(TTS_SR_SERVER_SERVICE_INTERFACE) + 1, sizeof(char));
292
293                 snprintf(g_service_name, strlen(TTS_SR_SERVER_SERVICE_NAME) + 1, "%s", TTS_SR_SERVER_SERVICE_NAME);
294                 snprintf(g_service_object, strlen(TTS_SR_SERVER_SERVICE_OBJECT_PATH) + 1, "%s", TTS_SR_SERVER_SERVICE_OBJECT_PATH);
295                 snprintf(g_service_interface, strlen(TTS_SR_SERVER_SERVICE_INTERFACE) + 1, "%s", TTS_SR_SERVER_SERVICE_INTERFACE);
296         } else if (TTSD_MODE_NOTIFICATION == ttsd_get_mode()) {
297                 g_service_name = (char*)calloc(strlen(TTS_NOTI_SERVER_SERVICE_NAME) + 1, sizeof(char));
298                 g_service_object = (char*)calloc(strlen(TTS_NOTI_SERVER_SERVICE_OBJECT_PATH) + 1, sizeof(char));
299                 g_service_interface = (char*)calloc(strlen(TTS_NOTI_SERVER_SERVICE_INTERFACE) + 1, sizeof(char));
300
301                 snprintf(g_service_name, strlen(TTS_NOTI_SERVER_SERVICE_NAME) + 1, "%s", TTS_NOTI_SERVER_SERVICE_NAME);
302                 snprintf(g_service_object, strlen(TTS_NOTI_SERVER_SERVICE_OBJECT_PATH) + 1, "%s", TTS_NOTI_SERVER_SERVICE_OBJECT_PATH);
303                 snprintf(g_service_interface, strlen(TTS_NOTI_SERVER_SERVICE_INTERFACE) + 1, "%s", TTS_NOTI_SERVER_SERVICE_INTERFACE);
304         } else {
305                 g_service_name = (char*)calloc(strlen(TTS_SERVER_SERVICE_NAME) + 1, sizeof(char));
306                 g_service_object = (char*)calloc(strlen(TTS_SERVER_SERVICE_OBJECT_PATH) + 1, sizeof(char));
307                 g_service_interface = (char*)calloc(strlen(TTS_SERVER_SERVICE_INTERFACE) + 1, sizeof(char));
308
309                 snprintf(g_service_name, strlen(TTS_SERVER_SERVICE_NAME) + 1, "%s", TTS_SERVER_SERVICE_NAME);
310                 snprintf(g_service_object, strlen(TTS_SERVER_SERVICE_OBJECT_PATH) + 1, "%s", TTS_SERVER_SERVICE_OBJECT_PATH);
311                 snprintf(g_service_interface, strlen(TTS_SERVER_SERVICE_INTERFACE)+ 1, "%s", TTS_SERVER_SERVICE_INTERFACE);
312         }
313
314         /* request our name on the bus and check for errors */
315         ret = dbus_bus_request_name(g_conn, g_service_name, DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
316
317         if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
318                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail to be primary owner");
319                 return -1;
320         }
321
322         if (dbus_error_is_set(&err)) { 
323                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail to request dbus name : %s", err.message);
324                 dbus_error_free(&err); 
325
326                 return -1;
327         }
328
329         /* add a rule for getting signal */
330         char rule[128];
331         snprintf(rule, 128, "type='signal',interface='%s'", g_service_interface);
332
333         /* add a rule for which messages we want to see */
334         dbus_bus_add_match(g_conn, rule, &err); /* see signals from the given interface */
335         dbus_connection_flush(g_conn);
336
337         if (dbus_error_is_set(&err)) { 
338                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] dbus_bus_add_match() : %s", err.message);
339                 return -1; 
340         }
341
342         int fd = 0;
343         dbus_connection_get_unix_fd(g_conn, &fd);
344
345         Ecore_Fd_Handler* fd_handler = NULL;
346         fd_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, (Ecore_Fd_Cb)listener_event_callback, g_conn, NULL, NULL);
347         if (NULL == fd_handler) {
348                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] Fail to get fd handler");
349                 return -1;
350         }
351
352         return 0;
353 }
354
355 int ttsd_dbus_close_connection()
356 {
357         DBusError err;
358         dbus_error_init(&err);
359
360         dbus_bus_release_name (g_conn, g_service_name, &err);
361
362         if (dbus_error_is_set(&err)) {
363                 SLOG(LOG_ERROR, get_tag(), "[Dbus ERROR] dbus_bus_release_name() : %s", err.message); 
364                 dbus_error_free(&err); 
365                 return -1;
366         }
367
368         if (NULL != g_service_name)     free(g_service_name);
369         if (NULL != g_service_object)   free(g_service_object);
370         if (NULL != g_service_interface)free(g_service_interface);
371
372         return 0;
373 }
374
375 int ttsd_file_msg_open_connection(int pid)
376 {
377         /* Make file for Inotify */
378         char* send_filename;
379         send_filename = tts_config_get_message_path((int)ttsd_get_mode(), pid);
380
381         if (NULL == send_filename) {
382                 SLOG(LOG_ERROR, get_tag(), "[Message ERROR] Fail to get message file path");
383                 return -1;
384         }
385
386         FILE* fp;
387         fp = fopen(send_filename, "a+");
388         if (NULL == fp) {
389                 SLOG(LOG_ERROR, get_tag(), "[File message ERROR] Fail to make message file");
390                 if (NULL != send_filename)      free(send_filename);
391                 return -1;
392         }
393         fclose(fp);
394
395         if (NULL != send_filename)      free(send_filename);
396         return 0;
397 }
398
399 int ttsd_file_msg_close_connection(int pid)
400 {
401         /* delete inotify file */
402         char* path = NULL;
403         path = tts_config_get_message_path((int)ttsd_get_mode(), pid);
404
405         if (NULL == path) {
406                 SLOG(LOG_ERROR, get_tag(), "[Message ERROR] Fail to get message file path");
407                 return -1;
408         }
409
410         if (0 != remove(path)) {
411                 SLOG(LOG_WARN, get_tag(), "[File message WARN] Fail to remove message file");
412         }
413
414         if (NULL != path)       free(path);
415         return 0;
416 }
417
418 int ttsd_file_clean_up()
419 {
420         SLOG(LOG_DEBUG, get_tag(), "== Old message file clean up == ");
421
422         DIR *dp = NULL;
423         int ret = -1;
424         struct dirent entry;
425         struct dirent *dirp = NULL;
426
427         dp = opendir(MESSAGE_FILE_PATH_ROOT);
428         if (dp == NULL) {
429                 SLOG(LOG_ERROR, get_tag(), "[File message WARN] Fail to open path : %s", MESSAGE_FILE_PATH_ROOT);
430                 return -1;
431         }
432
433         char prefix[36] = {0, };
434         char remove_path[256] = {0, };
435
436         switch(ttsd_get_mode()) {
437         case TTSD_MODE_DEFAULT:         snprintf(prefix, 36, "%s", MESSAGE_FILE_PREFIX_DEFAULT);                break;
438         case TTSD_MODE_NOTIFICATION:    snprintf(prefix, 36, "%s", MESSAGE_FILE_PREFIX_NOTIFICATION);   break;
439         case TTSD_MODE_SCREEN_READER:   snprintf(prefix, 36, "%s", MESSAGE_FILE_PREFIX_SCREEN_READER);  break;
440         default:
441                 SLOG(LOG_ERROR, get_tag(), "[File ERROR] Fail to get mode : %d", ttsd_get_mode());
442                 closedir(dp);
443                 return -1;
444         }
445
446         do {
447                 ret = readdir_r(dp, &entry, &dirp);
448                 if (0 != ret) {
449                         SLOG(LOG_ERROR, get_tag(), "[File ERROR] Fail to read directory");
450                         break;
451                 }
452
453                 if (NULL != dirp) {
454                         if (!strncmp(prefix, dirp->d_name, strlen(prefix))) {
455                                 memset(remove_path, 0, 256);
456                                 snprintf(remove_path, 256, "%s%s", MESSAGE_FILE_PATH_ROOT, dirp->d_name);
457
458                                 /* Clean up code */
459                                 if (0 != remove(remove_path)) {
460                                         SLOG(LOG_WARN, get_tag(), "[File message WARN] Fail to remove message file : %s", remove_path);
461                                 } else {
462                                         SLOG(LOG_DEBUG, get_tag(), "[File message] Remove message file : %s", remove_path);
463                                 }
464                         }
465                 }
466         } while (NULL != dirp);
467
468         closedir(dp);
469
470         return 0;
471 }