1 /***************************************************************************
2 * Copyright (C) 2007, Gilles Casse <gcasse@oralux.org> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 3 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18 ***************************************************************************/
19
20 #include "speech.h"
21
22 #ifdef USE_ASYNC
23 // This source file is only used for asynchronious modes
24
25
26 //<includes
27 #ifndef PLATFORM_WINDOWS
28 #include <unistd.h>
29 #endif
30 #include <assert.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <pthread.h>
34 #include <semaphore.h>
35 #include <sys/time.h>
36 #include <errno.h>
37
38 #include "speak_lib.h"
39 #include "event.h"
40 #include "wave.h"
41 #include "debug.h"
42 //>
43 //<decls and function prototypes
44
45
46 // my_mutex: protects my_thread_is_talking,
47 static pthread_mutex_t my_mutex;
48 static sem_t my_sem_start_is_required;
49 static sem_t my_sem_stop_is_required;
50 static sem_t my_sem_stop_is_acknowledged;
51 // my_thread: polls the audio duration and compares it to the duration of the first event.
52 static pthread_t my_thread;
53 static bool thread_inited;
54
55 static t_espeak_callback* my_callback = NULL;
56 static int my_event_is_running=0;
57
58 enum {MIN_TIMEOUT_IN_MS=10,
59 ACTIVITY_TIMEOUT=50, // in ms, check that the stream is active
60 MAX_ACTIVITY_CHECK=6
61 };
62
63
64 typedef struct t_node
65 {
66 void* data;
67 t_node *next;
68 } node;
69
70 static node* head=NULL;
71 static node* tail=NULL;
72 static int node_counter=0;
73 static espeak_ERROR push(void* data);
74 static void* pop();
75 static void init();
76 static void* polling_thread(void*);
77
78 //>
79 //<event_init
80
event_set_callback(t_espeak_callback * SynthCallback)81 void event_set_callback(t_espeak_callback* SynthCallback)
82 {
83 my_callback = SynthCallback;
84 }
85
event_init(void)86 void event_init(void)
87 {
88 ENTER("event_init");
89
90 my_event_is_running=0;
91
92 // security
93 pthread_mutex_init( &my_mutex, (const pthread_mutexattr_t *)NULL);
94 init();
95
96 assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
97 assert(-1 != sem_init(&my_sem_stop_is_required, 0, 0));
98 assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));
99
100 pthread_attr_t a_attrib;
101
102 if (pthread_attr_init (&a_attrib) == 0
103 && pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE) == 0)
104 {
105 thread_inited = (0 == pthread_create(&my_thread,
106 &a_attrib,
107 polling_thread,
108 (void*)NULL));
109 }
110 assert(thread_inited);
111 pthread_attr_destroy(&a_attrib);
112 }
113 //>
114 //<event_display
event_display(espeak_EVENT * event)115 static void event_display(espeak_EVENT* event)
116 {
117 ENTER("event_display");
118
119 #ifdef DEBUG_ENABLED
120 if (event==NULL)
121 {
122 SHOW("event_display > event=%s\n","NULL");
123 }
124 else
125 {
126 static const char* label[] = {
127 "LIST_TERMINATED",
128 "WORD",
129 "SENTENCE",
130 "MARK",
131 "PLAY",
132 "END",
133 "MSG_TERMINATED",
134 "PHONEME",
135 "SAMPLERATE",
136 "??"
137 };
138
139 SHOW("event_display > event=0x%x\n",event);
140 SHOW("event_display > type=%s\n",label[event->type]);
141 SHOW("event_display > uid=%d\n",event->unique_identifier);
142 SHOW("event_display > text_position=%d\n",event->text_position);
143 SHOW("event_display > length=%d\n",event->length);
144 SHOW("event_display > audio_position=%d\n",event->audio_position);
145 SHOW("event_display > sample=%d\n",event->sample);
146 SHOW("event_display > user_data=0x%x\n",event->user_data);
147 }
148 #endif
149 }
150 //>
151 //<event_copy
152
event_copy(espeak_EVENT * event)153 static espeak_EVENT* event_copy (espeak_EVENT* event)
154 {
155 ENTER("event_copy");
156
157 if (event==NULL)
158 {
159 return NULL;
160 }
161
162 espeak_EVENT* a_event=(espeak_EVENT*)malloc(sizeof(espeak_EVENT));
163 if (a_event)
164 {
165 memcpy(a_event, event, sizeof(espeak_EVENT));
166
167 switch(event->type)
168 {
169 case espeakEVENT_MARK:
170 case espeakEVENT_PLAY:
171 if (event->id.name)
172 {
173 a_event->id.name = strdup(event->id.name);
174 }
175 break;
176
177 default:
178 break;
179 }
180 }
181
182 event_display(a_event);
183
184 return a_event;
185 }
186
187 //>
188 //<event_notify
189
190 // Call the user supplied callback
191 //
192 // Note: the current sequence is:
193 //
194 // * First call with: event->type = espeakEVENT_SENTENCE
195 // * 0, 1 or several calls: event->type = espeakEVENT_WORD
196 // * Last call: event->type = espeakEVENT_MSG_TERMINATED
197 //
198
event_notify(espeak_EVENT * event)199 static void event_notify(espeak_EVENT* event)
200 {
201 ENTER("event_notify");
202 static unsigned int a_old_uid = 0;
203
204 espeak_EVENT events[2];
205 memcpy(&events[0],event,sizeof(espeak_EVENT)); // the event parameter in the callback function should be an array of eventd
206 memcpy(&events[1],event,sizeof(espeak_EVENT));
207 events[1].type = espeakEVENT_LIST_TERMINATED; // ... terminated by an event type=0
208
209 if (event && my_callback)
210 {
211 event_display(event);
212
213 switch(event->type)
214 {
215 case espeakEVENT_SENTENCE:
216 my_callback(NULL, 0, events);
217 a_old_uid = event->unique_identifier;
218 break;
219
220 case espeakEVENT_MSG_TERMINATED:
221 case espeakEVENT_MARK:
222 case espeakEVENT_WORD:
223 case espeakEVENT_END:
224 case espeakEVENT_PHONEME:
225 {
226 // jonsd - I'm not sure what this is for. gilles says it's for when Gnome Speech reads a file of blank lines
227 if (a_old_uid != event->unique_identifier)
228 {
229 espeak_EVENT_TYPE a_new_type = events[0].type;
230 events[0].type = espeakEVENT_SENTENCE;
231 my_callback(NULL, 0, events);
232 events[0].type = a_new_type;
233 usleep(50000);
234 }
235 my_callback(NULL, 0, events);
236 a_old_uid = event->unique_identifier;
237 }
238 break;
239
240 default:
241 case espeakEVENT_LIST_TERMINATED:
242 case espeakEVENT_PLAY:
243 break;
244 }
245 }
246 }
247 //>
248 //<event_delete
249
event_delete(espeak_EVENT * event)250 static int event_delete(espeak_EVENT* event)
251 {
252 ENTER("event_delete");
253
254 event_display(event);
255
256 if(event==NULL)
257 {
258 return 0;
259 }
260
261 switch(event->type)
262 {
263 case espeakEVENT_MSG_TERMINATED:
264 event_notify(event);
265 break;
266
267 case espeakEVENT_MARK:
268 case espeakEVENT_PLAY:
269 if(event->id.name)
270 {
271 free((void*)(event->id.name));
272 }
273 break;
274
275 default:
276 break;
277 }
278
279 free(event);
280 return 1;
281 }
282
283 //>
284 //<event_declare
285
event_declare(espeak_EVENT * event)286 espeak_ERROR event_declare (espeak_EVENT* event)
287 {
288 ENTER("event_declare");
289
290 event_display(event);
291
292 if (!event)
293 {
294 return EE_INTERNAL_ERROR;
295 }
296
297 int a_status = pthread_mutex_lock(&my_mutex);
298 espeak_ERROR a_error = EE_OK;
299
300 if (!a_status)
301 {
302 SHOW_TIME("event_declare > locked\n");
303 espeak_EVENT* a_event = event_copy(event);
304 a_error = push(a_event);
305 if (a_error != EE_OK)
306 {
307 event_delete(a_event);
308 }
309 SHOW_TIME("event_declare > unlocking\n");
310 a_status = pthread_mutex_unlock(&my_mutex);
311 }
312
313 // TBD: remove the comment
314 // reminder: code in comment.
315 // This wait can lead to an underrun
316 //
317 // if (!a_status && !my_event_is_running && (a_error == EE_OK))
318 // {
319 // // quit when command is actually started
320 // // (for possible forthcoming 'end of command' checks)
321 SHOW_TIME("event_declare > post my_sem_start_is_required\n");
322 sem_post(&my_sem_start_is_required);
323 // int val=1;
324 // while (val)
325 // {
326 // usleep(50000); // TBD: event?
327 // sem_getvalue(&my_sem_start_is_required, &val);
328 // }
329 // }
330
331 if (a_status != 0)
332 {
333 a_error = EE_INTERNAL_ERROR;
334 }
335
336 return a_error;
337 }
338
339 //>
340 //<event_clear_all
341
event_clear_all()342 espeak_ERROR event_clear_all ()
343 {
344 ENTER("event_clear_all");
345
346 int a_status = pthread_mutex_lock(&my_mutex);
347 int a_event_is_running = 0;
348
349 SHOW_TIME("event_stop > locked\n");
350 if (a_status != 0)
351 {
352 return EE_INTERNAL_ERROR;
353 }
354
355 if (my_event_is_running)
356 {
357 SHOW_TIME("event_stop > post my_sem_stop_is_required\n");
358 sem_post(&my_sem_stop_is_required);
359 a_event_is_running = 1;
360 }
361 else
362 {
363 init(); // clear pending events
364 }
365 SHOW_TIME("event_stop > unlocking\n");
366 a_status = pthread_mutex_unlock(&my_mutex);
367 if (a_status != 0)
368 {
369 return EE_INTERNAL_ERROR;
370 }
371
372 if (a_event_is_running)
373 {
374 SHOW_TIME("event_stop > wait for my_sem_stop_is_acknowledged\n");
375 while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
376 {
377 continue; // Restart when interrupted by handler
378 }
379 SHOW_TIME("event_stop > get my_sem_stop_is_acknowledged\n");
380 }
381
382 SHOW_TIME("LEAVE event_stop\n");
383
384 return EE_OK;
385 }
386
387 //>
388 //<sleep_until_timeout_or_stop_request
389
sleep_until_timeout_or_stop_request(uint32_t time_in_ms)390 static int sleep_until_timeout_or_stop_request(uint32_t time_in_ms)
391 {
392 ENTER("sleep_until_timeout_or_stop_request");
393
394 int a_stop_is_required=0;
395 struct timespec ts;
396 struct timeval tv;
397 int err=0;
398
399 clock_gettime2( &ts);
400
401 #ifdef DEBUG_ENABLED
402 struct timespec to;
403 to.tv_sec = ts.tv_sec;
404 to.tv_nsec = ts.tv_nsec;
405 #endif
406
407 add_time_in_ms( &ts, time_in_ms);
408
409 SHOW("polling_thread > sleep_until_timeout_or_stop_request > start sem_timedwait from %d.%09lu to %d.%09lu \n",
410 to.tv_sec, to.tv_nsec,
411 ts.tv_sec, ts.tv_nsec);
412
413 while ((err = sem_timedwait(&my_sem_stop_is_required, &ts)) == -1
414 && errno == EINTR)
415 {
416 continue; // Restart when interrupted by handler
417 }
418
419 assert (gettimeofday(&tv, NULL) != -1);
420 SHOW("polling_thread > sleep_until_timeout_or_stop_request > stop sem_timedwait %d.%09lu \n",
421 tv.tv_sec, tv.tv_usec*1000);
422
423 if (err == 0)
424 {
425 SHOW("polling_thread > sleep_until_timeout_or_stop_request > %s\n","stop required!");
426 a_stop_is_required=1; // stop required
427 }
428 return a_stop_is_required;
429 }
430
431 //>
432 //<get_remaining_time
433 // Asked for the time interval required for reaching the sample.
434 // If the stream is opened but the audio samples are not played,
435 // a timeout is started.
436
get_remaining_time(uint32_t sample,uint32_t * time_in_ms,int * stop_is_required)437 static int get_remaining_time(uint32_t sample, uint32_t* time_in_ms, int* stop_is_required)
438 {
439 ENTER("get_remaining_time");
440
441 int err = 0;
442 *stop_is_required = 0;
443 int i=0;
444
445 for (i=0; i < MAX_ACTIVITY_CHECK && (*stop_is_required == 0); i++)
446 {
447 err = wave_get_remaining_time( sample, time_in_ms);
448
449 if (err || wave_is_busy(NULL) || (*time_in_ms == 0))
450 { // if err, stream not available: quit
451 // if wave is busy, time_in_ms is known: quit
452 // if wave is not busy but remaining time == 0, event is reached: quit
453 break;
454 }
455
456 // stream opened but not active
457 //
458 // Several possible states:
459 // * the stream is opened but not yet started:
460 //
461 // wait for the start of stream
462 //
463 // * some samples have already been played,
464 // ** the end of stream is reached
465 // ** or there is an underrun
466 //
467 // wait for the close of stream
468
469 *stop_is_required = sleep_until_timeout_or_stop_request( ACTIVITY_TIMEOUT);
470 }
471
472 return err;
473 }
474
475 //>
476 //<polling_thread
477
polling_thread(void *)478 static void* polling_thread(void*)
479 {
480 ENTER("polling_thread");
481
482 while(1)
483 {
484 int a_stop_is_required=0;
485
486 SHOW_TIME("polling_thread > locking\n");
487 int a_status = pthread_mutex_lock(&my_mutex);
488 SHOW_TIME("polling_thread > locked (my_event_is_running = 0)\n");
489 my_event_is_running = 0;
490 pthread_mutex_unlock(&my_mutex);
491 SHOW_TIME("polling_thread > unlocked\n");
492
493 SHOW_TIME("polling_thread > wait for my_sem_start_is_required\n");
494
495 while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
496 {
497 continue; // Restart when interrupted by handler
498 }
499
500 SHOW_TIME("polling_thread > get my_sem_start_is_required\n");
501
502 a_status = pthread_mutex_lock(&my_mutex);
503 SHOW_TIME("polling_thread > locked (my_event_is_running = 1)\n");
504 my_event_is_running = 1;
505 pthread_mutex_unlock(&my_mutex);
506 SHOW_TIME("polling_thread > unlocked\n");
507
508 a_stop_is_required=0;
509 a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required); // NOTE: may set a_stop_is_required to -1
510 if ((a_status==0) && (a_stop_is_required > 0))
511 {
512 SHOW("polling_thread > stop required (%d)\n", __LINE__);
513 while(0 == sem_trywait(&my_sem_stop_is_required))
514 {
515 };
516 }
517 else
518 {
519 a_stop_is_required=0;
520 }
521
522 // In this loop, my_event_is_running = 1
523 while (head && (a_stop_is_required <= 0))
524 {
525 SHOW_TIME("polling_thread > check head\n");
526 while(0 == sem_trywait(&my_sem_start_is_required))
527 {
528 };
529
530 espeak_EVENT* event = (espeak_EVENT*)(head->data);
531 assert(event);
532
533 uint32_t time_in_ms = 0;
534
535 int err = get_remaining_time((uint32_t)event->sample,
536 &time_in_ms,
537 &a_stop_is_required);
538 if (a_stop_is_required > 0)
539 {
540 break;
541 }
542 else if (err != 0)
543 {
544 // No available time: the event is deleted.
545 SHOW("polling_thread > %s\n","audio device down");
546 a_status = pthread_mutex_lock(&my_mutex);
547 SHOW_TIME("polling_thread > locked\n");
548 event_delete( (espeak_EVENT*)pop());
549 a_status = pthread_mutex_unlock(&my_mutex);
550 SHOW_TIME("polling_thread > unlocked\n");
551 }
552 else if (time_in_ms==0)
553 { // the event is already reached.
554 if (my_callback)
555 {
556 event_notify(event);
557 // the user_data (and the type) are cleaned to be sure
558 // that MSG_TERMINATED is called twice (at delete time too).
559 event->type=espeakEVENT_LIST_TERMINATED;
560 event->user_data=NULL;
561 }
562
563 a_status = pthread_mutex_lock(&my_mutex);
564 SHOW_TIME("polling_thread > locked\n");
565 event_delete( (espeak_EVENT*)pop());
566 a_status = pthread_mutex_unlock(&my_mutex);
567 SHOW_TIME("polling_thread > unlocked\n");
568
569 a_stop_is_required=0;
570 a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);
571
572 if ((a_status==0) && (a_stop_is_required > 0))
573 {
574 SHOW("polling_thread > stop required (%d)\n", __LINE__);
575 while(0 == sem_trywait(&my_sem_stop_is_required))
576 {
577 };
578 }
579 else
580 {
581 a_stop_is_required=0;
582 }
583 }
584 else
585 { // The event will be notified soon: sleep until timeout or stop request
586 a_stop_is_required = sleep_until_timeout_or_stop_request(time_in_ms);
587 }
588 }
589
590 a_status = pthread_mutex_lock(&my_mutex);
591 SHOW_TIME("polling_thread > locked\n");
592
593 SHOW_TIME("polling_thread > my_event_is_running = 0\n");
594 my_event_is_running = 0;
595
596 if(a_stop_is_required <= 0)
597 {
598 a_status = sem_getvalue(&my_sem_stop_is_required, &a_stop_is_required);
599 if ((a_status==0) && (a_stop_is_required > 0))
600 {
601 SHOW("polling_thread > stop required (%d)\n", __LINE__);
602 while(0 == sem_trywait(&my_sem_stop_is_required))
603 {
604 };
605 }
606 else
607 {
608 a_stop_is_required=0;
609 }
610 }
611
612 a_status = pthread_mutex_unlock(&my_mutex);
613 SHOW_TIME("polling_thread > unlocked\n");
614
615 if (a_stop_is_required > 0)
616 {
617 SHOW("polling_thread > %s\n","stop required!");
618 // no mutex required since the stop command is synchronous
619 // and waiting for my_sem_stop_is_acknowledged
620 init();
621
622 // acknowledge the stop request
623 SHOW_TIME("polling_thread > post my_sem_stop_is_acknowledged\n");
624 a_status = sem_post(&my_sem_stop_is_acknowledged);
625 }
626 }
627
628 return NULL;
629 }
630
631 //>
632 //<push, pop, init
633 enum {MAX_NODE_COUNTER=1000};
634 // return 1 if ok, 0 otherwise
push(void * the_data)635 static espeak_ERROR push(void* the_data)
636 {
637 ENTER("event > push");
638
639 assert((!head && !tail) || (head && tail));
640
641 if (the_data == NULL)
642 {
643 SHOW("event > push > event=0x%x\n", NULL);
644 return EE_INTERNAL_ERROR;
645 }
646
647 if (node_counter >= MAX_NODE_COUNTER)
648 {
649 SHOW("event > push > %s\n", "EE_BUFFER_FULL");
650 return EE_BUFFER_FULL;
651 }
652
653 node *n = (node *)malloc(sizeof(node));
654 if (n == NULL)
655 {
656 return EE_INTERNAL_ERROR;
657 }
658
659 if (head == NULL)
660 {
661 head = n;
662 tail = n;
663 }
664 else
665 {
666 tail->next = n;
667 tail = n;
668 }
669
670 tail->next = NULL;
671 tail->data = the_data;
672
673 node_counter++;
674 SHOW("event > push > counter=%d (uid=%d)\n",node_counter,((espeak_EVENT*)the_data)->unique_identifier);
675
676 return EE_OK;
677 }
678
pop()679 static void* pop()
680 {
681 ENTER("event > pop");
682 void* the_data = NULL;
683
684 assert((!head && !tail) || (head && tail));
685
686 if (head != NULL)
687 {
688 node* n = head;
689 the_data = n->data;
690 head = n->next;
691 free(n);
692 node_counter--;
693 SHOW("event > pop > event=0x%x (counter=%d, uid=%d)\n",the_data, node_counter,((espeak_EVENT*)the_data)->unique_identifier);
694 }
695
696 if(head == NULL)
697 {
698 tail = NULL;
699 }
700
701 return the_data;
702 }
703
704
init()705 static void init()
706 {
707 ENTER("event > init");
708
709 while (event_delete( (espeak_EVENT*)pop() ))
710 {}
711
712 node_counter = 0;
713 }
714
715 //>
716 //<event_terminate
event_terminate()717 void event_terminate()
718 {
719 ENTER("event_terminate");
720
721 if (thread_inited)
722 {
723 pthread_cancel(my_thread);
724 pthread_join(my_thread,NULL);
725 pthread_mutex_destroy(&my_mutex);
726 sem_destroy(&my_sem_start_is_required);
727 sem_destroy(&my_sem_stop_is_required);
728 sem_destroy(&my_sem_stop_is_acknowledged);
729 init(); // purge event
730 thread_inited = 0;
731 }
732 }
733
734 #endif
735 //>
736
737