summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/playback.c10
-rw-r--r--apps/playback.h2
-rw-r--r--apps/talk.c70
-rw-r--r--apps/voice_thread.c21
4 files changed, 76 insertions, 27 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 937bf05394..daa9ab3f2e 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -2599,13 +2599,7 @@ void audio_init(void)
2599 2599
2600} /* audio_init */ 2600} /* audio_init */
2601 2601
2602void audio_wait_for_init(void) 2602bool audio_is_thread_ready(void)
2603{ 2603{
2604 /* audio thread will only set this once after it finished the final 2604 return audio_thread_ready;
2605 * audio hardware init so this little construct is safe - even
2606 * cross-core. */
2607 while (!audio_thread_ready)
2608 {
2609 sleep(0);
2610 }
2611} 2605}
diff --git a/apps/playback.h b/apps/playback.h
index 66d96b4084..d9f29cc56a 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -28,7 +28,7 @@
28/* Functions */ 28/* Functions */
29const char *get_codec_filename(int cod_spec); 29const char *get_codec_filename(int cod_spec);
30void voice_wait(void); 30void voice_wait(void);
31void audio_wait_for_init(void); 31bool audio_is_thread_ready(void);
32int audio_track_count(void); 32int audio_track_count(void);
33long audio_filebufused(void); 33long audio_filebufused(void);
34void audio_pre_ff_rewind(void); 34void audio_pre_ff_rewind(void);
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;
diff --git a/apps/voice_thread.c b/apps/voice_thread.c
index 8d08e7744b..aeffa5bd7c 100644
--- a/apps/voice_thread.c
+++ b/apps/voice_thread.c
@@ -136,11 +136,12 @@ void mp3_play_data(const unsigned char* start, int size,
136/* Stop current voice clip from playing */ 136/* Stop current voice clip from playing */
137void mp3_play_stop(void) 137void mp3_play_stop(void)
138{ 138{
139 mutex_lock(&voice_mutex); /* Sync against voice_stop */ 139 if(!audio_is_thread_ready())
140 return;
140 141
141 LOGFQUEUE("mp3 > voice Q_VOICE_STOP: 1"); 142 mutex_lock(&voice_mutex); /* Sync against voice_stop */
142 queue_remove_from_head(&voice_queue, Q_VOICE_STOP); 143 LOGFQUEUE("mp3 >| voice Q_VOICE_STOP: 1");
143 queue_post(&voice_queue, Q_VOICE_STOP, 1); 144 queue_send(&voice_queue, Q_VOICE_STOP, 1);
144 145
145 mutex_unlock(&voice_mutex); 146 mutex_unlock(&voice_mutex);
146} 147}
@@ -167,8 +168,7 @@ void voice_stop(void)
167 mutex_lock(&voice_mutex); 168 mutex_lock(&voice_mutex);
168 169
169 /* Stop the output and current clip */ 170 /* Stop the output and current clip */
170 LOGFQUEUE("mp3 >| voice Q_VOICE_STOP: 1"); 171 mp3_play_stop();
171 queue_send(&voice_queue, Q_VOICE_STOP, 1);
172 172
173 /* Careful if using sync objects in talk.c - make sure locking order is 173 /* Careful if using sync objects in talk.c - make sure locking order is
174 * observed with one or the other always granted first */ 174 * observed with one or the other always granted first */
@@ -298,8 +298,13 @@ static void voice_thread(void)
298 struct voice_thread_data td; 298 struct voice_thread_data td;
299 299
300 voice_data_init(&td); 300 voice_data_init(&td);
301 audio_wait_for_init(); 301
302 302 /* audio thread will only set this once after it finished the final
303 * audio hardware init so this little construct is safe - even
304 * cross-core. */
305 while (!audio_is_thread_ready())
306 sleep(0);
307
303 goto message_wait; 308 goto message_wait;
304 309
305 while (1) 310 while (1)