summaryrefslogtreecommitdiff
path: root/apps/talk.c
diff options
context:
space:
mode:
authorStéphane Doyon <s.doyon@videotron.ca>2008-07-15 14:06:11 +0000
committerStéphane Doyon <s.doyon@videotron.ca>2008-07-15 14:06:11 +0000
commitc893affeefa35975c916a222d20a989f31555646 (patch)
tree72db68190ff77e70e0d9ffc0df4753a24b2261e1 /apps/talk.c
parent4aafed43d40d72315ad314b71737b169f8dbdf22 (diff)
downloadrockbox-c893affeefa35975c916a222d20a989f31555646.tar.gz
rockbox-c893affeefa35975c916a222d20a989f31555646.zip
Accept FS#8918: Voice multiple thumbnails and talk race fixes.
-Allows loading multiple thumbnails back-to-back in the one thumbnail buffer. -Mutex to prevent race conditions with talk queue indices and thumbnail buffer state. -Synchronous shutup. -Shutup is a noop if no voice is queued. -mp3_play_stop() does nothing until the audio thread is ready. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18046 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/talk.c')
-rw-r--r--apps/talk.c70
1 files changed, 60 insertions, 10 deletions
diff --git a/apps/talk.c b/apps/talk.c
index 61dafb0c6c..f84ecd0ef5 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -44,6 +44,7 @@
44#include "playback.h" 44#include "playback.h"
45#endif 45#endif
46#include "debug.h" 46#include "debug.h"
47#include "kernel.h"
47 48
48 49
49/* Memory layout varies between targets because the 50/* Memory layout varies between targets because the
@@ -110,14 +111,27 @@ struct queue_entry /* one entry of the internal queue */
110 111
111/***************** Globals *****************/ 112/***************** Globals *****************/
112 113
113static unsigned char* p_thumbnail = NULL; /* buffer for thumbnail */ 114static unsigned char* p_thumbnail = NULL; /* buffer for thumbnails */
114static long size_for_thumbnail; /* leftover buffer size for it */ 115/* Multiple thumbnails can be loaded back-to-back in this buffer. */
116static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in
117 thumbnail buffer */
118static long size_for_thumbnail; /* total thumbnail buffer size */
115static struct voicefile* p_voicefile; /* loaded voicefile */ 119static struct voicefile* p_voicefile; /* loaded voicefile */
116static bool has_voicefile; /* a voicefile file is present */ 120static bool has_voicefile; /* a voicefile file is present */
121static bool need_shutup; /* is there possibly any voice playing to be shutup */
117static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */ 122static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */
118static bool force_enqueue_next; /* enqueue next utterance even if enqueue is false */ 123static bool force_enqueue_next; /* enqueue next utterance even if enqueue is false */
119static int queue_write; /* write index of queue, by application */ 124static int queue_write; /* write index of queue, by application */
120static int queue_read; /* read index of queue, by ISR context */ 125static int queue_read; /* read index of queue, by ISR context */
126#if CONFIG_CODEC == SWCODEC
127struct mutex queue_mutex SHAREDBSS_ATTR; /* protects queue_read, queue_write
128 and thumbnail_buf_used */
129#define talk_queue_lock() ({ mutex_lock(&queue_mutex); })
130#define talk_queue_unlock() ({ mutex_unlock(&queue_mutex); })
131#else
132#define talk_queue_lock() ({ })
133#define talk_queue_unlock() ({ })
134#endif /* CONFIG_CODEC */
121static int sent; /* how many bytes handed over to playback, owned by ISR */ 135static int sent; /* how many bytes handed over to playback, owned by ISR */
122static unsigned char curr_hd[3]; /* current frame header, for re-sync */ 136static unsigned char curr_hd[3]; /* current frame header, for re-sync */
123static int filehandle = -1; /* global, so the MMC variant can keep the file open */ 137static int filehandle = -1; /* global, so the MMC variant can keep the file open */
@@ -299,7 +313,11 @@ static void mp3_callback(unsigned char** start, size_t* size)
299 *size = sent; 313 *size = sent;
300 return; 314 return;
301 } 315 }
302 else if (sent > 0) /* go to next entry */ 316 talk_queue_lock();
317 if(p_thumbnail
318 && queue[queue_read].buf == p_thumbnail +thumbnail_buf_used)
319 thumbnail_buf_used = 0;
320 if (sent > 0) /* go to next entry */
303 { 321 {
304 queue_read = (queue_read + 1) & QUEUE_MASK; 322 queue_read = (queue_read + 1) & QUEUE_MASK;
305 } 323 }
@@ -321,7 +339,8 @@ re_check:
321 } 339 }
322 else if (p_silence != NULL /* silence clip available */ 340 else if (p_silence != NULL /* silence clip available */
323 && p_lastclip != p_silence /* previous clip wasn't silence */ 341 && p_lastclip != p_silence /* previous clip wasn't silence */
324 && p_lastclip != p_thumbnail) /* ..or thumbnail */ 342 && !(p_lastclip >= p_thumbnail /* ..or thumbnail */
343 && p_lastclip < p_thumbnail +size_for_thumbnail))
325 { /* add silence clip when queue runs empty playing a voice clip */ 344 { /* add silence clip when queue runs empty playing a voice clip */
326 queue[queue_write].buf = p_silence; 345 queue[queue_write].buf = p_silence;
327 queue[queue_write].len = silence_len; 346 queue[queue_write].len = silence_len;
@@ -333,6 +352,7 @@ re_check:
333 { 352 {
334 *size = 0; /* end of data */ 353 *size = 0; /* end of data */
335 } 354 }
355 talk_queue_unlock();
336} 356}
337 357
338/***************** Public routines *****************/ 358/***************** Public routines *****************/
@@ -388,6 +408,7 @@ void talk_force_shutup(void)
388 DTCR3 = sent; /* let the DMA finish this frame */ 408 DTCR3 = sent; /* let the DMA finish this frame */
389 CHCR3 |= 0x0001; /* re-enable DMA */ 409 CHCR3 |= 0x0001; /* re-enable DMA */
390#endif /* CONFIG_CPU == SH7034 */ 410#endif /* CONFIG_CPU == SH7034 */
411 thumbnail_buf_used = 0;
391 return; 412 return;
392 } 413 }
393 } 414 }
@@ -395,14 +416,17 @@ void talk_force_shutup(void)
395 416
396 /* Either SWCODEC, or MAS had nothing to do (was frame boundary or not our clip) */ 417 /* Either SWCODEC, or MAS had nothing to do (was frame boundary or not our clip) */
397 mp3_play_stop(); 418 mp3_play_stop();
419 talk_queue_lock();
398 queue_write = queue_read = 0; /* reset the queue */ 420 queue_write = queue_read = 0; /* reset the queue */
399 return; 421 thumbnail_buf_used = 0;
422 talk_queue_unlock();
423 need_shutup = false;
400} 424}
401 425
402/* Shutup the voice, except if force_enqueue_next is set. */ 426/* Shutup the voice, except if force_enqueue_next is set. */
403void talk_shutup(void) 427void talk_shutup(void)
404{ 428{
405 if (!force_enqueue_next) 429 if (need_shutup && !force_enqueue_next)
406 talk_force_shutup(); 430 talk_force_shutup();
407} 431}
408 432
@@ -423,6 +447,7 @@ static void queue_clip(unsigned char* buf, long size, bool enqueue)
423 /* disable the DMA temporarily, to be safe of race condition */ 447 /* disable the DMA temporarily, to be safe of race condition */
424 CHCR3 &= ~0x0001; 448 CHCR3 &= ~0x0001;
425#endif 449#endif
450 talk_queue_lock();
426 queue_level = QUEUE_LEVEL; /* check old level */ 451 queue_level = QUEUE_LEVEL; /* check old level */
427 452
428 if (queue_level < QUEUE_SIZE - 1) /* space left? */ 453 if (queue_level < QUEUE_SIZE - 1) /* space left? */
@@ -431,7 +456,8 @@ static void queue_clip(unsigned char* buf, long size, bool enqueue)
431 queue[queue_write].len = size; 456 queue[queue_write].len = size;
432 queue_write = (queue_write + 1) & QUEUE_MASK; 457 queue_write = (queue_write + 1) & QUEUE_MASK;
433 } 458 }
434 459 talk_queue_unlock();
460
435 if (queue_level == 0) 461 if (queue_level == 0)
436 { /* queue was empty, we have to do the initial start */ 462 { /* queue was empty, we have to do the initial start */
437 p_lastclip = buf; 463 p_lastclip = buf;
@@ -453,6 +479,8 @@ static void queue_clip(unsigned char* buf, long size, bool enqueue)
453#endif 479#endif
454 } 480 }
455 481
482 need_shutup = true;
483
456 return; 484 return;
457} 485}
458 486
@@ -476,6 +504,7 @@ static void reset_state(void)
476 p_thumbnail = audiobuf; 504 p_thumbnail = audiobuf;
477 size_for_thumbnail = audiobufend - audiobuf; 505 size_for_thumbnail = audiobufend - audiobuf;
478#endif 506#endif
507 thumbnail_buf_used = 0;
479 p_silence = NULL; /* pause clip not accessible */ 508 p_silence = NULL; /* pause clip not accessible */
480} 509}
481 510
@@ -499,6 +528,11 @@ void talk_init(void)
499 } 528 }
500#endif 529#endif
501 530
531#if CONFIG_CODEC == SWCODEC
532 if(!talk_initialized)
533 mutex_init(&queue_mutex);
534#endif /* CONFIG_CODEC == SWCODEC */
535
502 talk_initialized = true; 536 talk_initialized = true;
503 strncpy((char *) last_lang, (char *)global_settings.lang_file, 537 strncpy((char *) last_lang, (char *)global_settings.lang_file,
504 MAX_FILENAME); 538 MAX_FILENAME);
@@ -625,6 +659,7 @@ int talk_file(const char* filename, bool enqueue)
625{ 659{
626 int fd; 660 int fd;
627 int size; 661 int size;
662 int thumb_used;
628#if CONFIG_CODEC != SWCODEC 663#if CONFIG_CODEC != SWCODEC
629 struct mp3entry info; 664 struct mp3entry info;
630#endif 665#endif
@@ -646,27 +681,42 @@ int talk_file(const char* filename, bool enqueue)
646 } 681 }
647#endif 682#endif
648 683
684 if (!enqueue)
685 /* shutup now to free the thumbnail buffer */
686 talk_shutup();
687
649 fd = open(filename, O_RDONLY); 688 fd = open(filename, O_RDONLY);
650 if (fd < 0) /* failed to open */ 689 if (fd < 0) /* failed to open */
651 { 690 {
652 return 0; 691 return 0;
653 } 692 }
654 693
694 thumb_used = thumbnail_buf_used;
695 if(filesize(fd) > size_for_thumbnail -thumb_used)
696 { /* Don't play truncated clips */
697 close(fd);
698 return 0;
699 }
700
655#if CONFIG_CODEC != SWCODEC 701#if CONFIG_CODEC != SWCODEC
656 lseek(fd, info.first_frame_offset, SEEK_SET); /* behind ID data */ 702 lseek(fd, info.first_frame_offset, SEEK_SET); /* behind ID data */
657#endif 703#endif
658 704
659 size = read(fd, p_thumbnail, size_for_thumbnail); 705 size = read(fd, p_thumbnail +thumb_used,
706 size_for_thumbnail -thumb_used);
660 close(fd); 707 close(fd);
661 708
662 /* ToDo: find audio, skip ID headers and trailers */ 709 /* ToDo: find audio, skip ID headers and trailers */
663 710
664 if (size > 0 && size != size_for_thumbnail) /* Don't play missing or truncated clips */ 711 if (size > 0) /* Don't play missing clips */
665 { 712 {
666#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) 713#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
667 bitswap(p_thumbnail, size); 714 bitswap(p_thumbnail, size);
668#endif 715#endif
669 queue_clip(p_thumbnail, size, enqueue); 716 talk_queue_lock();
717 thumbnail_buf_used = thumb_used +size;
718 talk_queue_unlock();
719 queue_clip(p_thumbnail +thumb_used, size, true);
670 } 720 }
671 721
672 return size; 722 return size;