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