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