/native/external/espeak/src/fifo.cpp

http://eyes-free.googlecode.com/ · C++ · 593 lines · 400 code · 104 blank · 89 comment · 87 complexity · 72e363a29b06be6b4f40ca30462333cb MD5 · raw file

  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. #include "speech.h"
  20. #ifdef USE_ASYNC
  21. // This source file is only used for asynchronious modes
  22. //<includes
  23. #include <unistd.h>
  24. #include <assert.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <pthread.h>
  28. #include <semaphore.h>
  29. ////#include <wchar.h>
  30. #include <errno.h>
  31. #include <sys/time.h>
  32. #include <time.h>
  33. #include "fifo.h"
  34. #include "wave.h"
  35. #include "debug.h"
  36. //>
  37. //<decls and function prototypes
  38. // my_mutex: protects my_thread_is_talking,
  39. // my_stop_is_required, and the command fifo
  40. static pthread_mutex_t my_mutex;
  41. static int my_command_is_running = 0;
  42. static int my_stop_is_required = 0;
  43. // + fifo
  44. //
  45. // my_thread: reads commands from the fifo, and runs them.
  46. static pthread_t my_thread;
  47. static sem_t my_sem_start_is_required;
  48. static sem_t my_sem_stop_is_acknowledged;
  49. static void* say_thread(void*);
  50. static espeak_ERROR push(t_espeak_command* the_command);
  51. static t_espeak_command* pop();
  52. static void init();
  53. static int node_counter=0;
  54. enum {MAX_NODE_COUNTER=400,
  55. INACTIVITY_TIMEOUT=50, // in ms, check that the stream is inactive
  56. MAX_INACTIVITY_CHECK=2
  57. };
  58. //>
  59. //<fifo_init
  60. void fifo_init()
  61. {
  62. ENTER("fifo_init");
  63. // security
  64. pthread_mutex_init( &my_mutex, (const pthread_mutexattr_t *)NULL);
  65. init();
  66. assert(-1 != sem_init(&my_sem_start_is_required, 0, 0));
  67. assert(-1 != sem_init(&my_sem_stop_is_acknowledged, 0, 0));
  68. pthread_attr_t a_attrib;
  69. if (pthread_attr_init (& a_attrib)
  70. || pthread_attr_setdetachstate(&a_attrib, PTHREAD_CREATE_JOINABLE)
  71. || pthread_create( &my_thread,
  72. & a_attrib,
  73. say_thread,
  74. (void*)NULL))
  75. {
  76. assert(0);
  77. }
  78. pthread_attr_destroy(&a_attrib);
  79. // leave once the thread is actually started
  80. SHOW_TIME("fifo > wait for my_sem_stop_is_acknowledged\n");
  81. while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
  82. {
  83. continue; // Restart when interrupted by handler
  84. }
  85. SHOW_TIME("fifo > get my_sem_stop_is_acknowledged\n");
  86. }
  87. //>
  88. //<fifo_add_command
  89. espeak_ERROR fifo_add_command (t_espeak_command* the_command)
  90. {
  91. ENTER("fifo_add_command");
  92. int a_status = pthread_mutex_lock(&my_mutex);
  93. espeak_ERROR a_error = EE_OK;
  94. if (!a_status)
  95. {
  96. SHOW_TIME("fifo_add_command > locked\n");
  97. a_error = push(the_command);
  98. SHOW_TIME("fifo_add_command > unlocking\n");
  99. a_status = pthread_mutex_unlock(&my_mutex);
  100. }
  101. if (!a_status && !my_command_is_running && (a_error == EE_OK))
  102. {
  103. // quit when command is actually started
  104. // (for possible forthcoming 'end of command' checks)
  105. SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
  106. sem_post(&my_sem_start_is_required);
  107. int val=1;
  108. while (val)
  109. {
  110. usleep(50000); // TBD: event?
  111. sem_getvalue(&my_sem_start_is_required, &val);
  112. }
  113. }
  114. if (a_status != 0)
  115. {
  116. a_error = EE_INTERNAL_ERROR;
  117. }
  118. SHOW_TIME("LEAVE fifo_add_command");
  119. return a_error;
  120. }
  121. //>
  122. //<fifo_add_commands
  123. espeak_ERROR fifo_add_commands (t_espeak_command* command1, t_espeak_command* command2)
  124. {
  125. ENTER("fifo_add_command");
  126. int a_status = pthread_mutex_lock(&my_mutex);
  127. espeak_ERROR a_error = EE_OK;
  128. if (!a_status)
  129. {
  130. SHOW_TIME("fifo_add_commands > locked\n");
  131. if (node_counter+1 >= MAX_NODE_COUNTER)
  132. {
  133. SHOW("push > %s\n", "EE_BUFFER_FULL");
  134. a_error = EE_BUFFER_FULL;
  135. }
  136. else
  137. {
  138. push(command1);
  139. push(command2);
  140. }
  141. SHOW_TIME("fifo_add_command > unlocking\n");
  142. a_status = pthread_mutex_unlock(&my_mutex);
  143. }
  144. if (!a_status && !my_command_is_running && (a_error == EE_OK))
  145. {
  146. // quit when one command is actually started
  147. // (for possible forthcoming 'end of command' checks)
  148. SHOW_TIME("fifo_add_command > post my_sem_start_is_required\n");
  149. sem_post(&my_sem_start_is_required);
  150. int val=1;
  151. while (val)
  152. {
  153. usleep(50000); // TBD: event?
  154. sem_getvalue(&my_sem_start_is_required, &val);
  155. }
  156. }
  157. if (a_status != 0)
  158. {
  159. a_error = EE_INTERNAL_ERROR;
  160. }
  161. SHOW_TIME("LEAVE fifo_add_commands");
  162. return a_error;
  163. }
  164. //>
  165. //<fifo_stop
  166. espeak_ERROR fifo_stop ()
  167. {
  168. ENTER("fifo_stop");
  169. int a_command_is_running = 0;
  170. int a_status = pthread_mutex_lock(&my_mutex);
  171. SHOW_TIME("fifo_stop > locked\n");
  172. if (a_status != 0)
  173. {
  174. return EE_INTERNAL_ERROR;
  175. }
  176. if (my_command_is_running)
  177. {
  178. a_command_is_running = 1;
  179. my_stop_is_required = 1;
  180. SHOW_TIME("fifo_stop > my_stop_is_required = 1\n");
  181. }
  182. SHOW_TIME("fifo_stop > unlocking\n");
  183. a_status = pthread_mutex_unlock(&my_mutex);
  184. if (a_status != 0)
  185. {
  186. return EE_INTERNAL_ERROR;
  187. }
  188. if (a_command_is_running)
  189. {
  190. SHOW_TIME("fifo_stop > wait for my_sem_stop_is_acknowledged\n");
  191. while ((sem_wait(&my_sem_stop_is_acknowledged) == -1) && errno == EINTR)
  192. {
  193. continue; // Restart when interrupted by handler
  194. }
  195. SHOW_TIME("fifo_stop > get my_sem_stop_is_acknowledged\n");
  196. }
  197. SHOW_TIME("fifo_stop > my_stop_is_required = 0\n");
  198. my_stop_is_required = 0;
  199. SHOW_TIME("LEAVE fifo_stop\n");
  200. return EE_OK;
  201. }
  202. //>
  203. //<fifo_is_speaking
  204. int fifo_is_busy ()
  205. {
  206. // ENTER("isSpeaking");
  207. // int aResult = (int) (my_command_is_running || WaveIsPlaying());
  208. SHOW("fifo_is_busy > aResult = %d\n",my_command_is_running);
  209. return my_command_is_running;
  210. }
  211. // int pause ()
  212. // {
  213. // ENTER("pause");
  214. // // TBD
  215. // // if (espeakPause (espeakHandle, 1))
  216. // return true;
  217. // }
  218. // int resume ()
  219. // {
  220. // ENTER("resume");
  221. // // TBD
  222. // // if (espeakPause (espeakHandle, 0))
  223. // return true;
  224. // }
  225. //>
  226. //<sleep_until_start_request_or_inactivity
  227. int sleep_until_start_request_or_inactivity()
  228. {
  229. SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > ENTER");
  230. int a_start_is_required=0;
  231. // Wait for the start request (my_sem_start_is_required).
  232. // Besides this, if the audio stream is still busy,
  233. // check from time to time its end.
  234. // The end of the stream is confirmed by several checks
  235. // for filtering underflow.
  236. //
  237. int i=0;
  238. while((i<= MAX_INACTIVITY_CHECK) && !a_start_is_required)
  239. {
  240. if (wave_is_busy( NULL) )
  241. {
  242. i = 0;
  243. }
  244. else
  245. {
  246. i++;
  247. }
  248. int err=0;
  249. struct timespec ts, to;
  250. struct timeval tv;
  251. clock_gettime2( &ts);
  252. to.tv_sec = ts.tv_sec;
  253. to.tv_nsec = ts.tv_nsec;
  254. add_time_in_ms( &ts, INACTIVITY_TIMEOUT);
  255. SHOW("fifo > sleep_until_start_request_or_inactivity > start sem_timedwait (start_is_required) from %d.%09lu to %d.%09lu \n",
  256. to.tv_sec, to.tv_nsec,
  257. ts.tv_sec, ts.tv_nsec);
  258. while ((err = sem_timedwait(&my_sem_start_is_required, &ts)) == -1
  259. && errno == EINTR)
  260. {
  261. continue;
  262. }
  263. assert (gettimeofday(&tv, NULL) != -1);
  264. SHOW("fifo > sleep_until_start_request_or_inactivity > stop sem_timedwait (start_is_required, err=%d) %d.%09lu \n", err,
  265. tv.tv_sec, tv.tv_usec*1000);
  266. if (err==0)
  267. {
  268. a_start_is_required = 1;
  269. }
  270. }
  271. SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > LEAVE");
  272. return a_start_is_required;
  273. }
  274. //>
  275. //<close_stream
  276. static void close_stream()
  277. {
  278. SHOW_TIME("fifo > close_stream > ENTER\n");
  279. // Warning: a wave_close can be already required by
  280. // an external command (espeak_Cancel + fifo_stop), if so:
  281. // my_stop_is_required = 1;
  282. int a_status = pthread_mutex_lock(&my_mutex);
  283. assert (!a_status);
  284. int a_stop_is_required = my_stop_is_required;
  285. if (!a_stop_is_required)
  286. {
  287. my_command_is_running = 1;
  288. }
  289. a_status = pthread_mutex_unlock(&my_mutex);
  290. if (!a_stop_is_required)
  291. {
  292. wave_close(NULL);
  293. int a_status = pthread_mutex_lock(&my_mutex);
  294. assert (!a_status);
  295. my_command_is_running = 0;
  296. a_stop_is_required = my_stop_is_required;
  297. a_status = pthread_mutex_unlock(&my_mutex);
  298. if (a_stop_is_required)
  299. {
  300. // acknowledge the stop request
  301. SHOW_TIME("fifo > close_stream > post my_sem_stop_is_acknowledged\n");
  302. int a_status = sem_post(&my_sem_stop_is_acknowledged);
  303. assert( a_status != -1);
  304. }
  305. }
  306. SHOW_TIME("fifo > close_stream > LEAVE\n");
  307. }
  308. //>
  309. //<say_thread
  310. static void* say_thread(void*)
  311. {
  312. ENTER("say_thread");
  313. SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");
  314. // announce that thread is started
  315. sem_post(&my_sem_stop_is_acknowledged);
  316. int look_for_inactivity=0;
  317. while(1)
  318. {
  319. SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");
  320. int a_start_is_required = 0;
  321. if (look_for_inactivity)
  322. {
  323. a_start_is_required = sleep_until_start_request_or_inactivity();
  324. if (!a_start_is_required)
  325. {
  326. close_stream();
  327. }
  328. }
  329. look_for_inactivity = 1;
  330. if (!a_start_is_required)
  331. {
  332. while ((sem_wait(&my_sem_start_is_required) == -1) && errno == EINTR)
  333. {
  334. continue; // Restart when interrupted by handler
  335. }
  336. }
  337. SHOW_TIME("say_thread > get my_sem_start_is_required\n");
  338. SHOW_TIME("say_thread > my_command_is_running = 1\n");
  339. my_command_is_running = 1;
  340. while( my_command_is_running)
  341. {
  342. SHOW_TIME("say_thread > locking\n");
  343. int a_status = pthread_mutex_lock(&my_mutex);
  344. assert (!a_status);
  345. t_espeak_command* a_command = (t_espeak_command*)pop();
  346. if (a_command == NULL)
  347. {
  348. SHOW_TIME("say_thread > text empty (talking=0) \n");
  349. a_status = pthread_mutex_unlock(&my_mutex);
  350. SHOW_TIME("say_thread > unlocked\n");
  351. SHOW_TIME("say_thread > my_command_is_running = 0\n");
  352. my_command_is_running = 0;
  353. }
  354. else
  355. {
  356. display_espeak_command(a_command);
  357. // purge start semaphore
  358. SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
  359. while(0 == sem_trywait(&my_sem_start_is_required))
  360. {
  361. };
  362. if (my_stop_is_required)
  363. {
  364. SHOW_TIME("say_thread > my_command_is_running = 0\n");
  365. my_command_is_running = 0;
  366. }
  367. SHOW_TIME("say_thread > unlocking\n");
  368. a_status = pthread_mutex_unlock(&my_mutex);
  369. if (my_command_is_running)
  370. {
  371. process_espeak_command(a_command);
  372. }
  373. delete_espeak_command(a_command);
  374. }
  375. }
  376. if (my_stop_is_required)
  377. {
  378. // no mutex required since the stop command is synchronous
  379. // and waiting for my_sem_stop_is_acknowledged
  380. init();
  381. // purge start semaphore
  382. SHOW_TIME("say_thread > purge my_sem_start_is_required\n");
  383. while(0==sem_trywait(&my_sem_start_is_required))
  384. {
  385. };
  386. // acknowledge the stop request
  387. SHOW_TIME("say_thread > post my_sem_stop_is_acknowledged\n");
  388. int a_status = sem_post(&my_sem_stop_is_acknowledged);
  389. assert( a_status != -1);
  390. }
  391. // and wait for the next start
  392. SHOW_TIME("say_thread > wait for my_sem_start_is_required\n");
  393. }
  394. return NULL;
  395. }
  396. int fifo_is_command_enabled()
  397. {
  398. SHOW("ENTER fifo_is_command_enabled=%d\n",(int)(0 == my_stop_is_required));
  399. return (0 == my_stop_is_required);
  400. }
  401. //>
  402. //<fifo
  403. typedef struct t_node
  404. {
  405. t_espeak_command* data;
  406. t_node *next;
  407. } node;
  408. static node* head=NULL;
  409. static node* tail=NULL;
  410. // return 1 if ok, 0 otherwise
  411. static espeak_ERROR push(t_espeak_command* the_command)
  412. {
  413. ENTER("fifo > push");
  414. assert((!head && !tail) || (head && tail));
  415. if (the_command == NULL)
  416. {
  417. SHOW("push > command=0x%x\n", NULL);
  418. return EE_INTERNAL_ERROR;
  419. }
  420. if (node_counter >= MAX_NODE_COUNTER)
  421. {
  422. SHOW("push > %s\n", "EE_BUFFER_FULL");
  423. return EE_BUFFER_FULL;
  424. }
  425. node *n = (node *)malloc(sizeof(node));
  426. if (n == NULL)
  427. {
  428. return EE_INTERNAL_ERROR;
  429. }
  430. if (head == NULL)
  431. {
  432. head = n;
  433. tail = n;
  434. }
  435. else
  436. {
  437. tail->next = n;
  438. tail = n;
  439. }
  440. tail->next = NULL;
  441. tail->data = the_command;
  442. node_counter++;
  443. SHOW("push > counter=%d\n",node_counter);
  444. the_command->state = CS_PENDING;
  445. display_espeak_command(the_command);
  446. return EE_OK;
  447. }
  448. static t_espeak_command* pop()
  449. {
  450. ENTER("fifo > pop");
  451. t_espeak_command* the_command = NULL;
  452. assert((!head && !tail) || (head && tail));
  453. if (head != NULL)
  454. {
  455. node* n = head;
  456. the_command = n->data;
  457. head = n->next;
  458. free(n);
  459. node_counter--;
  460. SHOW("pop > command=0x%x (counter=%d)\n",the_command, node_counter);
  461. }
  462. if(head == NULL)
  463. {
  464. tail = NULL;
  465. }
  466. display_espeak_command(the_command);
  467. return the_command;
  468. }
  469. static void init()
  470. {
  471. ENTER("fifo > init");
  472. while (delete_espeak_command( pop() ))
  473. {}
  474. node_counter = 0;
  475. }
  476. //>
  477. //<fifo_init
  478. void fifo_terminate()
  479. {
  480. ENTER("fifo_terminate");
  481. pthread_cancel(my_thread);
  482. pthread_join(my_thread,NULL);
  483. pthread_mutex_destroy(&my_mutex);
  484. sem_destroy(&my_sem_start_is_required);
  485. sem_destroy(&my_sem_stop_is_acknowledged);
  486. init(); // purge fifo
  487. }
  488. #endif
  489. //>