33c8435ed4084a72b71205b6cbcc659e526fb62f
[profile/ivi/speech-recognition.git] / src / daemon / voice.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 <unistd.h>
31 #include <errno.h>
32 #include <ctype.h>
33
34 #include <murphy/common/macros.h>
35 #include <murphy/common/mm.h>
36 #include <murphy/common/list.h>
37
38 #include "srs/daemon/context.h"
39 #include "srs/daemon/voice.h"
40
41 typedef struct state_s state_t;
42
43 /*
44  * a speech synthesizer backend
45  */
46
47 typedef struct {
48     int                id;               /* internal backend ID */
49     srs_context_t     *srs;              /* main context */
50     char              *name;             /* engine name */
51     srs_voice_api_t    api;              /* backend API */
52     void              *api_data;         /* opaque engine data */
53     srs_voice_actor_t *actors;           /* backend voice actors */
54     int                nactor;           /* number of actors */
55     mrp_list_hook_t    hook;             /* to list of backends */
56     state_t           *state;            /* our state */
57 } renderer_t;
58
59
60 /*
61  * languages
62  */
63
64 typedef struct {
65     char            *lang;               /* language name */
66     mrp_list_hook_t  hook;               /* to list of languages */
67     mrp_list_hook_t  actors;             /* list of actors */
68     int              nmale;              /* number of male actors */
69     int              nfemale;            /* number of female actors */
70 } language_t;
71
72
73 /*
74  * actors
75  */
76
77 typedef struct {
78     char               *voice;           /* globally unique voice id */
79     renderer_t         *r;               /* rendering backend */
80     int                 id;              /* backend voice id */
81     char               *dialect;         /* language dialect, if any */
82     srs_voice_gender_t  gender;          /* actor gender */
83     int                 age;             /* actor age */
84     char               *description;     /* description */
85     mrp_list_hook_t     hook;            /* to list of languages */
86 } actor_t;
87
88
89 /*
90  * ative and queued rendering requests
91  */
92
93 typedef struct {
94     uint32_t            id;              /* request id */
95     renderer_t         *r;               /* rendering backend */
96     uint32_t            vid;             /* backend id */
97     int                 notify_mask;     /* notification event mask */
98     srs_voice_notify_t  notify;          /* notification callback */
99     void               *notify_data;     /* opaque notification data */
100     mrp_timer_t        *timer;           /* request timeout timer */
101     mrp_list_hook_t     hook;            /* hook to list of requests */
102 } request_t;
103
104
105 typedef struct {
106     request_t           req;             /* request */
107     char               *msg;             /* message to render */
108     char              **tags;            /* stream tags */
109     uint32_t            actor;           /* actor id */
110     double              rate;            /* synthesis rate (1 = normal) */
111     double              pitch;           /* synthesis pitch (1 = default) */
112     int                 timeout;         /* timeout */
113 } queued_t;
114
115
116 /*
117  * speech synthesizer state
118  */
119
120 struct state_s {
121     mrp_list_hook_t  synthesizers;       /* registered synthesizers */
122     int              nsynthesizer;       /* number of synthesizers */
123     mrp_list_hook_t  languages;          /* list of supported languages */
124     uint32_t         nextid;             /* next voice id */
125     mrp_list_hook_t  requests;           /* request queue */
126     request_t       *active;             /* active request */
127     request_t       *cancelling;         /* request being cancelled */
128 };
129
130
131 static request_t *find_request(state_t *state, uint32_t rid, uint32_t vid);
132 static request_t *activate_next(state_t *state);
133
134
135 static language_t *find_language(state_t *state, const char *lang, int create)
136 {
137     mrp_list_hook_t *p, *n;
138     language_t      *l;
139
140     mrp_list_foreach(&state->languages, p, n) {
141         l = mrp_list_entry(p, typeof(*l), hook);
142
143         if (!strcasecmp(l->lang, lang))
144             return l;
145     }
146
147     if (!create)
148         return NULL;
149
150     l = mrp_allocz(sizeof(*l));
151
152     if (l == NULL)
153         return NULL;
154
155     mrp_list_init(&l->hook);
156     mrp_list_init(&l->actors);
157
158     l->lang = mrp_strdup(lang);
159
160     if (l->lang == NULL) {
161         mrp_free(l);
162         return NULL;
163     }
164
165     mrp_list_append(&state->languages, &l->hook);
166
167     return l;
168 }
169
170
171 static char *canonical_actor_name(char *buf, size_t size,
172                                   language_t *language, actor_t *actor)
173 {
174     const char *lang, *dialect, *gender, *s;
175     char       *d;
176     int         idx, i;
177     ssize_t     n;
178
179     lang    = language->lang;
180     dialect = actor->dialect;
181
182     if (actor->gender != SRS_VOICE_GENDER_FEMALE) {
183         gender = "-male";
184         idx    = language->nmale++;
185     }
186     else {
187         gender = "-female";
188         idx    = language->nfemale++;
189     }
190
191     d = buf;
192     s = lang;
193
194     while (*s && size > 0) {
195         if (isalnum(*s))
196             *d = tolower(*s);
197         else
198             *d = '-';
199
200         s++;
201         d++;
202         size--;
203     }
204
205     if (dialect != NULL && size > 0) {
206         s = dialect;
207         *d++ = '-';
208         size--;
209
210         while (*s && size > 0) {
211             if (isalnum(*s))
212                 *d = tolower(*s);
213             else
214                 *d = '-';
215
216             s++;
217             d++;
218             size--;
219         }
220     }
221
222     if (idx > 0)
223         snprintf(d, size, "%s-%d", gender, idx);
224     else
225         snprintf(d, size, "%s", gender);
226
227     return buf;
228 }
229
230
231 static int register_actor(renderer_t *r, srs_voice_actor_t *act)
232 {
233     state_t    *state = r->state;
234     language_t *l;
235     actor_t    *a;
236     char        voice[256];
237
238     l = find_language(state, act->lang, TRUE);
239
240     if (l == NULL)
241         return -1;
242
243     a = mrp_allocz(sizeof(*a));
244
245     if (a == NULL)
246         return -1;
247
248
249     mrp_list_init(&a->hook);
250     a->r           = r;
251     a->id          = act->id;
252     a->dialect     = mrp_strdup(act->dialect);
253     a->gender      = act->gender;
254     a->age         = act->age;
255     a->description = mrp_strdup(act->description);
256
257     if ((act->dialect && !a->dialect) ||
258         (act->description && !a->description)) {
259         mrp_free(a->dialect);
260         mrp_free(a->description);
261         mrp_free(a);
262
263         return -1;
264     }
265
266     a->voice = mrp_strdup(canonical_actor_name(voice, sizeof(voice), l, a));
267
268     if (a->voice == NULL) {
269         mrp_free(a->dialect);
270         mrp_free(a->description);
271         mrp_free(a);
272
273         return -1;
274     }
275
276     mrp_list_append(&l->actors, &a->hook);
277
278     mrp_log_info("Registered voice %s/%s.", r->name, voice);
279
280     return 0;
281 }
282
283
284 static void unregister_actors(renderer_t *r)
285 {
286     state_t         *state = r->state;
287     mrp_list_hook_t *lp, *ln;
288     language_t      *l;
289     mrp_list_hook_t *ap, *an;
290     actor_t         *a;
291
292     mrp_list_foreach(&state->languages, lp, ln) {
293         l = mrp_list_entry(lp, typeof(*l), hook);
294
295         mrp_list_foreach(&l->actors, ap, an) {
296             a = mrp_list_entry(ap, typeof(*a), hook);
297
298             if (a->r == r) {
299                 if (a->gender == SRS_VOICE_GENDER_MALE)
300                     l->nmale--;
301                 else
302                     l->nfemale--;
303
304                 mrp_log_info("Unregistering voice %s/%s.", r->name, a->voice);
305
306                 mrp_list_delete(&l->hook);
307
308                 mrp_free(a->voice);
309                 mrp_free(a->dialect);
310                 mrp_free(a->description);
311                 mrp_free(a);
312             }
313         }
314
315         if (mrp_list_empty(&l->actors)) {
316             mrp_list_delete(&l->hook);
317             mrp_free(l);
318         }
319     }
320 }
321
322
323 static actor_t *find_actor(state_t *state, const char *r, const char *v)
324 {
325     mrp_list_hook_t *lp, *ln, *ap, *an;
326     language_t      *l;
327     actor_t         *a;
328
329     mrp_list_foreach(&state->languages, lp, ln) {
330         l = mrp_list_entry(lp, typeof(*l), hook);
331
332         mrp_list_foreach(&l->actors, ap, an) {
333             a = mrp_list_entry(ap, typeof(*a), hook);
334
335             if (!strcmp(a->r->name, r) && !strcmp(a->voice, v))
336                 return a;
337         }
338     }
339
340     return NULL;
341 }
342
343
344 static void free_renderer(renderer_t *r)
345 {
346     if (r != NULL) {
347         mrp_list_delete(&r->hook);
348         unregister_actors(r);
349         mrp_free(r->name);
350     }
351 }
352
353
354 static void notify_request(request_t *req, srs_voice_event_t *event)
355 {
356     renderer_t        *r     = req->r;
357     int                mask  = (1 << event->type);
358     srs_voice_event_t  e;
359
360     if (req->notify != NULL && (mask & req->notify_mask)) {
361         e    = *event;
362         e.id = req->id;
363         req->notify(&e, req->notify_data);
364     }
365 }
366
367
368 static void voice_notify_cb(srs_voice_event_t *event, void *notify_data)
369 {
370     renderer_t        *r     = (renderer_t *)notify_data;
371     state_t           *state = (state_t *)r->state;
372     uint32_t           vid   = event->id;
373     request_t         *req   = find_request(state, -1, vid);
374     int                mask  = (1 << event->type);
375
376     if (req == NULL) {
377         mrp_log_error("Failed to find request for event 0x%x of <%d>.",
378                       event->type, event->id);
379         return;
380     }
381
382     if (event->type == SRS_VOICE_EVENT_STARTED) {
383         mrp_del_timer(req->timer);
384         req->timer = NULL;
385     }
386
387     notify_request(req, event);
388
389     if (mask & SRS_VOICE_MASK_DONE) {
390         mrp_del_timer(req->timer);
391         req->timer = NULL;
392         if (state->cancelling != req) {
393             mrp_list_delete(&req->hook);
394             mrp_free(req);
395         }
396
397         if (state->active == req) {
398             state->active = NULL;
399             activate_next(state);
400         }
401     }
402 }
403
404
405 int srs_register_voice(srs_context_t *srs, const char *name,
406                        srs_voice_api_t *api, void *api_data,
407                        srs_voice_actor_t *actors, int nactor,
408                        srs_voice_notify_t *notify, void **notify_data)
409 {
410     state_t           *state = (state_t *)srs->synthesizer;
411     renderer_t        *r;
412     srs_voice_actor_t *a;
413     int                i;
414
415     if (state == NULL) {
416         srs->synthesizer = state = mrp_allocz(sizeof(*state));
417
418         if (state == NULL)
419             return -1;
420
421         mrp_list_init(&state->synthesizers);
422         mrp_list_init(&state->languages);
423         mrp_list_init(&state->requests);
424         state->nextid = 1;
425     }
426
427     if (api == NULL || name == NULL || actors == NULL || nactor < 1) {
428         errno = EINVAL;
429         return -1;
430     }
431
432     r = mrp_allocz(sizeof(*r));
433
434     if (r == NULL)
435         return -1;
436
437     mrp_list_init(&r->hook);
438     r->id    = state->nsynthesizer++;
439     r->srs   = srs;
440     r->state = state;
441     r->name  = mrp_strdup(name);
442
443     if (r->name == NULL) {
444         free_renderer(r);
445         return -1;
446     }
447
448     r->api      = *api;
449     r->api_data = api_data;
450
451     for (i = 0; i < nactor; i++) {
452         if (register_actor(r, actors + i) != 0)
453             free_renderer(r);
454     }
455
456     mrp_log_info("Registered voice/TTS backend '%s'.", r->name);
457
458     mrp_list_append(&state->synthesizers, &r->hook);
459
460     *notify      = voice_notify_cb;
461     *notify_data = r;
462
463     return 0;
464 }
465
466
467 void srs_unregister_voice(srs_context_t *srs, const char *name)
468 {
469     state_t         *state = (state_t *)srs->synthesizer;
470     renderer_t      *r;
471     mrp_list_hook_t *p, *n;
472
473     if (state != NULL) {
474         mrp_list_foreach(&state->synthesizers, p, n) {
475             r = mrp_list_entry(p, typeof(*r), hook);
476
477             if (!strcmp(r->name, name)) {
478                 mrp_log_info("Unregistering voice/TTS backend '%s'.", name);
479                 free_renderer(r);
480                 return;
481             }
482         }
483     }
484 }
485
486
487 static renderer_t *find_renderer(state_t *state, const char *voice,
488                                  uint32_t *actor)
489 {
490     language_t      *l;
491     actor_t         *a, *fallback;
492     mrp_list_hook_t *ap, *an;
493     char             lang[128], renderer[128], *e;
494     int              n;
495
496     if (state == NULL) {
497         errno = ENOSYS;
498
499         return NULL;
500     }
501
502     if ((e = strchr(voice, '/')) != NULL) {
503         n = e - voice;
504
505         if (n >= sizeof(renderer) - 1)
506             return NULL;
507
508         strncpy(renderer, voice, n);
509         renderer[n] = '\0';
510
511         if ((a = find_actor(state, renderer, e + 1)) != NULL) {
512             *actor = a->id;
513             return a->r;
514         }
515         else
516             return NULL;
517     }
518
519     if ((e = strchr(voice, '-')) == NULL)
520         l = find_language(state, voice, FALSE);
521     else {
522         n = e - voice;
523         if (snprintf(lang, sizeof(lang), "%*.*s", n, n, voice) >= sizeof(lang))
524             l = NULL;
525         else
526             l = find_language(state, lang, FALSE);
527     }
528
529     if (l == NULL)
530         return NULL;
531
532     fallback = NULL;
533     mrp_list_foreach(&l->actors, ap, an) {
534         a = mrp_list_entry(ap, typeof(*a), hook);
535
536         if (!strcmp(a->voice, voice)) {
537             *actor = a->id;
538
539             return a->r;
540         }
541
542         if (fallback == NULL)
543             fallback = a;
544     }
545
546     if (fallback != NULL) {
547         *actor = fallback->id;
548
549         return fallback->r;
550     }
551
552     return NULL;
553 }
554
555
556 #if 0
557 static renderer_t *select_renderer(state_t *state, const char *voice,
558                                    uint32_t *actid)
559 {
560     renderer_t         *r;
561     language_t         *l;
562     srs_voice_actor_t  *a;
563     srs_voice_gender_t  gender;
564     mrp_list_hook_t    *p, *n;
565     renderer_t         *dfltv;
566     uint32_t            dfltid;
567     int                 i;
568
569     if (state == NULL) {
570         errno = ENOSYS;
571         goto notfound;
572     }
573
574     if (!strcmp(actor, SRS_VOICE_FEMALE)) {
575         gender = SRS_VOICE_GENDER_FEMALE;
576         actor  = NULL;
577     }
578     else if (!strcmp(actor, SRS_VOICE_MALE)) {
579         gender = SRS_VOICE_GENDER_MALE;
580         actor  = NULL;
581     }
582     else
583         gender = SRS_VOICE_GENDER_ANY;
584
585     dfltv  = NULL;
586     dfltid = SRS_VOICE_INVALID;
587
588     mrp_list_foreach(&state->synthesizers, p, n) {
589         r = mrp_list_entry(p, typeof(*r), hook);
590
591         for (i = 0, a = r->actors; i < r->nactor; i++, a++) {
592             if (strcmp(a->lang, lang))
593                 continue;
594
595             if (actor == NULL) {
596                 if (gender == a->gender) {
597                     *actid = a->id;
598                     return r;
599                 }
600             }
601             else {
602                 if (!strcmp(a->name, actor)) {
603                     *actid = a->id;
604                     return r;
605                 }
606
607                 if (dfltid == SRS_VOICE_INVALID) {
608                     dfltv  = r;
609                     dfltid = a->id;
610                 }
611             }
612         }
613     }
614
615  notfound:
616     *actid = dfltid;
617     return dfltv;
618 }
619 #endif
620
621 static void free_tags(char **tags)
622 {
623     int i;
624
625     if (tags == NULL)
626         return;
627
628     for (i = 0; tags[i] != NULL; i++)
629         mrp_free(tags[i]);
630
631     mrp_free(tags);
632 }
633
634
635 static char **copy_tags(char **tags)
636 {
637     char **cp = NULL;
638     int    i;
639
640     if (tags == NULL)
641         return NULL;
642
643     for (i = 0; tags[i] != NULL; i++) {
644         if (!mrp_reallocz(cp, i, i + 1))
645             goto fail;
646         if ((cp[i] = mrp_strdup(tags[i])) == NULL)
647             goto fail;
648     }
649
650     if (mrp_reallocz(cp, i, i + 1))
651         return cp;
652     /* fall through */
653  fail:
654     free_tags(cp);
655     return NULL;
656 }
657
658
659 static void request_timer_cb(mrp_timer_t *t, void *user_data)
660 {
661     queued_t          *qr  = (queued_t *)user_data;
662     request_t         *req = &qr->req;
663     srs_voice_event_t  event;
664
665     mrp_log_info("Voice/TTS request #%u timed out.", qr->req.id);
666
667     mrp_del_timer(req->timer);
668     req->timer = NULL;
669
670     mrp_clear(&event);
671     event.type = SRS_VOICE_EVENT_TIMEOUT;
672     event.id   = req->id;
673
674     notify_request(req, &event);
675
676     mrp_list_delete(&req->hook);
677
678     mrp_free(qr->msg);
679     free_tags(qr->tags);
680
681     mrp_free(qr);
682 }
683
684
685 static request_t *enqueue_request(state_t *state, const char *msg, char **tags,
686                                   renderer_t *r, uint32_t actor, double rate,
687                                   double pitch, int timeout, int notify_mask,
688                                   srs_voice_notify_t notify, void *notify_data)
689 {
690     queued_t *qr;
691
692     qr = mrp_allocz(sizeof(*qr));
693
694     if (qr == NULL)
695         return NULL;
696
697     mrp_list_init(&qr->req.hook);
698
699     qr->req.id          = state->nextid++;
700     qr->req.r           = r;
701     qr->req.vid         = SRS_VOICE_INVALID;
702     qr->req.notify_mask = notify_mask;
703     qr->req.notify      = notify;
704     qr->req.notify_data = notify_data;
705
706     qr->msg     = mrp_strdup(msg);
707     qr->tags    = copy_tags(tags);
708     qr->actor   = actor;
709     qr->timeout = timeout;
710
711     if (qr->msg != NULL && (qr->tags != NULL || tags == NULL)) {
712         mrp_list_append(&state->requests, &qr->req.hook);
713
714         if (timeout > 0)
715             qr->req.timer = mrp_add_timer(r->srs->ml, timeout,
716                                           request_timer_cb, qr);
717
718         return &qr->req;
719     }
720     else {
721         mrp_free(qr->msg);
722         free_tags(qr->tags);
723         mrp_free(qr);
724
725         return NULL;
726     }
727 }
728
729
730 static request_t *activate_next(state_t *state)
731 {
732     queued_t        *qr;
733     renderer_t      *r;
734     mrp_list_hook_t *p, *n;
735
736     if (state->active != NULL)
737         return NULL;
738
739     qr = NULL;
740     mrp_list_foreach(&state->requests, p, n) {
741         mrp_list_delete(p);
742         qr = mrp_list_entry(p, typeof(*qr), req.hook);
743         break;
744     }
745
746     if (qr == NULL)
747         return NULL;
748
749     mrp_del_timer(qr->req.timer);
750     qr->req.timer = NULL;
751
752     r = qr->req.r;
753     qr->req.vid = r->api.render(qr->msg, qr->tags, qr->actor, qr->rate,
754                                 qr->pitch, qr->req.notify_mask, r->api_data);
755
756     mrp_free(qr->msg);
757     qr->msg = NULL;
758     free_tags(qr->tags);
759     qr->tags = NULL;
760
761     if (qr->req.vid == SRS_VOICE_INVALID) {
762         if (qr->req.notify != NULL &&
763             (qr->req.notify_mask & 1 << SRS_VOICE_EVENT_ABORTED)) {
764             srs_voice_event_t e;
765
766             mrp_clear(&e);
767             e.type = SRS_VOICE_EVENT_ABORTED;
768             e.id   = qr->req.id;
769
770             voice_notify_cb(&e, qr->req.notify_data);
771
772             free(qr);
773         }
774
775         return NULL;
776     }
777     else {
778         state->active = &qr->req;
779
780         return &qr->req;
781     }
782 }
783
784
785 request_t *render_request(state_t *state, const char *msg, char **tags,
786                           renderer_t *r, uint32_t actor, double rate,
787                           double pitch, int timeout, int notify_mask,
788                           srs_voice_notify_t notify, void *notify_data)
789 {
790     request_t *req;
791
792     req = mrp_allocz(sizeof(*req));
793
794     if (req == NULL)
795         return NULL;
796
797     mrp_list_init(&req->hook);
798     req->id  = state->nextid++;
799     req->r   = r;
800     req->vid = r->api.render(msg, tags, actor, rate, pitch,
801                              notify_mask, r->api_data);
802
803     if (req->vid == SRS_VOICE_INVALID) {
804         mrp_free(req);
805         return NULL;
806     }
807
808     req->notify      = notify;
809     req->notify_mask = notify_mask;
810     req->notify_data = notify_data;
811
812     state->active = req;
813
814     return req;
815 }
816
817
818 uint32_t srs_render_voice(srs_context_t *srs, const char *msg,
819                           char **tags, const char *voice, double rate,
820                           double pitch, int timeout, int notify_mask,
821                           srs_voice_notify_t notify, void *user_data)
822 {
823     state_t    *state = (state_t *)srs->synthesizer;
824     renderer_t *r;
825     request_t  *req;
826     uint32_t    actid;
827
828     if (state == NULL) {
829         errno = ENOSYS;
830
831         return SRS_VOICE_INVALID;
832     }
833
834     r = find_renderer(state, voice, &actid);
835
836     if (r == NULL) {
837         errno = EINVAL;
838
839         return SRS_VOICE_INVALID;
840     }
841
842     if (state->active == NULL)
843         req = render_request(state, msg, tags, r, actid, rate, pitch, timeout,
844                              notify_mask, notify, user_data);
845     else {
846         if (timeout == SRS_VOICE_IMMEDIATE) {
847             errno = EBUSY;
848             req   = NULL;
849         }
850         else
851             req = enqueue_request(state, msg, tags, r, actid, rate, pitch,
852                                   timeout, notify_mask, notify, user_data);
853     }
854
855     if (req != NULL)
856         return req->id;
857     else
858         return SRS_VOICE_INVALID;
859 }
860
861
862 static request_t *find_request(state_t *state, uint32_t rid, uint32_t vid)
863 {
864     mrp_list_hook_t *p, *n;
865     request_t       *req;
866
867     if (state == NULL) {
868         errno = ENOSYS;
869         goto error;
870     }
871
872     if ((req = state->active) != NULL) {
873         if ((rid == -1 || req->id == rid) && (vid == -1 || req->vid == vid))
874             return req;
875     }
876
877     mrp_list_foreach(&state->requests, p, n) {
878         req = mrp_list_entry(p, typeof(*req), hook);
879
880         if ((rid == -1 || req->id == rid) && (vid == -1 || req->vid == vid))
881             return req;
882     }
883
884     errno = EINVAL;
885
886  error:
887     return NULL;
888 }
889
890
891 void srs_cancel_voice(srs_context_t *srs, uint32_t rid, int notify)
892 {
893     state_t    *state = (state_t *)srs->synthesizer;
894     request_t  *req   = find_request(state, rid, -1);
895     renderer_t *voice = req ? req->r : NULL;
896
897     if (req == NULL)
898         return;
899
900     mrp_del_timer(req->timer);
901     req->timer = NULL;
902     state->cancelling = req;
903
904     voice->api.cancel(req->vid, voice->api_data);
905
906     mrp_list_delete(&req->hook);
907     mrp_free(req);
908
909     if (state->active == req) {
910         state->active = NULL;
911         activate_next(state);
912     }
913 }
914
915
916 int srs_query_voices(srs_context_t *srs, const char *language,
917                      srs_voice_actor_t **actorsp)
918 {
919     state_t            *state = (state_t *)srs->synthesizer;
920     srs_voice_actor_t  *actors, *actor;
921     int                 nactor, i;
922     language_t         *l;
923     mrp_list_hook_t    *lp, *ln;
924     actor_t            *a;
925     mrp_list_hook_t    *ap, *an;
926
927     if (state == NULL) {
928         *actorsp = NULL;
929
930         return 0;
931     }
932
933     actors = NULL;
934     nactor = 0;
935
936     mrp_list_foreach(&state->languages, lp, ln) {
937         l = mrp_list_entry(lp, typeof(*l), hook);
938
939         if (language != NULL && strcasecmp(l->lang, language))
940             continue;
941
942         mrp_list_foreach(&l->actors, ap, an) {
943             a = mrp_list_entry(ap, typeof(*a), hook);
944
945             if (mrp_reallocz(actors, nactor, nactor + 1) == NULL)
946                 goto fail;
947
948             actor = actors + nactor++;
949
950             actor->name        = mrp_strdup(a->voice);
951             actor->lang        = mrp_strdup(l->lang);
952             actor->dialect     = mrp_strdup(a->dialect);
953             actor->gender      = a->gender;
954             actor->age         = a->age;
955             actor->description = mrp_strdup(a->description);
956
957             if (!actor->name || !actor->lang ||
958                 (!actor->dialect && a->dialect) ||
959                 (!actor->description && a->description))
960                 goto fail;
961         }
962     }
963
964     if (actors != NULL) {
965         if (!mrp_reallocz(actors, nactor, nactor + 1))
966             goto fail;
967     }
968
969     *actorsp = actors;
970
971     return nactor;
972
973  fail:
974     for (i = 0; i < nactor; i++) {
975         mrp_free(actors[i].name);
976         mrp_free(actors[i].lang);
977         mrp_free(actors[i].dialect);
978         mrp_free(actors[i].description);
979     }
980
981     return -1;
982 }
983
984
985 void srs_free_queried_voices(srs_voice_actor_t *actors)
986 {
987     srs_voice_actor_t *a;
988
989     if (actors != NULL) {
990         for (a = actors; a->lang; a++) {
991             mrp_free(a->name);
992             mrp_free(a->lang);
993             mrp_free(a->dialect);
994             mrp_free(a->description);
995         }
996         mrp_free(actors);
997     }
998 }