summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2014-02-02 16:58:28 +0100
committerThomas Martitz <kugel@rockbox.org>2014-02-02 19:40:39 +0100
commitaf02a674c539ee76260be543c000637ffa6ce2af (patch)
tree5a8d1ed7879fcb503c6b3b119f4ad488c240f31a
parent03f373c9cd370e77766a511c574b3cf7bf8d9226 (diff)
downloadrockbox-af02a674c539ee76260be543c000637ffa6ce2af.tar.gz
rockbox-af02a674c539ee76260be543c000637ffa6ce2af.zip
talk.c: The new cache management is good enough to use it for .talk clips as well.
This unifies the talk.c for all possible voice payload. .talk clips are placed onto the same unified clip cache, along with normal clips. This allows for more effecient memory usage. The cache handling makes a slight difference between normal clips and .talk ones: .talk clips can be cached multiple and are always freed first.The extra logic to avoid loading multiple copies of .talks is not necessary because the will be freed first anyway. Change-Id: I88d056a0a613b129f5875f50fdb757b58bac0a42
-rw-r--r--apps/talk.c269
1 files changed, 104 insertions, 165 deletions
diff --git a/apps/talk.c b/apps/talk.c
index 820cb75c8d..a49de09e84 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -80,14 +80,6 @@ const char* const file_thumbnail_ext = ".talk";
80 80
81#define LOADED_MASK 0x80000000 /* MSB */ 81#define LOADED_MASK 0x80000000 /* MSB */
82 82
83/* swcodec: cap thumbnail buffer to MAX_THUMNAIL_BUFSIZE since audio keeps
84 * playing while voice
85 * hwcodec: just use whatever is left in the audiobuffer, music
86 * playback is impossible => no cap */
87#if CONFIG_CODEC == SWCODEC
88#define MAX_THUMBNAIL_BUFSIZE 0x10000
89#endif
90
91#define DEFAULT_VOICE_LANG "english" 83#define DEFAULT_VOICE_LANG "english"
92 84
93/***************** Data types *****************/ 85/***************** Data types *****************/
@@ -124,13 +116,14 @@ struct voicefile_header /* file format of our voice file */
124#endif 116#endif
125 117
126#ifndef MAX_CLIP_BUFFER_SIZE 118#ifndef MAX_CLIP_BUFFER_SIZE
127#define MAX_CLIP_BUFFER_SIZE (1<<30) /* 1GB should be enough for everybody */ 119/* 1GB should be enough for everybody; will be capped to voicefile size */
120#define MAX_CLIP_BUFFER_SIZE (1<<30)
128#endif 121#endif
122#define THUMBNAIL_RESERVE (50000)
129 123
130/* Multiple thumbnails can be loaded back-to-back in this buffer. */ 124/* Multiple thumbnails can be loaded back-to-back in this buffer. */
131static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in 125static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in
132 thumbnail buffer */ 126 thumbnail buffer */
133static long size_for_thumbnail; /* total thumbnail buffer size */
134static struct voicefile_header voicefile; /* loaded voicefile */ 127static struct voicefile_header voicefile; /* loaded voicefile */
135static bool has_voicefile; /* a voicefile file is present */ 128static bool has_voicefile; /* a voicefile file is present */
136static bool need_shutup; /* is there possibly any voice playing to be shutup */ 129static bool need_shutup; /* is there possibly any voice playing to be shutup */
@@ -158,16 +151,9 @@ static unsigned long voicefile_size, voicebuf_size;
158 151
159struct queue_entry /* one entry of the internal queue */ 152struct queue_entry /* one entry of the internal queue */
160{ 153{
161 int offset; /* actually a buflib handle if type == HANDLE */ 154 int handle; /* buflib handle to the clip data */
162 int length; /* total length of the clip */ 155 int length; /* total length of the clip */
163 int remaining; /* bytes that still need to be deoded */ 156 int remaining; /* bytes that still need to be deoded */
164 /* for large QUEUE_SIZE values it might be worthwhile to merge the type
165 * into the bits of the above members (as a space saver). For small values
166 * the required extra code outweights this so it's not done here */
167 enum offset_type {
168 TALK_HANDLE,
169 THUMB_OFFSET,
170 } type;
171}; 157};
172 158
173static struct buflib_context clip_ctx; 159static struct buflib_context clip_ctx;
@@ -186,7 +172,7 @@ static struct queue_entry silence, *last_clip;
186 172
187/***************** Private implementation *****************/ 173/***************** Private implementation *****************/
188 174
189static int index_handle, talk_handle, thumb_handle; 175static int index_handle, talk_handle;
190 176
191static int move_callback(int handle, void *current, void *new) 177static int move_callback(int handle, void *current, void *new)
192{ 178{
@@ -282,34 +268,12 @@ static int shrink_callback(int handle, unsigned hints, void *start, size_t old_s
282 return BUFLIB_CB_CANNOT_SHRINK; 268 return BUFLIB_CB_CANNOT_SHRINK;
283} 269}
284 270
285static int thumb_shrink_callback(int handle, unsigned hints, void *start, size_t old_size)
286{
287 (void)start;(void)old_size;(void)hints;
288
289 if (handle == thumb_handle && thumbnail_buf_used == 0)
290 {
291 mutex_lock(&read_buffer_mutex);
292 thumb_handle = core_free(handle);
293 mutex_unlock(&read_buffer_mutex);
294 return BUFLIB_CB_OK;
295 }
296
297 return BUFLIB_CB_CANNOT_SHRINK;
298}
299
300
301
302static struct buflib_callbacks talk_ops = { 271static struct buflib_callbacks talk_ops = {
303 .move_callback = move_callback, 272 .move_callback = move_callback,
304 .sync_callback = sync_callback, 273 .sync_callback = sync_callback,
305 .shrink_callback = shrink_callback, 274 .shrink_callback = shrink_callback,
306}; 275};
307 276
308static struct buflib_callbacks thumb_ops = {
309 .move_callback = move_callback,
310 .sync_callback = sync_callback,
311 .shrink_callback = thumb_shrink_callback,
312};
313 277
314static int open_voicefile(void) 278static int open_voicefile(void)
315{ 279{
@@ -375,19 +339,31 @@ static int free_oldest_clip(void)
375 struct clip_cache_metadata *cc = buflib_get_data(&clip_ctx, metadata_table_handle); 339 struct clip_cache_metadata *cc = buflib_get_data(&clip_ctx, metadata_table_handle);
376 for(age = i = 0, now = current_tick; i < max_clips; i++) 340 for(age = i = 0, now = current_tick; i < max_clips; i++)
377 { 341 {
378 if (cc[i].handle && (now - cc[i].tick) > age 342 if (cc[i].handle)
379 && cc[i].voice_id != VOICE_PAUSE) /* never consider silence */
380 { 343 {
381 age = now - cc[i].tick; 344 if ((now - cc[i].tick) > age && cc[i].voice_id != VOICE_PAUSE)
382 oldest = i; 345 {
346 /* find the last-used clip but never consider silence */
347 age = now - cc[i].tick;
348 oldest = i;
349 }
350 else if (cc[i].voice_id == VOICEONLY_DELIMITER)
351 {
352 /* thumb clips are freed immediately */
353 oldest = i;
354 break;
355 }
383 } 356 }
384 } 357 }
358 /* free the last one if no oldest one could be determined */
385 cc = &cc[oldest]; 359 cc = &cc[oldest];
386 cc->handle = buflib_free(&clip_ctx, cc->handle); 360 cc->handle = buflib_free(&clip_ctx, cc->handle);
387 /* need to clear the LOADED bit too */ 361 /* need to clear the LOADED bit too (not for thumb clips) */
388 clipbuf = core_get_data(index_handle); 362 if (cc->voice_id != VOICEONLY_DELIMITER)
389 clipbuf[id2index(cc->voice_id)].size &= ~LOADED_MASK; 363 {
390 364 clipbuf = core_get_data(index_handle);
365 clipbuf[id2index(cc->voice_id)].size &= ~LOADED_MASK;
366 }
391 return oldest; 367 return oldest;
392} 368}
393 369
@@ -458,6 +434,8 @@ static void load_initial_clips(int fd)
458 int handle; 434 int handle;
459 struct clip_entry* clipbuf = core_get_data(index_handle); 435 struct clip_entry* clipbuf = core_get_data(index_handle);
460 size_t clipsize = clipbuf[index].size; 436 size_t clipsize = clipbuf[index].size;
437 ssize_t ret;
438
461 if (clipsize == 0) /* clip not included in voicefile */ 439 if (clipsize == 0) /* clip not included in voicefile */
462 continue; 440 continue;
463 441
@@ -465,7 +443,8 @@ static void load_initial_clips(int fd)
465 if (handle < 0) 443 if (handle < 0)
466 break; 444 break;
467 445
468 if (read_clip_data(fd, index, handle) < 0) 446 ret = read_clip_data(fd, index, handle);
447 if (ret < 0)
469 break; 448 break;
470 449
471 add_cache_entry(handle, i++, index2id(index)); 450 add_cache_entry(handle, i++, index2id(index));
@@ -480,7 +459,6 @@ static int get_clip(long id, struct queue_entry *q)
480 int retval = -1; 459 int retval = -1;
481 struct clip_entry* clipbuf; 460 struct clip_entry* clipbuf;
482 size_t clipsize; 461 size_t clipsize;
483 enum offset_type type;
484 462
485 index = id2index(id); 463 index = id2index(id);
486 if (index == -1) 464 if (index == -1)
@@ -521,12 +499,10 @@ static int get_clip(long id, struct queue_entry *q)
521 clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */ 499 clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
522 retval = cc[i].handle; 500 retval = cc[i].handle;
523 } 501 }
524 type = TALK_HANDLE;
525 502
526 q->offset = retval; 503 q->handle = retval;
527 q->length = clipsize; 504 q->length = clipsize;
528 q->remaining = clipsize; 505 q->remaining = clipsize;
529 q->type = type;
530 return 0; 506 return 0;
531} 507}
532 508
@@ -596,33 +572,6 @@ alloc_err:
596 index_handle = core_free(index_handle); 572 index_handle = core_free(index_handle);
597 return false; 573 return false;
598} 574}
599
600static bool alloc_thumbnail_buf(void)
601{
602 int handle;
603 size_t size;
604 if (thumb_handle > 0)
605 return true; /* nothing to do? */
606#if CONFIG_CODEC == SWCODEC
607 /* try to allocate the max. first, and take whatever we can get if that
608 * fails */
609 size = MAX_THUMBNAIL_BUFSIZE;
610 handle = core_alloc_ex("voice thumb", MAX_THUMBNAIL_BUFSIZE, &thumb_ops);
611 if (handle < 0)
612 {
613 size = core_allocatable();
614 handle = core_alloc_ex("voice thumb", size, &thumb_ops);
615 }
616#else
617 /* on HWCODEC, just use the rest of the remaining buffer,
618 * normal playback cannot happen anyway */
619 size = audio_buffer_available();
620 handle = core_alloc_ex("voice thumb", size, &thumb_ops);
621#endif
622 thumb_handle = handle;
623 size_for_thumbnail = (handle > 0) ? size : 0;
624 return handle > 0;
625}
626 575
627/* load the voice file into the mp3 buffer */ 576/* load the voice file into the mp3 buffer */
628static bool load_voicefile_index(int fd) 577static bool load_voicefile_index(int fd)
@@ -684,10 +633,6 @@ static bool load_voicefile_data(int fd)
684 * VOICE_PAUSE clip is specially handled */ 633 * VOICE_PAUSE clip is specially handled */
685 get_clip(VOICE_PAUSE, &silence); 634 get_clip(VOICE_PAUSE, &silence);
686 635
687 /* not an error if this fails here, might try again when the
688 * actual thumbnails are attempted to be played back */
689 alloc_thumbnail_buf();
690
691 return true; 636 return true;
692} 637}
693 638
@@ -701,18 +646,13 @@ static void* commit_transfer(struct queue_entry *qe, size_t *size)
701{ 646{
702 void *buf = NULL; /* shut up gcc */ 647 void *buf = NULL; /* shut up gcc */
703 static unsigned char *bufpos = commit_buffer; 648 static unsigned char *bufpos = commit_buffer;
704 int offset = qe->offset;
705#if CONFIG_CODEC != SWCODEC 649#if CONFIG_CODEC != SWCODEC
706 sent = MIN(qe->remaining, 0xFFFF); 650 sent = MIN(qe->remaining, 0xFFFF);
707#else 651#else
708 sent = qe->remaining; 652 sent = qe->remaining;
709#endif 653#endif
710 sent = MIN((size_t)sent, sizeof(commit_buffer)); 654 sent = MIN((size_t)sent, sizeof(commit_buffer));
711 switch (qe->type) 655 buf = buflib_get_data(&clip_ctx, qe->handle);
712 {
713 case TALK_HANDLE: buf = buflib_get_data(&clip_ctx, offset); break;
714 case THUMB_OFFSET: buf = core_get_data(thumb_handle) + offset; break;
715 }
716 /* adjust buffer position to what has been played already */ 656 /* adjust buffer position to what has been played already */
717 buf += (qe->length - qe->remaining); 657 buf += (qe->length - qe->remaining);
718 memcpy(bufpos, buf, sent); 658 memcpy(bufpos, buf, sent);
@@ -724,8 +664,8 @@ static void* commit_transfer(struct queue_entry *qe, size_t *size)
724 664
725static inline bool is_silence(struct queue_entry *qe) 665static inline bool is_silence(struct queue_entry *qe)
726{ 666{
727 if (silence.length > 0) /* silence clip available? */ 667 if (silence.handle > 0) /* silence clip available? */
728 return (qe->offset == silence.offset && qe->type == silence.type); 668 return (qe->handle == silence.handle);
729 else 669 else
730 return false; 670 return false;
731} 671}
@@ -743,21 +683,15 @@ static void mp3_callback(const void** start, size_t* size)
743 } 683 }
744 684
745 talk_queue_lock(); 685 talk_queue_lock();
746 /* check if thumbnails have been played */
747 if (qe->type == THUMB_OFFSET)
748 {
749 if (qe->remaining == 0 && (qe->length + qe->offset) == thumbnail_buf_used)
750 thumbnail_buf_used = 0;
751 }
752 686
753 /* increment read position for the just played clip */ 687 /* increment read position for the just played clip */
754 queue_read = (queue_read + 1) & QUEUE_MASK; 688 queue_read = (queue_read + 1) & QUEUE_MASK;
755 689
756 if (QUEUE_LEVEL == 0) 690 if (QUEUE_LEVEL == 0)
757 { 691 {
758 if (!is_silence(last_clip) && last_clip->type != THUMB_OFFSET) 692 if (!is_silence(last_clip))
759 { /* add silence clip when queue runs empty playing a voice clip, 693 { /* add silence clip when queue runs empty playing a voice clip,
760 * only if the previous clip wasn't silence or thumbnail */ 694 * only if the previous clip wasn't already silence */
761 queue[queue_write] = silence; 695 queue[queue_write] = silence;
762 queue_write = (queue_write + 1) & QUEUE_MASK; 696 queue_write = (queue_write + 1) & QUEUE_MASK;
763 } 697 }
@@ -793,7 +727,6 @@ void talk_force_shutup(void)
793 unsigned char* search; 727 unsigned char* search;
794 unsigned char* end; 728 unsigned char* end;
795 int len; 729 int len;
796 unsigned offset;
797 if (QUEUE_LEVEL == 0) /* has ended anyway */ 730 if (QUEUE_LEVEL == 0) /* has ended anyway */
798 return; 731 return;
799 732
@@ -802,13 +735,7 @@ void talk_force_shutup(void)
802#endif /* CONFIG_CPU == SH7034 */ 735#endif /* CONFIG_CPU == SH7034 */
803 /* search next frame boundary and continue up to there */ 736 /* search next frame boundary and continue up to there */
804 pos = search = mp3_get_pos(); 737 pos = search = mp3_get_pos();
805 offset = queue[queue_read].offset; 738 end = buflib_get_data(&clip_ctx, queue[queue_read].handle);
806 switch (queue[queue_read].type)
807 {
808 case THUMB_OFFSET: end = core_get_data(thumb_handle) + offset; break;
809 case TALK_HANDLE: end = buflib_get_data(&clip_ctx, offset); break;
810 default: end = NULL; /* shut up gcc */
811 }
812 len = queue[queue_read].length; 739 len = queue[queue_read].length;
813 740
814 if (pos >= end && pos <= (end+len)) /* really our clip? */ 741 if (pos >= end && pos <= (end+len)) /* really our clip? */
@@ -914,7 +841,6 @@ static void queue_clip(struct queue_entry *clip, bool enqueue)
914 return; 841 return;
915} 842}
916 843
917#if CONFIG_CODEC == SWCODEC
918/* return if a voice codec is required or not */ 844/* return if a voice codec is required or not */
919static bool talk_voice_required(void) 845static bool talk_voice_required(void)
920{ 846{
@@ -922,7 +848,6 @@ static bool talk_voice_required(void)
922 || (global_settings.talk_dir_clip) /* Thumbnail clips are required */ 848 || (global_settings.talk_dir_clip) /* Thumbnail clips are required */
923 || (global_settings.talk_file_clip); 849 || (global_settings.talk_file_clip);
924} 850}
925#endif
926 851
927/***************** Public implementation *****************/ 852/***************** Public implementation *****************/
928 853
@@ -951,7 +876,7 @@ void talk_init(void)
951 queue_write = queue_read = 0; /* reset the queue */ 876 queue_write = queue_read = 0; /* reset the queue */
952 memset(&voicefile, 0, sizeof(voicefile)); 877 memset(&voicefile, 0, sizeof(voicefile));
953 878
954 silence.offset = -1; /* pause clip not accessible */ 879 silence.handle = -1; /* pause clip not accessible */
955 voicefile_size = has_voicefile = 0; 880 voicefile_size = has_voicefile = 0;
956 /* need to free these as their size depends on the voice file, and 881 /* need to free these as their size depends on the voice file, and
957 * this function is called when the talk voice file changes */ 882 * this function is called when the talk voice file changes */
@@ -961,37 +886,46 @@ void talk_init(void)
961 * and so we can re-use it if it's already allocated in any event */ 886 * and so we can re-use it if it's already allocated in any event */
962 887
963 filehandle = open_voicefile(); 888 filehandle = open_voicefile();
964 if (filehandle < 0) 889 if (filehandle > 0)
965 return;
966
967 if (!load_voicefile_index(filehandle))
968 goto out;
969
970 /* Now determine the maximum buffer size needed for the voicefile.
971 * The below pretends the entire voicefile would be loaded. The buffer
972 * size is eventually capped later on in load_voicefile_data() */
973 int num_clips = voicefile.id1_max + voicefile.id2_max;
974 int non_empty = num_clips;
975 int total_size = 0, avg_size;
976 struct clip_entry *clips = core_get_data(index_handle);
977 /* check for the average clip size to estimate the maximum number of
978 * clips the buffer can hold */
979 for (int i = 0; i<num_clips; i++)
980 { 890 {
981 if (clips[i].size) 891 if (!load_voicefile_index(filehandle))
982 total_size += ALIGN_UP(clips[i].size, sizeof(void *)); 892 goto out;
983 else 893
984 non_empty -= 1; 894 /* Now determine the maximum buffer size needed for the voicefile.
895 * The below pretends the entire voicefile would be loaded. The buffer
896 * size is eventually capped later on in load_voicefile_data() */
897 int num_clips = voicefile.id1_max + voicefile.id2_max;
898 int non_empty = num_clips;
899 int total_size = 0, avg_size;
900 struct clip_entry *clips = core_get_data(index_handle);
901 /* check for the average clip size to estimate the maximum number of
902 * clips the buffer can hold */
903 for (int i = 0; i<num_clips; i++)
904 {
905 if (clips[i].size)
906 total_size += ALIGN_UP(clips[i].size, sizeof(void *));
907 else
908 non_empty -= 1;
909 }
910 avg_size = total_size / non_empty;
911 max_clips = MIN((int)(MAX_CLIP_BUFFER_SIZE/avg_size) + 1, non_empty);
912 /* account for possible thumb clips */
913 total_size += THUMBNAIL_RESERVE;
914 max_clips += 16;
915 voicefile_size = total_size;
916 has_voicefile = true;
985 } 917 }
986 avg_size = total_size / non_empty; 918 else if (talk_voice_required())
987 max_clips = MIN((int)(MAX_CLIP_BUFFER_SIZE/avg_size) + 1, non_empty); 919 {
988 voicefile_size = total_size; 920 /* create buffer just for thumb clips */
989 /* additionally to the clips we need a table to record the age of the clips 921 max_clips = 16;
922 voicefile_size = THUMBNAIL_RESERVE;
923 }
924 /* additionally to the clip we need a table to record the age of the clips
990 * so that, when memory is tight, only the most recently used ones are kept */ 925 * so that, when memory is tight, only the most recently used ones are kept */
991 voicefile_size += sizeof(struct clip_cache_metadata) * max_clips; 926 voicefile_size += sizeof(struct clip_cache_metadata) * max_clips;
992 /* compensate a bit for buflib alloc overhead. */ 927 /* compensate a bit for buflib alloc overhead. */
993 voicefile_size += BUFLIB_ALLOC_OVERHEAD * max_clips + 64; 928 voicefile_size += BUFLIB_ALLOC_OVERHEAD * max_clips + 64;
994 has_voicefile = true;
995 929
996 load_voicefile_data(filehandle); 930 load_voicefile_data(filehandle);
997 931
@@ -1003,7 +937,6 @@ void talk_init(void)
1003 937
1004out: 938out:
1005 close(filehandle); /* close again, this was just to detect presence */ 939 close(filehandle); /* close again, this was just to detect presence */
1006 filehandle = -1;
1007} 940}
1008 941
1009/* somebody else claims the mp3 buffer, e.g. for regular play/record */ 942/* somebody else claims the mp3 buffer, e.g. for regular play/record */
@@ -1035,10 +968,10 @@ int talk_id(int32_t id, bool enqueue)
1035 if (talk_handle <= 0 || index_handle <= 0) /* reload needed? */ 968 if (talk_handle <= 0 || index_handle <= 0) /* reload needed? */
1036 { 969 {
1037 int fd = open_voicefile(); 970 int fd = open_voicefile();
1038 if (fd < 0 971 if (fd < 0 || !load_voicefile_index(fd))
1039 || !load_voicefile_index(fd)
1040 || !load_voicefile_data(fd))
1041 return -1; 972 return -1;
973 load_voicefile_data(fd);
974 close(fd);
1042 } 975 }
1043 976
1044 if (id == -1) /* -1 is an indication for silence */ 977 if (id == -1) /* -1 is an indication for silence */
@@ -1100,7 +1033,7 @@ static int _talk_file(const char* filename,
1100{ 1033{
1101 int fd; 1034 int fd;
1102 int size; 1035 int size;
1103 int thumb_used; 1036 int handle, oldest = -1;
1104#if CONFIG_CODEC != SWCODEC 1037#if CONFIG_CODEC != SWCODEC
1105 struct mp3entry info; 1038 struct mp3entry info;
1106#endif 1039#endif
@@ -1110,9 +1043,8 @@ static int _talk_file(const char* filename,
1110 return -1; /* talking has been disabled */ 1043 return -1; /* talking has been disabled */
1111 if (!check_audio_status()) 1044 if (!check_audio_status())
1112 return -1; 1045 return -1;
1113 1046 if (talk_handle <= 0)
1114 if (!alloc_thumbnail_buf()) 1047 load_voicefile_data(-1);
1115 return -1;
1116 1048
1117#if CONFIG_CODEC != SWCODEC 1049#if CONFIG_CODEC != SWCODEC
1118 if(mp3info(&info, filename)) /* use this to find real start */ 1050 if(mp3info(&info, filename)) /* use this to find real start */
@@ -1130,19 +1062,17 @@ static int _talk_file(const char* filename,
1130 { 1062 {
1131 return 0; 1063 return 0;
1132 } 1064 }
1133 1065 size = filesize(fd);
1134 thumb_used = thumbnail_buf_used;
1135 if(filesize(fd) > size_for_thumbnail -thumb_used)
1136 { /* Don't play truncated clips */
1137 close(fd);
1138 return 0;
1139 }
1140 1066
1141#if CONFIG_CODEC != SWCODEC 1067#if CONFIG_CODEC != SWCODEC
1142 lseek(fd, info.first_frame_offset, SEEK_SET); /* behind ID data */ 1068 size -= lseek(fd, info.first_frame_offset, SEEK_SET); /* behind ID data */
1143#endif 1069#endif
1144 1070
1145 size = read_to_handle(fd, thumb_handle, thumb_used, size_for_thumbnail - thumb_used); 1071 /* free clips from cache until this one succeeds to allocate */
1072 while ((handle = buflib_alloc(&clip_ctx, size)) < 0)
1073 oldest = free_oldest_clip();
1074
1075 size = read_to_handle_ex(fd, &clip_ctx, handle, 0, size);
1146 close(fd); 1076 close(fd);
1147 1077
1148 /* ToDo: find audio, skip ID headers and trailers */ 1078 /* ToDo: find audio, skip ID headers and trailers */
@@ -1150,21 +1080,25 @@ static int _talk_file(const char* filename,
1150 if (size > 0) /* Don't play missing clips */ 1080 if (size > 0) /* Don't play missing clips */
1151 { 1081 {
1152 struct queue_entry clip; 1082 struct queue_entry clip;
1083 clip.handle = handle;
1084 clip.length = clip.remaining = size;
1153#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) 1085#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
1154 /* bitswap doesnt yield() */ 1086 /* bitswap doesnt yield() */
1155 bitswap(core_get_data(thumb_handle), size); 1087 bitswap(buflib_get_data(&clip_ctx, handle), size);
1156#endif 1088#endif
1157 if(prefix_ids) 1089 if(prefix_ids)
1158 /* prefix thumbnail by speaking these ids, but only now 1090 /* prefix thumbnail by speaking these ids, but only now
1159 that we know there's actually a thumbnail to be 1091 that we know there's actually a thumbnail to be
1160 spoken. */ 1092 spoken. */
1161 talk_idarray(prefix_ids, true); 1093 talk_idarray(prefix_ids, true);
1162 talk_queue_lock(); 1094 /* finally insert into metadata table. thumb clips go under the
1163 thumbnail_buf_used = thumb_used + size; 1095 * VOICEONLY_DELIMITER id so the cache can distinguish them from
1164 talk_queue_unlock(); 1096 * normal clips */
1165 clip = (struct queue_entry){ .offset = thumb_used, .length = size, .remaining = size, .type = THUMB_OFFSET }; 1097 add_cache_entry(handle, oldest, VOICEONLY_DELIMITER);
1166 queue_clip(&clip, true); 1098 queue_clip(&clip, true);
1167 } 1099 }
1100 else
1101 buflib_free(&clip_ctx, handle);
1168 1102
1169 return size; 1103 return size;
1170} 1104}
@@ -1566,6 +1500,7 @@ void talk_time(const struct tm *tm, bool enqueue)
1566bool talk_get_debug_data(struct talk_debug_data *data) 1500bool talk_get_debug_data(struct talk_debug_data *data)
1567{ 1501{
1568 char* p_lang = DEFAULT_VOICE_LANG; /* default */ 1502 char* p_lang = DEFAULT_VOICE_LANG; /* default */
1503 struct clip_cache_metadata *cc;
1569 1504
1570 memset(data, 0, sizeof(*data)); 1505 memset(data, 0, sizeof(*data));
1571 1506
@@ -1593,17 +1528,21 @@ bool talk_get_debug_data(struct talk_debug_data *data)
1593 if (size > data->max_clipsize) 1528 if (size > data->max_clipsize)
1594 data->max_clipsize = size; 1529 data->max_clipsize = size;
1595 data->avg_clipsize += size; 1530 data->avg_clipsize += size;
1596 if (clips[i].size & LOADED_MASK) 1531 }
1597 cached++; 1532 cc = buflib_get_data(&clip_ctx, metadata_table_handle);
1533 for (int i = 0; i < (int) max_clips; i++)
1534 {
1535 if (cc[i].handle > 0)
1536 cached += 1;
1598 } 1537 }
1599 data->avg_clipsize /= real_clips; 1538 data->avg_clipsize /= real_clips;
1600 data->num_empty_clips = data->num_clips - real_clips; 1539 data->num_empty_clips = data->num_clips - real_clips;
1601 data->memory_allocated = sizeof(commit_buffer) + sizeof(voicefile) 1540 data->memory_allocated = sizeof(commit_buffer) + sizeof(voicefile)
1602 + data->num_clips * sizeof(struct clip_entry) 1541 + data->num_clips * sizeof(struct clip_entry)
1603 + voicebuf_size + size_for_thumbnail; 1542 + voicebuf_size;
1604 data->memory_used = data->memory_allocated - size_for_thumbnail + thumbnail_buf_used; 1543 data->memory_used = 0;
1605 if (talk_handle > 0) 1544 if (talk_handle > 0)
1606 data->memory_used -= buflib_available(&clip_ctx); 1545 data->memory_used = data->memory_allocated - buflib_available(&clip_ctx);
1607 data->cached_clips = cached; 1546 data->cached_clips = cached;
1608 data->cache_hits = cache_hits; 1547 data->cache_hits = cache_hits;
1609 data->cache_misses = cache_misses; 1548 data->cache_misses = cache_misses;