40b1351602739e15589be5aa9dedef7df6e0833c
[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_get_string_config(cfg, CONFIG_SREC, DEFAULT_SREC);
80     name_ssyn = srs_get_string_config(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     srs_context_t *srs = ctx->srs;
178
179     MRP_UNUSED(err);
180
181     switch (rctx->state) {
182     case MRP_RES_CONNECTED:
183         mrp_log_info("Resource context connection is up.");
184         stop_connect(ctx);
185         notify_connect(ctx);
186         break;
187
188     case MRP_RES_DISCONNECTED:
189         mrp_log_info("Resource context connection is down.");
190         notify_disconnect(ctx, FALSE);
191         start_connect(ctx);
192     }
193 }
194
195
196 static void notify_connect(srs_resctx_t *ctx)
197 {
198     srs_resctl_event_t e;
199
200     if (ctx->cb != NULL) {
201         e.connection.type = SRS_RESCTL_EVENT_CONNECTION;
202         e.connection.up   = TRUE;
203         ctx->cb(&e, ctx->user_data);
204     }
205 }
206
207
208 static void notify_disconnect(srs_resctx_t *ctx, int requested)
209 {
210     mrp_list_hook_t    *p, *n;
211     srs_resset_t       *set;
212     srs_resctl_event_t  e;
213
214     if (!requested) {
215         if (ctx->cb != NULL) {
216             e.connection.type = SRS_RESCTL_EVENT_CONNECTION;
217             e.connection.up   = FALSE;
218             ctx->cb(&e, ctx->user_data);
219         }
220     }
221
222     e.type = SRS_RESCTL_EVENT_DESTROYED;
223
224     mrp_list_foreach(&ctx->sets, p, n) {
225         set = mrp_list_entry(p, typeof(*set), hook);
226
227         if (set->cb != NULL)
228             set->cb(&e, set->user_data);
229     }
230 }
231
232
233 srs_resset_t *srs_resctl_create(srs_context_t *srs, char *appclass,
234                                 srs_resctl_event_cb_t cb, void *user_data)
235 {
236     srs_resctx_t *ctx = srs->rctx;
237     srs_resset_t *set;
238     int           shared;
239
240     set = mrp_allocz(sizeof(*set));
241
242     if (set == NULL)
243         return NULL;
244
245     mrp_list_init(&set->hook);
246     set->ctx       = ctx;
247     set->cb        = cb;
248     set->user_data = user_data;
249     set->shared    = shared = TRUE;
250     set->appclass  = mrp_strdup(appclass);
251
252     if (ctx == NULL || ctx->ctx == NULL || srs_resctl_online(srs, set)) {
253         mrp_list_append(&ctx->sets, &set->hook);
254         return set;
255     }
256
257  fail:
258     if (ctx != NULL) {
259         if (set->set != NULL)
260             mrp_res_delete_resource_set(set->set);
261
262         mrp_free(set->appclass);
263         mrp_free(set);
264     }
265
266     return NULL;
267 }
268
269
270 void srs_resctl_destroy(srs_resset_t *set)
271 {
272     srs_resctx_t *ctx = set ? set->ctx : NULL;
273
274     if (set != NULL) {
275         if (set->emul != NULL) {
276             mrp_del_deferred(set->emul);
277             set->emul = NULL;
278         }
279
280         if (ctx != NULL)
281             mrp_res_delete_resource_set(set->set);
282
283         mrp_list_delete(&set->hook);
284         mrp_free(set->appclass);
285         mrp_free(set);
286     }
287 }
288
289
290 int srs_resctl_online(srs_context_t *srs, srs_resset_t *set)
291 {
292     srs_resctx_t *ctx    = srs->rctx;
293     int           shared = set->shared;
294
295     if (set == NULL)
296         return FALSE;
297
298     if (set->emul != NULL) {
299         mrp_del_deferred(set->emul);
300         set->emul = NULL;
301     }
302
303     set->ctx = ctx;
304     set->set = mrp_res_create_resource_set(ctx->ctx, set->appclass,
305                                            set_event, set);
306
307     if (set->set == NULL)
308         return FALSE;
309
310     if (name_srec == NULL || name_ssyn == NULL)
311         get_resource_names(srs->settings);
312
313     if (mrp_res_create_resource(set->set, name_srec, TRUE, shared) &&
314         mrp_res_create_resource(set->set, name_ssyn, TRUE, shared))
315         return TRUE;
316
317     mrp_res_delete_resource_set(set->set);
318     set->set = NULL;
319
320     return FALSE;
321 }
322
323
324 void srs_resctl_offline(srs_resset_t *set)
325 {
326     if (set != NULL)
327         set->set = NULL;
328 }
329
330
331 int srs_resctl_acquire(srs_resset_t *set, int shared)
332 {
333     srs_resctx_t *ctx = set ? set->ctx : NULL;
334
335     if (ctx == NULL)
336         return FALSE;
337
338     if (ctx->ctx == NULL || set->set == NULL)
339         return emul_acquire(set, shared);
340
341     if (!!shared != !!set->shared) {
342         mrp_res_delete_resource_set(set->set);
343         set->shared = !!shared;
344         set->set    = NULL;
345
346         set->set = mrp_res_create_resource_set(ctx->ctx, set->appclass,
347                                                set_event, set);
348
349         if (set->set == NULL)
350             goto fail;
351
352         if (!mrp_res_create_resource(set->set, name_srec,
353                                      TRUE, shared) ||
354             !mrp_res_create_resource(set->set, name_ssyn,
355                                      TRUE, shared))
356             goto fail;
357     }
358
359     if (mrp_res_acquire_resource_set(set->set) == 0)
360         return TRUE;
361     else
362         /* fall through */;
363
364  fail:
365     if (set->set != NULL) {
366         mrp_res_delete_resource_set(set->set);
367         set->set = NULL;
368     }
369
370     return FALSE;
371 }
372
373
374 int srs_resctl_release(srs_resset_t *set)
375 {
376     srs_resctx_t *ctx = set ? set->ctx : NULL;
377
378     if (ctx == NULL)
379         return FALSE;
380
381     if (ctx->ctx == NULL || set->set == NULL)
382         return emul_release(set);
383
384     if (mrp_res_release_resource_set(set->set) >= 0)
385         return TRUE;
386     else
387         return FALSE;
388 }
389
390
391 static void set_event(mrp_res_context_t *rctx,
392                       const mrp_res_resource_set_t *rset, void *user_data)
393 {
394     srs_resset_t       *set  = (srs_resset_t *)user_data;
395     mrp_res_resource_t *srec, *ssyn;
396     srs_resctl_event_t  e;
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 }