Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/plugins/text-to-speech-announcer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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 from the queue
this.message.remove()
}
}
})
Expand All @@ -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
21 changes: 15 additions & 6 deletions src/announcer/announcer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { Log } from '../lib/log.js'
import speechSynthesis from './speechSynthesis.js'

let active = false
Expand All @@ -28,6 +29,7 @@ const noopAnnouncement = {
then() {},
done() {},
cancel() {},
remove() {},
stop() {},
}

Expand Down Expand Up @@ -66,11 +68,11 @@ const addToQueue = (message, politeness, delay = false) => {
resolveFn = resolve
})

// augment the promise with a cancel function
done.cancel = () => {
// 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)
isProcessing = false
Log.debug(`Announcer - removed from queue: "${message}" (id: ${id})`)
resolveFn('canceled')
}

Expand All @@ -92,6 +94,8 @@ const addToQueue = (message, politeness, delay = false) => {
queue.push({ delay, resolveFn, id })
}

Log.debug(`Announcer - added to queue: "${message}" (id: ${id})`)

setTimeout(() => {
processQueue()
}, 100)
Expand All @@ -118,17 +122,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()
})
Expand Down
2 changes: 1 addition & 1 deletion src/announcer/speechSynthesis.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down