packaging: bumped version, updated changelog.
[profile/ivi/speech-recognition.git] / src / daemon / daemon.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *   * Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *   * Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *   * Neither the name of Intel Corporation nor the names of its contributors
14  *     may be used to endorse or promote products derived from this software
15  *     without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdio.h>
31
32 #include <murphy/common/macros.h>
33 #include <murphy/common/mm.h>
34 #include <murphy/common/log.h>
35 #include <murphy/common/utils.h>
36
37 #include <glib-object.h>
38
39 #include "srs/daemon/context.h"
40 #include "srs/daemon/config.h"
41 #include "srs/daemon/resctl.h"
42 #include "srs/daemon/plugin.h"
43 #include "srs/daemon/client.h"
44 #include "srs/daemon/recognizer.h"
45 #include "srs/daemon/pulse.h"
46
47 static void cleanup_mainloop(srs_context_t *srs);
48 static void resctl_state_change(srs_resctl_event_t *e, void *user_data);
49
50 static void cleanup_context(srs_context_t *srs)
51 {
52     if (srs != NULL) {
53         srs_resctl_disconnect(srs);
54         srs_pulse_cleanup(srs->pulse);
55         cleanup_mainloop(srs);
56
57         /*
58          * XXX TODO: should purge recognizers, disambiguators, synthesizers...
59          */
60
61         mrp_free(srs);
62     }
63 }
64
65
66 static srs_context_t *create_context(void)
67 {
68     srs_context_t *srs = mrp_allocz(sizeof(*srs));
69
70     if (srs != NULL) {
71         mrp_list_init(&srs->clients);
72         mrp_list_init(&srs->plugins);
73         mrp_list_init(&srs->recognizers);
74         mrp_list_init(&srs->disambiguators);
75     }
76
77     return srs;
78 }
79
80
81 static void setup_logging(srs_context_t *srs)
82 {
83     const char *target;
84
85     target = mrp_log_parse_target(srs->log_target);
86
87     if (target != NULL)
88         mrp_log_set_target(target);
89     else
90         mrp_log_error("invalid log target '%s'", srs->log_target);
91 }
92
93
94 static void daemonize(srs_context_t *srs)
95 {
96     if (!srs->foreground) {
97         mrp_log_info("Switching to daemon mode.");
98
99         if (!mrp_daemonize("/", "/dev/null", "/dev/null")) {
100             mrp_log_error("Failed to daemonize.");
101             exit(1);
102         }
103     }
104 }
105
106
107 static void create_mainloop(srs_context_t *srs)
108 {
109     if (srs_config_get_bool(srs->settings, "gmainloop", FALSE)) {
110         mrp_log_info("Configured to run with glib mainloop.");
111
112 #ifndef GLIB_VERSION_2_36
113         g_type_init();
114 #endif
115         srs->gl = g_main_loop_new(NULL, FALSE);
116
117         if (srs->gl == NULL) {
118             mrp_log_error("Failed to create GMainLoop.");
119             exit(1);
120         }
121     }
122     else
123         mrp_log_info("Configured to run with native PA mainloop.");
124
125     if (srs->gl == NULL) {
126         srs->pl = pa_mainloop_new();
127         srs->pa = pa_mainloop_get_api(srs->pl);
128         srs->ml = mrp_mainloop_pulse_get(srs->pa);
129     }
130     else {
131         srs->pl = pa_glib_mainloop_new(g_main_loop_get_context(srs->gl));
132         srs->pa = pa_glib_mainloop_get_api(srs->pl);
133         srs->ml = mrp_mainloop_glib_get(srs->gl);
134     }
135
136     srs->pulse = srs_pulse_setup(srs->pa, "SRS daemon");
137
138     if (srs->pa != NULL && srs->pulse != NULL && srs->ml != NULL) {
139         if (srs_resctl_connect(srs, resctl_state_change, srs, TRUE))
140             return;
141     }
142
143     cleanup_context(srs);
144     exit(1);
145 }
146
147
148 static void run_mainloop(srs_context_t *srs)
149 {
150     if (srs->gl == NULL)
151         pa_mainloop_run((pa_mainloop *)srs->pl, &srs->exit_status);
152     else
153         g_main_loop_run(srs->gl);
154 }
155
156
157 static void quit_mainloop(srs_context_t *srs, int exit_status)
158 {
159     if (srs != NULL) {
160         if (srs->gl != NULL)
161             g_main_loop_quit(srs->gl);
162         else
163             pa_mainloop_quit((pa_mainloop *)srs->pl, exit_status);
164     }
165     else
166         exit(exit_status);
167 }
168
169
170 static void cleanup_mainloop(srs_context_t *srs)
171 {
172     mrp_mainloop_destroy(srs->ml);
173     srs->ml = NULL;
174
175     if (srs->gl == NULL) {
176         if (srs->pl != NULL)
177             pa_mainloop_free(srs->pl);
178     }
179     else {
180         pa_glib_mainloop_free(srs->pl);
181         g_main_loop_unref(srs->gl);
182         srs->gl = NULL;
183     }
184
185     srs->pl = NULL;
186     srs->pa = NULL;
187 }
188
189
190 static void resctl_state_change(srs_resctl_event_t *e, void *user_data)
191 {
192     srs_context_t *srs = (srs_context_t *)user_data;
193
194     if (e->type != SRS_RESCTL_EVENT_CONNECTION)
195         return;
196
197     if (e->connection.up) {
198         mrp_log_info("Resource control connection is up.");
199         client_create_resources(srs);
200     }
201     else {
202         mrp_log_info("Resource control connection is down.");
203         client_reset_resources(srs);
204     }
205 }
206
207
208 static void sighandler(mrp_sighandler_t *h, int signum, void *user_data)
209 {
210     static int rlog = FALSE;
211
212     srs_context_t *srs = (srs_context_t *)user_data;
213
214     MRP_UNUSED(h);
215
216     switch (signum) {
217     case SIGINT:
218         mrp_log_info("Received SIGINT, exiting...");
219         quit_mainloop(srs, 0);
220         break;
221
222     case SIGTERM:
223         mrp_log_info("Received SIGTERM, exiting...");
224         quit_mainloop(srs, 0);
225         break;
226
227     case SIGUSR2:
228         mrp_log_info("%s resource library logging...",
229                      rlog ? "Disabling" : "Enabling");
230         mrp_res_set_logger(rlog ? NULL : srs->rlog);
231         rlog = !rlog;
232         break;
233     }
234 }
235
236
237 static void setup_signals(srs_context_t *srs)
238 {
239     mrp_add_sighandler(srs->ml, SIGINT , sighandler, srs);
240     mrp_add_sighandler(srs->ml, SIGTERM, sighandler, srs);
241     mrp_add_sighandler(srs->ml, SIGUSR2, sighandler, srs);
242 }
243
244
245 int main(int argc, char *argv[], char *env[])
246 {
247     srs_context_t *srs;
248     srs_cfg_t     *cfg;
249     const char    *srec;
250
251     srs = create_context();
252
253     if (srs != NULL) {
254         srs->rlog = mrp_res_set_logger(NULL);
255
256         config_parse_cmdline(srs, argc, argv, env);
257         setup_logging(srs);
258
259         create_mainloop(srs);
260         setup_signals(srs);
261
262         if (!srs_configure_plugins(srs)) {
263             mrp_log_error("Some plugins failed to configure.");
264             exit(1);
265         }
266
267         if (!srs_start_plugins(srs)) {
268             mrp_log_error("Some plugins failed to start.");
269             exit(1);
270         }
271
272         cfg  = srs->settings;
273         srec = srs_config_get_string(cfg, "daemon.speech-backend", NULL);
274         srs_activate_srec(srs, srec);
275
276         daemonize(srs);
277
278         run_mainloop(srs);
279
280         srs_stop_plugins(srs);
281         srs_destroy_plugins(srs);
282
283         cleanup_context(srs);
284
285         exit(0);
286     }
287     else
288         exit(1);
289 }