diff options
author | William Wilgus <wilgus.william@gmail.com> | 2020-09-20 13:29:02 -0400 |
---|---|---|
committer | William Wilgus <wilgus.william@gmail.com> | 2020-09-20 16:08:49 -0400 |
commit | 2ffe87902dc72b4c26032c94e8250ff92d2888dc (patch) | |
tree | 9a6cf73d37a5a5e3f93813b44720c1bd5604ddd9 | |
parent | c528c01312d85e2d177bcc05ce82a29c97b803cc (diff) | |
download | rockbox-2ffe87902dc72b4c26032c94e8250ff92d2888dc.tar.gz rockbox-2ffe87902dc72b4c26032c94e8250ff92d2888dc.zip |
Add Invalid Voice Announcement to the voice system FS#13216
When a voice file is invalid or fails to load the voice system splash a
message 'Invalid Voice'
Now we supply a single voice file (currently only english is used)
the support for other languages is in but I haven't set it up to
look for anything but InvalidVoice_english.talk
Also adds a one time kill voice thread function
ie. it doesn't allow re-init after killing the voice thread & queue
Change-Id: I7b43f340c3cc65c65110190f0e0075b31218a7ac
-rw-r--r-- | apps/lang/InvalidVoice_english.talk | bin | 0 -> 2707 bytes | |||
-rw-r--r-- | apps/lang/SOURCES | 1 | ||||
-rw-r--r-- | apps/lang/lang.make | 6 | ||||
-rw-r--r-- | apps/main.c | 3 | ||||
-rw-r--r-- | apps/talk.c | 65 | ||||
-rw-r--r-- | apps/talk.h | 2 | ||||
-rw-r--r-- | apps/voice_thread.c | 20 | ||||
-rw-r--r-- | apps/voice_thread.h | 2 | ||||
-rwxr-xr-x | tools/buildzip.pl | 3 |
9 files changed, 90 insertions, 12 deletions
diff --git a/apps/lang/InvalidVoice_english.talk b/apps/lang/InvalidVoice_english.talk new file mode 100644 index 0000000000..e40f227c33 --- /dev/null +++ b/apps/lang/InvalidVoice_english.talk | |||
Binary files differ | |||
diff --git a/apps/lang/SOURCES b/apps/lang/SOURCES index 276d1bff1c..3faa5d5add 100644 --- a/apps/lang/SOURCES +++ b/apps/lang/SOURCES | |||
@@ -46,3 +46,4 @@ hindi.lang | |||
46 | japanese.lang | 46 | japanese.lang |
47 | korean.lang | 47 | korean.lang |
48 | thai.lang | 48 | thai.lang |
49 | InvalidVoice_english.talk | ||
diff --git a/apps/lang/lang.make b/apps/lang/lang.make index 807ac0f53f..73b6dce3de 100644 --- a/apps/lang/lang.make +++ b/apps/lang/lang.make | |||
@@ -54,6 +54,10 @@ $(BUILDDIR)/%.lng $(BUILDDIR)/%.vstrings: $(ROOTDIR)/%.lang $(BUILDDIR)/apps/gen | |||
54 | $(SILENT)$(TOOLSDIR)/genlang -e=$(APPSDIR)/lang/$(ENGLISH).lang -t=$(MODELNAME):`cat $(BUILDDIR)/apps/genlang-features` -i=$(TARGET_ID) -b=$*.lng -c=$*.vstrings $@.tmp | 54 | $(SILENT)$(TOOLSDIR)/genlang -e=$(APPSDIR)/lang/$(ENGLISH).lang -t=$(MODELNAME):`cat $(BUILDDIR)/apps/genlang-features` -i=$(TARGET_ID) -b=$*.lng -c=$*.vstrings $@.tmp |
55 | $(SILENT)rm -f $@.tmp | 55 | $(SILENT)rm -f $@.tmp |
56 | 56 | ||
57 | $(BUILDDIR)/apps/lang/voicestrings.zip: $(VOICEOBJ) | 57 | $(BUILDDIR)/apps/lang/voicestrings.zip: $(VOICEOBJ) $(wildcard $(BUILDDIR)/apps/lang/*.talk) |
58 | $(call PRINTS,ZIP $(subst $(BUILDDIR)/,,$@)) | 58 | $(call PRINTS,ZIP $(subst $(BUILDDIR)/,,$@)) |
59 | $(SILENT)zip -9 -q $@ $(subst $(BUILDDIR)/,,$^) | 59 | $(SILENT)zip -9 -q $@ $(subst $(BUILDDIR)/,,$^) |
60 | |||
61 | #copy any included talk files to the /lang directory | ||
62 | $(BUILDDIR)/apps/lang/%.talk: $(ROOTDIR)/apps/lang/%.talk | ||
63 | $(call PRINTS,CP $(subst $(ROOTDIR)/,,$<))cp $< $(BUILDDIR)/apps/lang | ||
diff --git a/apps/main.c b/apps/main.c index e1eccc0fa9..3c549a8e63 100644 --- a/apps/main.c +++ b/apps/main.c | |||
@@ -372,7 +372,7 @@ static void init(void) | |||
372 | scrobbler_init(); | 372 | scrobbler_init(); |
373 | 373 | ||
374 | audio_init(); | 374 | audio_init(); |
375 | 375 | talk_announce_voice_invalid(); /* notify user w/ voice prompt if voice file invalid */ | |
376 | settings_apply_skins(); | 376 | settings_apply_skins(); |
377 | } | 377 | } |
378 | 378 | ||
@@ -631,6 +631,7 @@ static void init(void) | |||
631 | CHART(">audio_init"); | 631 | CHART(">audio_init"); |
632 | audio_init(); | 632 | audio_init(); |
633 | CHART("<audio_init"); | 633 | CHART("<audio_init"); |
634 | talk_announce_voice_invalid(); /* notify user w/ voice prompt if voice file invalid */ | ||
634 | 635 | ||
635 | /* runtime database has to be initialized after audio_init() */ | 636 | /* runtime database has to be initialized after audio_init() */ |
636 | cpu_boost(false); | 637 | cpu_boost(false); |
diff --git a/apps/talk.c b/apps/talk.c index 5d292b05d1..29f1331983 100644 --- a/apps/talk.c +++ b/apps/talk.c | |||
@@ -535,7 +535,6 @@ static bool load_header(int fd, struct voicefile_header *hdr) | |||
535 | 535 | ||
536 | static bool create_clip_buffer(size_t max_size) | 536 | static bool create_clip_buffer(size_t max_size) |
537 | { | 537 | { |
538 | size_t alloc_size; | ||
539 | /* just allocate, populate on an as-needed basis later */ | 538 | /* just allocate, populate on an as-needed basis later */ |
540 | talk_handle = core_alloc_ex("voice data", max_size, &talk_ops); | 539 | talk_handle = core_alloc_ex("voice data", max_size, &talk_ops); |
541 | if (talk_handle < 0) | 540 | if (talk_handle < 0) |
@@ -543,16 +542,12 @@ static bool create_clip_buffer(size_t max_size) | |||
543 | 542 | ||
544 | buflib_init(&clip_ctx, core_get_data(talk_handle), max_size); | 543 | buflib_init(&clip_ctx, core_get_data(talk_handle), max_size); |
545 | 544 | ||
546 | /* the first alloc is the clip metadata table */ | ||
547 | alloc_size = max_clips * sizeof(struct clip_cache_metadata); | ||
548 | metadata_table_handle = buflib_alloc(&clip_ctx, alloc_size); | ||
549 | memset(buflib_get_data(&clip_ctx, metadata_table_handle), 0, alloc_size); | ||
550 | |||
551 | return true; | 545 | return true; |
552 | 546 | ||
553 | alloc_err: | 547 | alloc_err: |
554 | talk_status = TALK_STATUS_ERR_ALLOC; | 548 | talk_status = TALK_STATUS_ERR_ALLOC; |
555 | index_handle = core_free(index_handle); | 549 | if (index_handle > 0) |
550 | index_handle = core_free(index_handle); | ||
556 | return false; | 551 | return false; |
557 | } | 552 | } |
558 | 553 | ||
@@ -608,6 +603,7 @@ static bool load_voicefile_data(int fd) | |||
608 | * other allocs succeed without disabling voice which would require | 603 | * other allocs succeed without disabling voice which would require |
609 | * reloading the voice from disk (as we do not shrink our buffer when | 604 | * reloading the voice from disk (as we do not shrink our buffer when |
610 | * other code attempts new allocs these would fail) */ | 605 | * other code attempts new allocs these would fail) */ |
606 | size_t metadata_alloc_size; | ||
611 | ssize_t cap = MIN(MAX_CLIP_BUFFER_SIZE, audio_buffer_available() - (64<<10)); | 607 | ssize_t cap = MIN(MAX_CLIP_BUFFER_SIZE, audio_buffer_available() - (64<<10)); |
612 | if (UNLIKELY(cap < 0)) | 608 | if (UNLIKELY(cap < 0)) |
613 | { | 609 | { |
@@ -625,6 +621,11 @@ static bool load_voicefile_data(int fd) | |||
625 | if (!create_clip_buffer(voicebuf_size)) | 621 | if (!create_clip_buffer(voicebuf_size)) |
626 | return false; | 622 | return false; |
627 | 623 | ||
624 | /* the first alloc is the clip metadata table */ | ||
625 | metadata_alloc_size = max_clips * sizeof(struct clip_cache_metadata); | ||
626 | metadata_table_handle = buflib_alloc(&clip_ctx, metadata_alloc_size); | ||
627 | memset(buflib_get_data(&clip_ctx, metadata_table_handle), 0, metadata_alloc_size); | ||
628 | |||
628 | load_initial_clips(fd); | 629 | load_initial_clips(fd); |
629 | /* make sure to have the silence clip, if available return value can | 630 | /* make sure to have the silence clip, if available return value can |
630 | * be cached globally even for TALK_PROGRESSIVE_LOAD because the | 631 | * be cached globally even for TALK_PROGRESSIVE_LOAD because the |
@@ -1499,6 +1500,56 @@ void talk_time(const struct tm *tm, bool enqueue) | |||
1499 | } | 1500 | } |
1500 | } | 1501 | } |
1501 | 1502 | ||
1503 | void talk_announce_voice_invalid(void) | ||
1504 | { | ||
1505 | int voice_fd; | ||
1506 | int voice_sz; | ||
1507 | int buf_handle; | ||
1508 | struct queue_entry qe; | ||
1509 | |||
1510 | const char talkfile[] = | ||
1511 | LANG_DIR "/InvalidVoice_" DEFAULT_VOICE_LANG ".talk"; | ||
1512 | |||
1513 | if (global_settings.talk_menu && talk_status != TALK_STATUS_OK && !button_hold()) | ||
1514 | { | ||
1515 | talk_temp_disable_count = 0xFF; /* don't let anyone else use voice sys */ | ||
1516 | |||
1517 | voice_fd = open(talkfile, O_RDONLY); | ||
1518 | if (voice_fd < 0) | ||
1519 | return; /* can't open */ | ||
1520 | |||
1521 | voice_sz= lseek(voice_fd, 0, SEEK_END); | ||
1522 | if (voice_sz == 0 || voice_sz > (64<<10)) | ||
1523 | return; /* nothing here or too big */ | ||
1524 | |||
1525 | lseek(voice_fd, 0, SEEK_SET); | ||
1526 | /* add a bit extra for buflib overhead (2K) */ | ||
1527 | if (!create_clip_buffer(ALIGN_UP(voice_sz, sizeof(long)) + (2<<10))) | ||
1528 | return; | ||
1529 | mutex_lock(&read_buffer_mutex); | ||
1530 | buf_handle = buflib_alloc(&clip_ctx, ALIGN_UP(voice_sz, sizeof(long))); | ||
1531 | |||
1532 | if (buf_handle < 0) | ||
1533 | return; | ||
1534 | |||
1535 | if (read_to_handle_ex(voice_fd, &clip_ctx, buf_handle, 0, voice_sz) > 0) | ||
1536 | { | ||
1537 | voice_thread_init(); | ||
1538 | qe.handle = buf_handle; | ||
1539 | qe.length = qe.remaining = voice_sz; | ||
1540 | queue_clip(&qe, false); | ||
1541 | voice_wait(); | ||
1542 | voice_thread_kill(); | ||
1543 | } | ||
1544 | |||
1545 | mutex_unlock(&read_buffer_mutex); | ||
1546 | close(voice_fd); | ||
1547 | |||
1548 | buf_handle = buflib_free(&clip_ctx, buf_handle); | ||
1549 | talk_handle = core_free(talk_handle); | ||
1550 | } | ||
1551 | } | ||
1552 | |||
1502 | bool talk_get_debug_data(struct talk_debug_data *data) | 1553 | bool talk_get_debug_data(struct talk_debug_data *data) |
1503 | { | 1554 | { |
1504 | char* p_lang = DEFAULT_VOICE_LANG; /* default */ | 1555 | char* p_lang = DEFAULT_VOICE_LANG; /* default */ |
diff --git a/apps/talk.h b/apps/talk.h index bfd8e496af..b4aa344916 100644 --- a/apps/talk.h +++ b/apps/talk.h | |||
@@ -186,6 +186,8 @@ struct talk_debug_data { | |||
186 | enum talk_status status; | 186 | enum talk_status status; |
187 | }; | 187 | }; |
188 | 188 | ||
189 | void talk_announce_voice_invalid(void); | ||
190 | |||
189 | bool talk_get_debug_data(struct talk_debug_data *data); | 191 | bool talk_get_debug_data(struct talk_debug_data *data); |
190 | 192 | ||
191 | #endif /* __TALK_H__ */ | 193 | #endif /* __TALK_H__ */ |
diff --git a/apps/voice_thread.c b/apps/voice_thread.c index 171902d10f..08c7fd6b0b 100644 --- a/apps/voice_thread.c +++ b/apps/voice_thread.c | |||
@@ -106,6 +106,7 @@ enum voice_state | |||
106 | VOICE_STATE_MESSAGE = 0, | 106 | VOICE_STATE_MESSAGE = 0, |
107 | VOICE_STATE_DECODE, | 107 | VOICE_STATE_DECODE, |
108 | VOICE_STATE_BUFFER_INSERT, | 108 | VOICE_STATE_BUFFER_INSERT, |
109 | VOICE_STATE_QUIT, | ||
109 | }; | 110 | }; |
110 | 111 | ||
111 | /* A delay to not bring audio back to normal level too soon */ | 112 | /* A delay to not bring audio back to normal level too soon */ |
@@ -115,6 +116,7 @@ enum voice_thread_messages | |||
115 | { | 116 | { |
116 | Q_VOICE_PLAY = 0, /* Play a clip */ | 117 | Q_VOICE_PLAY = 0, /* Play a clip */ |
117 | Q_VOICE_STOP, /* Stop current clip */ | 118 | Q_VOICE_STOP, /* Stop current clip */ |
119 | Q_VOICE_KILL, /* Kill voice thread till restart*/ | ||
118 | }; | 120 | }; |
119 | 121 | ||
120 | /* Structure to store clip data callback info */ | 122 | /* Structure to store clip data callback info */ |
@@ -383,7 +385,9 @@ static enum voice_state voice_message(struct voice_thread_data *td) | |||
383 | speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); | 385 | speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); |
384 | 386 | ||
385 | return VOICE_STATE_DECODE; | 387 | return VOICE_STATE_DECODE; |
386 | 388 | case Q_VOICE_KILL: | |
389 | queue_delete(&voice_queue); | ||
390 | return VOICE_STATE_QUIT; | ||
387 | case SYS_TIMEOUT: | 391 | case SYS_TIMEOUT: |
388 | if (voice_unplayed_frames()) | 392 | if (voice_unplayed_frames()) |
389 | { | 393 | { |
@@ -512,7 +516,7 @@ static enum voice_state voice_buffer_insert(struct voice_thread_data *td) | |||
512 | } | 516 | } |
513 | 517 | ||
514 | /* Voice thread entrypoint */ | 518 | /* Voice thread entrypoint */ |
515 | static void NORETURN_ATTR voice_thread(void) | 519 | static void voice_thread(void) |
516 | { | 520 | { |
517 | struct voice_thread_data td; | 521 | struct voice_thread_data td; |
518 | enum voice_state state = VOICE_STATE_MESSAGE; | 522 | enum voice_state state = VOICE_STATE_MESSAGE; |
@@ -532,8 +536,20 @@ static void NORETURN_ATTR voice_thread(void) | |||
532 | case VOICE_STATE_BUFFER_INSERT: | 536 | case VOICE_STATE_BUFFER_INSERT: |
533 | state = voice_buffer_insert(&td); | 537 | state = voice_buffer_insert(&td); |
534 | break; | 538 | break; |
539 | case VOICE_STATE_QUIT: | ||
540 | logf("Exiting voice thread"); | ||
541 | core_free(voice_buf_hid); | ||
542 | voice_buf_hid = 0; | ||
543 | return; | ||
535 | } | 544 | } |
536 | } | 545 | } |
546 | return; | ||
547 | } | ||
548 | |||
549 | /* kill voice thread and dont allow re-init*/ | ||
550 | void voice_thread_kill(void) | ||
551 | { | ||
552 | queue_send(&voice_queue, Q_VOICE_KILL, 0); | ||
537 | } | 553 | } |
538 | 554 | ||
539 | /* Initialize buffers, all synchronization objects and create the thread */ | 555 | /* Initialize buffers, all synchronization objects and create the thread */ |
diff --git a/apps/voice_thread.h b/apps/voice_thread.h index d662aaee33..81b11eea37 100644 --- a/apps/voice_thread.h +++ b/apps/voice_thread.h | |||
@@ -36,6 +36,8 @@ void voice_wait(void); | |||
36 | void voice_stop(void); | 36 | void voice_stop(void); |
37 | 37 | ||
38 | void voice_thread_init(void); | 38 | void voice_thread_init(void); |
39 | void voice_thread_kill(void); | ||
40 | |||
39 | #ifdef HAVE_PRIORITY_SCHEDULING | 41 | #ifdef HAVE_PRIORITY_SCHEDULING |
40 | void voice_thread_set_priority(int priority); | 42 | void voice_thread_set_priority(int priority); |
41 | #endif | 43 | #endif |
diff --git a/tools/buildzip.pl b/tools/buildzip.pl index 4b15771333..f53f16a674 100755 --- a/tools/buildzip.pl +++ b/tools/buildzip.pl | |||
@@ -614,8 +614,9 @@ sub buildzip { | |||
614 | copy("rockbox-info.txt", "$temp_dir/rockbox-info.txt"); | 614 | copy("rockbox-info.txt", "$temp_dir/rockbox-info.txt"); |
615 | 615 | ||
616 | # copy the already built lng files | 616 | # copy the already built lng files |
617 | glob_copy('apps/lang/*lng', "$temp_dir/langs/"); | 617 | glob_copy('apps/lang/*.lng', "$temp_dir/langs/"); |
618 | glob_copy('apps/lang/*.zip', "$temp_dir/langs/"); | 618 | glob_copy('apps/lang/*.zip', "$temp_dir/langs/"); |
619 | glob_copy('apps/lang/*.talk', "$temp_dir/langs/"); | ||
619 | 620 | ||
620 | # copy the .lua files | 621 | # copy the .lua files |
621 | glob_mkdir("$temp_dir/rocks/viewers/lua/"); | 622 | glob_mkdir("$temp_dir/rocks/viewers/lua/"); |