From 54c1bdf768062956c4f0e0d155fa51aceca1d633 Mon Sep 17 00:00:00 2001 From: Michiel van der Geest Date: Fri, 8 Aug 2025 15:00:42 +0200 Subject: [PATCH 1/5] Added debug logs to announcer. Fixed (?) issues with isProcessing. Optimzed unique id in speechSynthesis. --- src/announcer/announcer.js | 16 ++++++++++++---- src/announcer/speechSynthesis.js | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/announcer/announcer.js b/src/announcer/announcer.js index ddecd7b7..67b0a7b2 100644 --- a/src/announcer/announcer.js +++ b/src/announcer/announcer.js @@ -15,6 +15,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { Log } from '../lib/log.js' import speechSynthesis from './speechSynthesis.js' let active = false @@ -70,7 +71,7 @@ const addToQueue = (message, politeness, delay = false) => { done.cancel = () => { const index = queue.findIndex((item) => item.id === id) if (index !== -1) queue.splice(index, 1) - isProcessing = false + Log.debug(`Announcer - removed from queue: "${message}" (id: ${id})`) resolveFn('canceled') } @@ -92,6 +93,8 @@ const addToQueue = (message, politeness, delay = false) => { queue.push({ delay, resolveFn, id }) } + Log.debug(`Announcer - added to queue: "${message}" (id: ${id})`) + setTimeout(() => { processQueue() }, 100) @@ -118,17 +121,22 @@ const processQueue = async () => { if (debounce !== null) clearTimeout(debounce) // add some easing when speaking the messages to reduce stuttering debounce = setTimeout(() => { + Log.debug(`Announcer - speaking: "${message}" (id: ${id})`) + speechSynthesis - .speak({ message }) + .speak({ message, id }) .then(() => { - isProcessing = false + Log.debug(`Announcer - finished speaking: "${message}" (id: ${id})`) + currentId = null + isProcessing = false resolveFn('finished') processQueue() }) .catch((e) => { - isProcessing = false currentId = null + isProcessing = false + Log.debug(`Announcer - error ("${e.error}") while speaking: "${message}" (id: ${id})`) resolveFn(e.error) processQueue() }) diff --git a/src/announcer/speechSynthesis.js b/src/announcer/speechSynthesis.js index 697a8356..5c454ba4 100644 --- a/src/announcer/speechSynthesis.js +++ b/src/announcer/speechSynthesis.js @@ -64,7 +64,7 @@ const initialize = () => { const speak = (options) => { const utterance = new SpeechSynthesisUtterance(options.message) - const id = Date.now() + Math.random() // Unique ID for tracking + const id = options.id utterance.lang = options.lang || defaultUtteranceProps.lang utterance.pitch = options.pitch || defaultUtteranceProps.pitch utterance.rate = options.rate || defaultUtteranceProps.rate From 3c1fd0bec040f2b9f84279ba54cc0674f0928c77 Mon Sep 17 00:00:00 2001 From: Michiel van der Geest Date: Mon, 11 Aug 2025 14:02:49 +0200 Subject: [PATCH 2/5] Added remove as an alias (and the prefered name) for canceling a message. --- docs/plugins/text-to-speech-announcer.md | 8 ++++---- src/announcer/announcer.js | 10 +++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/plugins/text-to-speech-announcer.md b/docs/plugins/text-to-speech-announcer.md index 1ad2da19..8162c660 100644 --- a/docs/plugins/text-to-speech-announcer.md +++ b/docs/plugins/text-to-speech-announcer.md @@ -79,7 +79,7 @@ In some cases you may not want to clear the entire queue, but instead cancel out Imagine an App with a row of tiles, it's possible that before the title of the role is being spoken out, the user already navigates through the tiles within the row. Traditionally you'd use the focus event to speak out info about each tile (i.e. adding tot the queue). You don't want all previously focused tiles to still be announced, but would still want the category of the row to be announced, making clearing the queue not required. -The `speak()`-method return a Promise that also contains a `cancel()` function. When called, it will cancel that specific message and remove it from the queue before it can be spoken out. +The `speak()`-method return a Promise that also contains a `remove()` function. When called, it will remove it from the queue before it can be spoken out. Additionally if you want to _interrupt_ a specific messages as it's being spoken out as well and go straight to the next message in the queue (i.e. the newly focused item, for example). You can use the `stop()` message that is returned on the Promise returned by the `speak()`-method. @@ -100,8 +100,8 @@ Blits.Component('MyTile', { unfocus() { // when unfocused interrupt the message if it's already being spoken out this.message.stop() - // and cancel the message to remove it from the queue - this.message.cancel() + // and remove the message to remove it from the queue + this.message.remove() } } }) @@ -117,4 +117,4 @@ Alternatively the announcer can be enabled or disabled run time by using one of - `this.$announcer.enable()` - activates the announcer - `this.$announcer.disable()` - deactivates the announcer -- `this.$announcer.disable(true/false)` - turns the announcer or on off \ No newline at end of file +- `this.$announcer.disable(true/false)` - turns the announcer or on off diff --git a/src/announcer/announcer.js b/src/announcer/announcer.js index 67b0a7b2..5e1dc0c6 100644 --- a/src/announcer/announcer.js +++ b/src/announcer/announcer.js @@ -29,6 +29,7 @@ const noopAnnouncement = { then() {}, done() {}, cancel() {}, + remove() {}, stop() {}, } @@ -68,7 +69,14 @@ const addToQueue = (message, politeness, delay = false) => { }) // augment the promise with a cancel function - done.cancel = () => { + done.remove = done.cancel = () => { + const index = queue.findIndex((item) => item.id === id) + if (index !== -1) queue.splice(index, 1) + Log.debug(`Announcer - removed from queue: "${message}" (id: ${id})`) + resolveFn('canceled') + } + + done.remove = done.cancel = () => { const index = queue.findIndex((item) => item.id === id) if (index !== -1) queue.splice(index, 1) Log.debug(`Announcer - removed from queue: "${message}" (id: ${id})`) From c6bdd7c7d8c0d86356682ce251b9829c74f70e70 Mon Sep 17 00:00:00 2001 From: Michiel van der Geest Date: Mon, 11 Aug 2025 14:20:31 +0200 Subject: [PATCH 3/5] Fixed typo in docs. --- docs/plugins/text-to-speech-announcer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/text-to-speech-announcer.md b/docs/plugins/text-to-speech-announcer.md index 8162c660..53848757 100644 --- a/docs/plugins/text-to-speech-announcer.md +++ b/docs/plugins/text-to-speech-announcer.md @@ -117,4 +117,4 @@ Alternatively the announcer can be enabled or disabled run time by using one of - `this.$announcer.enable()` - activates the announcer - `this.$announcer.disable()` - deactivates the announcer -- `this.$announcer.disable(true/false)` - turns the announcer or on off +- `this.$announcer.disable(true/false)` - turns the announcer on or off From 1397e115bc4f7f3c9eb308b8d11cf6671d524e5e Mon Sep 17 00:00:00 2001 From: Michiel van der Geest Date: Mon, 11 Aug 2025 14:26:53 +0200 Subject: [PATCH 4/5] Removed duplication. --- src/announcer/announcer.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/announcer/announcer.js b/src/announcer/announcer.js index 5e1dc0c6..01ac6df6 100644 --- a/src/announcer/announcer.js +++ b/src/announcer/announcer.js @@ -68,14 +68,7 @@ const addToQueue = (message, politeness, delay = false) => { resolveFn = resolve }) - // augment the promise with a cancel function - done.remove = done.cancel = () => { - const index = queue.findIndex((item) => item.id === id) - if (index !== -1) queue.splice(index, 1) - Log.debug(`Announcer - removed from queue: "${message}" (id: ${id})`) - resolveFn('canceled') - } - + // augment the promise with a cancel / remove function done.remove = done.cancel = () => { const index = queue.findIndex((item) => item.id === id) if (index !== -1) queue.splice(index, 1) From 479a850affc8de264f1dc3fb213fc20bdc074f3e Mon Sep 17 00:00:00 2001 From: Michiel van der Geest Date: Mon, 11 Aug 2025 14:28:52 +0200 Subject: [PATCH 5/5] Fixed example in documentation. --- docs/plugins/text-to-speech-announcer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/text-to-speech-announcer.md b/docs/plugins/text-to-speech-announcer.md index 53848757..c3c907db 100644 --- a/docs/plugins/text-to-speech-announcer.md +++ b/docs/plugins/text-to-speech-announcer.md @@ -100,7 +100,7 @@ Blits.Component('MyTile', { unfocus() { // when unfocused interrupt the message if it's already being spoken out this.message.stop() - // and remove the message to remove it from the queue + // and remove the message from the queue this.message.remove() } }