From 2ffe87902dc72b4c26032c94e8250ff92d2888dc Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Sun, 20 Sep 2020 13:29:02 -0400 Subject: [PATCH] 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 --- apps/lang/InvalidVoice_english.talk | Bin 0 -> 2707 bytes apps/lang/SOURCES | 1 + apps/lang/lang.make | 6 ++- apps/main.c | 3 +- apps/talk.c | 65 +++++++++++++++++++++++++--- apps/talk.h | 2 + apps/voice_thread.c | 20 ++++++++- apps/voice_thread.h | 2 + tools/buildzip.pl | 3 +- 9 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 apps/lang/InvalidVoice_english.talk diff --git a/apps/lang/InvalidVoice_english.talk b/apps/lang/InvalidVoice_english.talk new file mode 100644 index 0000000000000000000000000000000000000000..e40f227c33c230365c26a08b9f209e5e42f89e7f GIT binary patch literal 2707 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 NtTxT87PYJvwX9_}NGbpT literal 0 HcmV?d00001 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 japanese.lang korean.lang thai.lang +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 $(SILENT)$(TOOLSDIR)/genlang -e=$(APPSDIR)/lang/$(ENGLISH).lang -t=$(MODELNAME):`cat $(BUILDDIR)/apps/genlang-features` -i=$(TARGET_ID) -b=$*.lng -c=$*.vstrings $@.tmp $(SILENT)rm -f $@.tmp -$(BUILDDIR)/apps/lang/voicestrings.zip: $(VOICEOBJ) +$(BUILDDIR)/apps/lang/voicestrings.zip: $(VOICEOBJ) $(wildcard $(BUILDDIR)/apps/lang/*.talk) $(call PRINTS,ZIP $(subst $(BUILDDIR)/,,$@)) $(SILENT)zip -9 -q $@ $(subst $(BUILDDIR)/,,$^) + +#copy any included talk files to the /lang directory +$(BUILDDIR)/apps/lang/%.talk: $(ROOTDIR)/apps/lang/%.talk + $(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) scrobbler_init(); audio_init(); - + talk_announce_voice_invalid(); /* notify user w/ voice prompt if voice file invalid */ settings_apply_skins(); } @@ -631,6 +631,7 @@ static void init(void) CHART(">audio_init"); audio_init(); CHART(" 0) + index_handle = core_free(index_handle); return false; } @@ -608,6 +603,7 @@ static bool load_voicefile_data(int fd) * other allocs succeed without disabling voice which would require * reloading the voice from disk (as we do not shrink our buffer when * other code attempts new allocs these would fail) */ + size_t metadata_alloc_size; ssize_t cap = MIN(MAX_CLIP_BUFFER_SIZE, audio_buffer_available() - (64<<10)); if (UNLIKELY(cap < 0)) { @@ -625,6 +621,11 @@ static bool load_voicefile_data(int fd) if (!create_clip_buffer(voicebuf_size)) return false; + /* the first alloc is the clip metadata table */ + metadata_alloc_size = max_clips * sizeof(struct clip_cache_metadata); + metadata_table_handle = buflib_alloc(&clip_ctx, metadata_alloc_size); + memset(buflib_get_data(&clip_ctx, metadata_table_handle), 0, metadata_alloc_size); + load_initial_clips(fd); /* make sure to have the silence clip, if available return value can * be cached globally even for TALK_PROGRESSIVE_LOAD because the @@ -1499,6 +1500,56 @@ void talk_time(const struct tm *tm, bool enqueue) } } +void talk_announce_voice_invalid(void) +{ + int voice_fd; + int voice_sz; + int buf_handle; + struct queue_entry qe; + + const char talkfile[] = + LANG_DIR "/InvalidVoice_" DEFAULT_VOICE_LANG ".talk"; + + if (global_settings.talk_menu && talk_status != TALK_STATUS_OK && !button_hold()) + { + talk_temp_disable_count = 0xFF; /* don't let anyone else use voice sys */ + + voice_fd = open(talkfile, O_RDONLY); + if (voice_fd < 0) + return; /* can't open */ + + voice_sz= lseek(voice_fd, 0, SEEK_END); + if (voice_sz == 0 || voice_sz > (64<<10)) + return; /* nothing here or too big */ + + lseek(voice_fd, 0, SEEK_SET); + /* add a bit extra for buflib overhead (2K) */ + if (!create_clip_buffer(ALIGN_UP(voice_sz, sizeof(long)) + (2<<10))) + return; + mutex_lock(&read_buffer_mutex); + buf_handle = buflib_alloc(&clip_ctx, ALIGN_UP(voice_sz, sizeof(long))); + + if (buf_handle < 0) + return; + + if (read_to_handle_ex(voice_fd, &clip_ctx, buf_handle, 0, voice_sz) > 0) + { + voice_thread_init(); + qe.handle = buf_handle; + qe.length = qe.remaining = voice_sz; + queue_clip(&qe, false); + voice_wait(); + voice_thread_kill(); + } + + mutex_unlock(&read_buffer_mutex); + close(voice_fd); + + buf_handle = buflib_free(&clip_ctx, buf_handle); + talk_handle = core_free(talk_handle); + } +} + bool talk_get_debug_data(struct talk_debug_data *data) { 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 { enum talk_status status; }; +void talk_announce_voice_invalid(void); + bool talk_get_debug_data(struct talk_debug_data *data); #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 VOICE_STATE_MESSAGE = 0, VOICE_STATE_DECODE, VOICE_STATE_BUFFER_INSERT, + VOICE_STATE_QUIT, }; /* A delay to not bring audio back to normal level too soon */ @@ -115,6 +116,7 @@ enum voice_thread_messages { Q_VOICE_PLAY = 0, /* Play a clip */ Q_VOICE_STOP, /* Stop current clip */ + Q_VOICE_KILL, /* Kill voice thread till restart*/ }; /* Structure to store clip data callback info */ @@ -383,7 +385,9 @@ static enum voice_state voice_message(struct voice_thread_data *td) speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); return VOICE_STATE_DECODE; - + case Q_VOICE_KILL: + queue_delete(&voice_queue); + return VOICE_STATE_QUIT; case SYS_TIMEOUT: if (voice_unplayed_frames()) { @@ -512,7 +516,7 @@ static enum voice_state voice_buffer_insert(struct voice_thread_data *td) } /* Voice thread entrypoint */ -static void NORETURN_ATTR voice_thread(void) +static void voice_thread(void) { struct voice_thread_data td; enum voice_state state = VOICE_STATE_MESSAGE; @@ -532,8 +536,20 @@ static void NORETURN_ATTR voice_thread(void) case VOICE_STATE_BUFFER_INSERT: state = voice_buffer_insert(&td); break; + case VOICE_STATE_QUIT: + logf("Exiting voice thread"); + core_free(voice_buf_hid); + voice_buf_hid = 0; + return; } } + return; +} + +/* kill voice thread and dont allow re-init*/ +void voice_thread_kill(void) +{ + queue_send(&voice_queue, Q_VOICE_KILL, 0); } /* 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); void voice_stop(void); void voice_thread_init(void); +void voice_thread_kill(void); + #ifdef HAVE_PRIORITY_SCHEDULING void voice_thread_set_priority(int priority); #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 { copy("rockbox-info.txt", "$temp_dir/rockbox-info.txt"); # copy the already built lng files - glob_copy('apps/lang/*lng', "$temp_dir/langs/"); + glob_copy('apps/lang/*.lng', "$temp_dir/langs/"); glob_copy('apps/lang/*.zip', "$temp_dir/langs/"); + glob_copy('apps/lang/*.talk', "$temp_dir/langs/"); # copy the .lua files glob_mkdir("$temp_dir/rocks/viewers/lua/");