packaging: bumped version, updated changelog.
[profile/ivi/speech-recognition.git] / src / daemon / resctl.c
1 /*
2  * Copyright (c) 2012, 2013, 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 "srs/daemon/context.h"
31 #include "srs/daemon/resctl.h"
32
33 #define CONNECT_TIMER (5 * 1000)
34
35 struct srs_resctx_s {
36     srs_context_t         *srs;          /* SRS context */
37     mrp_res_context_t     *ctx;          /* resource context */
38     mrp_list_hook_t        sets;         /* resource sets */
39     srs_resctl_event_cb_t  cb;           /* notification callback */
40     void                  *user_data;    /* opaque notification data */
41     mrp_timer_t           *t;            /* (re)connect timer */
42 };
43
44
45 struct srs_resset_s {
46     srs_resctx_t           *ctx;         /* resource context */
47     mrp_res_resource_set_t *set;         /* resource set */
48     mrp_list_hook_t         hook;        /* to list of resource sets */
49     srs_resctl_event_cb_t   cb;          /* notification callback */
50     void                   *user_data;   /* opaque notification data */
51     char                   *appclass;    /* application class */
52     int                     shared : 1;  /* whether currently shared */
53     mrp_deferred_t         *emul;        /* deferred cb for emulation */
54 };
55
56
57 static void context_event(mrp_res_context_t *rctx, mrp_res_error_t err,
58                           void *user_data);
59 static void set_event(mrp_res_context_t *rctx,
60                       const mrp_res_resource_set_t *rset, void *user_data);
61 static void stop_connect(srs_resctx_t *ctx);
62 static void notify_connect(srs_resctx_t *ctx);
63 static void notify_disconnect(srs_resctx_t *ctx, int requested);
64
65 static int emul_acquire(srs_resset_t *set, int shared);
66 static int emul_release(srs_resset_t *set);
67
68 #define CONFIG_SREC  "resource.recognition"
69 #define DEFAULT_SREC "speech_recognition"
70 #define CONFIG_SSYN  "resource.synthesis"
71 #define DEFAULT_SSYN "speech_synthesis"
72
73 static const char *name_srec;
74 static const char *name_ssyn;
75
76
77 static void get_resource_names(srs_cfg_t *cfg)
78 {
79     name_srec = srs_config_get_string(cfg, CONFIG_SREC, DEFAULT_SREC);
80     name_ssyn = srs_config_get_string(cfg, CONFIG_SSYN, DEFAULT_SSYN);
81
82     mrp_log_info("Using resource '%s' for speech recognition.", name_srec);
83     mrp_log_info("Using resoruce '%s' for speech synthesis.", name_ssyn);
84 }
85
86
87 static int try_connect(srs_resctx_t *ctx)
88 {
89     srs_context_t *srs = ctx->srs;
90
91     ctx->ctx = mrp_res_create(srs->ml, context_event, ctx);
92
93     if (ctx->ctx != NULL)
94         return TRUE;
95     else
96         return FALSE;
97 }
98
99
100 static void connect_timer_cb(mrp_timer_t *t, void *user_data)
101 {
102     srs_resctx_t *ctx = (srs_resctx_t *)user_data;
103
104     MRP_UNUSED(t);
105
106     if (try_connect(ctx))
107         stop_connect(ctx);
108 }
109
110
111 static int start_connect(srs_resctx_t *ctx)
112 {
113     srs_context_t *srs = ctx->srs;
114
115     ctx->t = mrp_add_timer(srs->ml, CONNECT_TIMER, connect_timer_cb, ctx);
116
117     return (ctx->t != NULL);
118 }
119
120
121 static void stop_connect(srs_resctx_t *ctx)
122 {
123     mrp_del_timer(ctx->t);
124     ctx->t = NULL;
125 }
126
127
128 int srs_resctl_connect(srs_context_t *srs, srs_resctl_event_cb_t cb,
129                        void *user_data, int reconnect)
130 {
131     srs_resctx_t *ctx;
132
133     if (srs->rctx != NULL)
134         return FALSE;
135
136     ctx = mrp_allocz(sizeof(*ctx));
137
138     if (ctx == NULL)
139         return FALSE;
140
141     mrp_list_init(&ctx->sets);
142     ctx->srs       = srs;
143     ctx->cb        = cb;
144     ctx->user_data = user_data;
145     srs->rctx      = ctx;
146
147     if (try_connect(ctx) || (reconnect && start_connect(ctx)))
148         return TRUE;
149     else {
150         mrp_free(ctx);
151         srs->rctx = NULL;
152         return FALSE;
153     }
154 }
155
156
157 void srs_resctl_disconnect(srs_context_t *srs)
158 {
159     srs_resctx_t *ctx = srs->rctx;
160
161     if (ctx != NULL) {
162         stop_connect(ctx);
163         mrp_res_destroy(ctx->ctx);
164         ctx->ctx = NULL;
165         notify_disconnect(ctx, TRUE);
166
167         mrp_free(ctx);
168         srs->rctx = NULL;
169     }
170 }
171
172
173 static void context_event(mrp_res_context_t *rctx, mrp_res_error_t err,
174                           void *user_data)
175 {
176     srs_resctx_t  *ctx = (srs_resctx_t *)user_data;
177
178     MRP_UNUSED(err);
179
180     switch (rctx->state) {
181     case MRP_RES_CONNECTED:
182         mrp_log_info("Resource context connection is up.");
183         stop_connect(ctx);
184         notify_connect(ctx);
185         break;
186
187     case MRP_RES_DISCONNECTED:
188         mrp_log_info("Resource context connection is down.");
189         notify_disconnect(ctx, FALSE);
190         start_connect(ctx);
191     }
192 }
193
194
195 static void notify_connect(srs_resctx_t *ctx)
196 {
197     srs_resctl_event_t e;
198
199     if (ctx->cb != NULL) {
200         e.connection.type = SRS_RESCTL_EVENT_CONNECTION;
201         e.connection.up   = TRUE;
202         ctx->cb(&e, ctx->user_data);
203     }
204 }
205
206
207 static void notify_disconnect(srs_resctx_t *ctx, int requested)
208 {
209     mrp_list_hook_t    *p, *n;
210     srs_resset_t       *set;
211     srs_resctl_event_t  e;
212
213     if (!requested) {
214         if (ctx->cb != NULL) {
215             e.connection.type = SRS_RESCTL_EVENT_CONNECTION;
216             e.connection.up   = FALSE;
217             ctx->cb(&e, ctx->user_data);
218         }
219     }
220
221     e.type = SRS_RESCTL_EVENT_DESTROYED;
222
223     mrp_list_foreach(&ctx->sets, p, n) {
224         set = mrp_list_entry(p, typeof(*set), hook);
225
226         if (set->cb != NULL)
227             set->cb(&e, set->user_data);
228     }
229 }
230
231
232 srs_resset_t *srs_resctl_create(srs_context_t *srs, char *appclass,
233                                 srs_resctl_event_cb_t cb, void *user_data)
234 {
235     srs_resctx_t *ctx = srs->rctx;
236     srs_resset_t *set;
237     int           shared;
238
239     set = mrp_allocz(sizeof(*set));
240
241     if (set == NULL)
242         return NULL;
243
244     mrp_list_init(&set->hook);
245     set->ctx       = ctx;
246     set->cb        = cb;
247     set->user_data = user_data;
248     set->shared    = shared = TRUE;
249     set->appclass  = mrp_strdup(appclass);
250
251     if (ctx == NULL || ctx->ctx == NULL || srs_resctl_online(srs, set)) {
252         mrp_list_append(&ctx->sets, &set->hook);
253         return set;
254     }
255
256     if (ctx != NULL) {
257         if (set->set != NULL)
258             mrp_res_delete_resource_set(set->set);
259
260         mrp_free(set->appclass);
261         mrp_free(set);
262     }
263
264     return NULL;
265 }
266
267
268 void srs_resctl_destroy(srs_resset_t *set)
269 {
270     srs_resctx_t *ctx = set ? set->ctx : NULL;
271
272     if (set != NULL) {
273         if (set->emul != NULL) {
274             mrp_del_deferred(set->emul);
275             set->emul = NULL;
276         }
277
278         if (ctx != NULL)
279             mrp_res_delete_resource_set(set->set);
280
281         mrp_list_delete(&set->hook);
282         mrp_free(set->appclass);
283         mrp_free(set);
284     }
285 }
286
287
288 int srs_resctl_online(srs_context_t *srs, srs_resset_t *set)
289 {
290     srs_resctx_t *ctx = srs->rctx;
291
292     if (set == NULL)
293         return FALSE;
294
295     if (set->emul != NULL) {
296         mrp_del_deferred(set->emul);
297         set->emul = NULL;
298     }
299
300     set->ctx = ctx;
301     set->set = mrp_res_create_resource_set(ctx->ctx, set->appclass,
302                                            set_event, set);
303
304     if (set->set == NULL)
305         return FALSE;
306
307     if (name_srec == NULL || name_ssyn == NULL)
308         get_resource_names(srs->settings);
309
310     if (mrp_res_create_resource(set->set, name_srec, TRUE, set->shared) &&
311         mrp_res_create_resource(set->set, name_ssyn, TRUE, set->shared))
312         return TRUE;
313
314     mrp_res_delete_resource_set(set->set);
315     set->set = NULL;
316
317     return FALSE;
318 }
319
320
321 void srs_resctl_offline(srs_resset_t *set)
322 {
323     if (set != NULL)
324         set->set = NULL;
325 }
326
327
328 int srs_resctl_acquire(srs_resset_t *set, int shared)
329 {
330     srs_resctx_t *ctx = set ? set->ctx : NULL;
331
332     if (ctx == NULL)
333         return FALSE;
334
335     if (ctx->ctx == NULL || set->set == NULL)
336         return emul_acquire(set, shared);
337
338     if (!!shared != !!set->shared) {
339         mrp_res_delete_resource_set(set->set);
340         set->shared = !!shared;
341         set->set    = NULL;
342
343         set->set = mrp_res_create_resource_set(ctx->ctx, set->appclass,
344                                                set_event, set);
345
346         if (set->set == NULL)
347             goto fail;
348
349         if (!mrp_res_create_resource(set->set, name_srec,
350                                      TRUE, shared) ||
351             !mrp_res_create_resource(set->set, name_ssyn,
352                                      TRUE, shared))
353             goto fail;
354     }
355
356     if (mrp_res_acquire_resource_set(set->set) == 0)
357         return TRUE;
358     else {
359         /* fall through */
360     }
361
362  fail:
363     if (set->set != NULL) {
364         mrp_res_delete_resource_set(set->set);
365         set->set = NULL;
366     }
367
368     return FALSE;
369 }
370
371
372 int srs_resctl_release(srs_resset_t *set)
373 {
374     srs_resctx_t *ctx = set ? set->ctx : NULL;
375
376     if (ctx == NULL)
377         return FALSE;
378
379     if (ctx->ctx == NULL || set->set == NULL)
380         return emul_release(set);
381
382     if (mrp_res_release_resource_set(set->set) >= 0)
383         return TRUE;
384     else
385         return FALSE;
386 }
387
388
389 static void set_event(mrp_res_context_t *rctx,
390                       const mrp_res_resource_set_t *rset, void *user_data)
391 {
392     srs_resset_t       *set  = (srs_resset_t *)user_data;
393     mrp_res_resource_t *srec, *ssyn;
394     srs_resctl_event_t  e;
395
396     MRP_UNUSED(rctx);
397
398     srec = mrp_res_get_resource_by_name(rset, name_srec);
399     ssyn = mrp_res_get_resource_by_name(rset, name_ssyn);
400
401     if (srec == NULL || ssyn == NULL || srec->state != ssyn->state) {
402         mrp_log_error("Inconsistent resources in set.");
403         return;
404     }
405
406     if (set->cb == NULL)
407         return;
408
409     e.resource.type    = SRS_RESCTL_EVENT_RESOURCE;
410     e.resource.granted = 0;
411
412     if (srec->state)
413         e.resource.granted |= SRS_RESCTL_MASK_SREC;
414     if (ssyn->state)
415         e.resource.granted |= SRS_RESCTL_MASK_SYNT;
416
417     set->cb(&e, set->user_data);
418 }
419
420
421 static void emul_acquire_cb(mrp_deferred_t *d, void *user_data)
422 {
423     srs_resset_t       *set = (srs_resset_t *)user_data;
424     srs_resctl_event_t  e;
425
426     mrp_del_deferred(d);
427
428     if (set->emul == d)
429         set->emul = NULL;
430
431     e.resource.type    = SRS_RESCTL_EVENT_RESOURCE;
432     e.resource.granted = SRS_RESCTL_MASK_SREC | SRS_RESCTL_MASK_SYNT;
433
434     set->cb(&e, set->user_data);
435 }
436
437
438 static int emul_acquire(srs_resset_t *set, int shared)
439 {
440     srs_resctx_t *ctx = set ? set->ctx : NULL;
441
442     MRP_UNUSED(shared);
443
444     if (ctx == NULL)
445         return FALSE;
446
447     if (set->emul != NULL)
448         return FALSE;
449
450     set->emul = mrp_add_deferred(ctx->srs->ml, emul_acquire_cb, set);
451
452     if (set->emul != NULL)
453         return TRUE;
454     else
455         return FALSE;
456 }
457
458
459 static void emul_release_cb(mrp_deferred_t *d, void *user_data)
460 {
461     srs_resset_t       *set = (srs_resset_t *)user_data;
462     srs_resctl_event_t  e;
463
464     mrp_del_deferred(d);
465
466     if (set->emul == d)
467         set->emul = NULL;
468
469     e.resource.type    = SRS_RESCTL_EVENT_RESOURCE;
470     e.resource.granted = 0;
471
472     set->cb(&e, set->user_data);
473 }
474
475
476 static int emul_release(srs_resset_t *set)
477 {
478     srs_resctx_t *ctx = set ? set->ctx : NULL;
479
480     if (ctx == NULL)
481         return FALSE;
482
483     if (set->emul != NULL)
484         return FALSE;
485
486     set->emul = mrp_add_deferred(set->ctx->srs->ml, emul_release_cb, set);
487
488     if (set->emul != NULL)
489         return TRUE;
490     else
491         return FALSE;
492 }