Refactor Linux, Windows, and Wasm platforms to use FnMut for callbacks, and bump version.

This commit is contained in:
Nolan Darilek 2020-09-25 11:08:19 -05:00
parent 2c70f77a15
commit 1f22843086
6 changed files with 40 additions and 30 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tts" name = "tts"
version = "0.7.0" version = "0.8.0"
authors = ["Nolan Darilek <nolan@thewordnerd.info>"] authors = ["Nolan Darilek <nolan@thewordnerd.info>"]
repository = "https://github.com/ndarilek/tts-rs" repository = "https://github.com/ndarilek/tts-rs"
description = "High-level Text-To-Speech (TTS) interface" description = "High-level Text-To-Speech (TTS) interface"
@ -25,7 +25,7 @@ winrt = "0.7"
tts_winrt_bindings = { version = "0.1", path="winrt_bindings" } tts_winrt_bindings = { version = "0.1", path="winrt_bindings" }
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
speech-dispatcher = "0.6" speech-dispatcher = "0.7"
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
cocoa-foundation = "0.1" cocoa-foundation = "0.1"

View File

@ -17,12 +17,12 @@ fn main() -> Result<(), Error> {
.. ..
} = tts.supported_features(); } = tts.supported_features();
if utterance_callbacks { if utterance_callbacks {
tts.on_utterance_begin(Some(|utterance| { tts.on_utterance_begin(Some(Box::new(|utterance| {
println!("Started speaking {:?}", utterance) println!("Started speaking {:?}", utterance)
}))?; })))?;
tts.on_utterance_end(Some(|utterance| { tts.on_utterance_end(Some(Box::new(|utterance| {
println!("Finished speaking {:?}", utterance) println!("Finished speaking {:?}", utterance)
}))?; })))?;
} }
tts.speak("Hello, world.", false)?; tts.speak("Hello, world.", false)?;
let Features { rate, .. } = tts.supported_features(); let Features { rate, .. } = tts.supported_features();

View File

@ -28,22 +28,22 @@ impl SpeechDispatcher {
sd.0.on_begin(Some(|msg_id, client_id| { sd.0.on_begin(Some(|msg_id, client_id| {
let mut speaking = SPEAKING.lock().unwrap(); let mut speaking = SPEAKING.lock().unwrap();
speaking.insert(client_id, true); speaking.insert(client_id, true);
let callbacks = CALLBACKS.lock().unwrap(); let mut callbacks = CALLBACKS.lock().unwrap();
let backend_id = BackendId::SpeechDispatcher(client_id); let backend_id = BackendId::SpeechDispatcher(client_id);
let cb = callbacks.get(&backend_id).unwrap(); let cb = callbacks.get_mut(&backend_id).unwrap();
let utterance_id = UtteranceId::SpeechDispatcher(msg_id); let utterance_id = UtteranceId::SpeechDispatcher(msg_id);
if let Some(f) = cb.utterance_begin { if let Some(f) = cb.utterance_begin.as_mut() {
f(utterance_id); f(utterance_id);
} }
})); }));
sd.0.on_end(Some(|msg_id, client_id| { sd.0.on_end(Some(|msg_id, client_id| {
let mut speaking = SPEAKING.lock().unwrap(); let mut speaking = SPEAKING.lock().unwrap();
speaking.insert(client_id, false); speaking.insert(client_id, false);
let callbacks = CALLBACKS.lock().unwrap(); let mut callbacks = CALLBACKS.lock().unwrap();
let backend_id = BackendId::SpeechDispatcher(client_id); let backend_id = BackendId::SpeechDispatcher(client_id);
let cb = callbacks.get(&backend_id).unwrap(); let cb = callbacks.get_mut(&backend_id).unwrap();
let utterance_id = UtteranceId::SpeechDispatcher(msg_id); let utterance_id = UtteranceId::SpeechDispatcher(msg_id);
if let Some(f) = cb.utterance_end { if let Some(f) = cb.utterance_end.as_mut() {
f(utterance_id); f(utterance_id);
} }
})); }));

View File

@ -60,18 +60,18 @@ impl Backend for Web {
let id = self.id().unwrap(); let id = self.id().unwrap();
let utterance_id = UtteranceId::Web(utterance.clone()); let utterance_id = UtteranceId::Web(utterance.clone());
let callback = Closure::wrap(Box::new(move |evt: SpeechSynthesisEvent| { let callback = Closure::wrap(Box::new(move |evt: SpeechSynthesisEvent| {
let callbacks = CALLBACKS.lock().unwrap(); let mut callbacks = CALLBACKS.lock().unwrap();
let callback = callbacks.get(&id).unwrap(); let callback = callbacks.get_mut(&id).unwrap();
if let Some(f) = callback.utterance_begin { if let Some(f) = callback.utterance_begin.as_mut() {
let utterance_id = UtteranceId::Web(evt.utterance()); let utterance_id = UtteranceId::Web(evt.utterance());
f(utterance_id); f(utterance_id);
} }
}) as Box<dyn Fn(_)>); }) as Box<dyn Fn(_)>);
utterance.set_onstart(Some(callback.as_ref().unchecked_ref())); utterance.set_onstart(Some(callback.as_ref().unchecked_ref()));
let callback = Closure::wrap(Box::new(move |evt: SpeechSynthesisEvent| { let callback = Closure::wrap(Box::new(move |evt: SpeechSynthesisEvent| {
let callbacks = CALLBACKS.lock().unwrap(); let mut callbacks = CALLBACKS.lock().unwrap();
let callback = callbacks.get(&id).unwrap(); let callback = callbacks.get_mut(&id).unwrap();
if let Some(f) = callback.utterance_end { if let Some(f) = callback.utterance_end.as_mut() {
let utterance_id = UtteranceId::Web(evt.utterance()); let utterance_id = UtteranceId::Web(evt.utterance());
f(utterance_id); f(utterance_id);
} }

View File

@ -83,9 +83,9 @@ impl WinRT {
let id = backend_to_media_player.iter().find(|v| v.1 == sender); let id = backend_to_media_player.iter().find(|v| v.1 == sender);
if let Some(id) = id { if let Some(id) = id {
let id = id.0; let id = id.0;
let callbacks = CALLBACKS.lock().unwrap(); let mut callbacks = CALLBACKS.lock().unwrap();
let callbacks = callbacks.get(&id).unwrap(); let callbacks = callbacks.get_mut(&id).unwrap();
if let Some(callback) = callbacks.utterance_end { if let Some(callback) = callbacks.utterance_end.as_mut() {
let last_spoken_utterance = LAST_SPOKEN_UTTERANCE.lock().unwrap(); let last_spoken_utterance = LAST_SPOKEN_UTTERANCE.lock().unwrap();
if let Some(utterance_id) = last_spoken_utterance.get(&id) { if let Some(utterance_id) = last_spoken_utterance.get(&id) {
callback(utterance_id.clone()); callback(utterance_id.clone());
@ -103,20 +103,20 @@ impl WinRT {
let id = backend_to_playback_list.iter().find(|v| v.1 == sender); let id = backend_to_playback_list.iter().find(|v| v.1 == sender);
if let Some(id) = id { if let Some(id) = id {
let id = id.0; let id = id.0;
let callbacks = CALLBACKS.lock().unwrap(); let mut callbacks = CALLBACKS.lock().unwrap();
let callbacks = callbacks.get(&id).unwrap(); let callbacks = callbacks.get_mut(&id).unwrap();
let old_item = args.old_item()?; let old_item = args.old_item()?;
if !old_item.is_null() { if !old_item.is_null() {
if let Some(callback) = callbacks.utterance_end { if let Some(callback) = callbacks.utterance_end.as_mut() {
callback(UtteranceId::WinRT(old_item)); callback(UtteranceId::WinRT(old_item));
} }
} }
let new_item = args.new_item()?; let new_item = args.new_item()?;
if !new_item.is_null() { if !new_item.is_null() {
let utterance_id = UtteranceId::WinRT(new_item);
let mut last_spoken_utterance = LAST_SPOKEN_UTTERANCE.lock().unwrap(); let mut last_spoken_utterance = LAST_SPOKEN_UTTERANCE.lock().unwrap();
let utterance_id = UtteranceId::WinRT(new_item);
last_spoken_utterance.insert(*id, utterance_id.clone()); last_spoken_utterance.insert(*id, utterance_id.clone());
if let Some(callback) = callbacks.utterance_begin { if let Some(callback) = callbacks.utterance_begin.as_mut() {
callback(utterance_id); callback(utterance_id);
} }
} }

View File

@ -137,10 +137,14 @@ pub trait Backend {
#[derive(Default)] #[derive(Default)]
struct Callbacks { struct Callbacks {
utterance_begin: Option<fn(UtteranceId)>, utterance_begin: Option<Box<dyn FnMut(UtteranceId)>>,
utterance_end: Option<fn(UtteranceId)>, utterance_end: Option<Box<dyn FnMut(UtteranceId)>>,
} }
unsafe impl Send for Callbacks {}
unsafe impl Sync for Callbacks {}
lazy_static! { lazy_static! {
static ref CALLBACKS: Mutex<HashMap<BackendId, Callbacks>> = { static ref CALLBACKS: Mutex<HashMap<BackendId, Callbacks>> = {
let m: HashMap<BackendId, Callbacks> = HashMap::new(); let m: HashMap<BackendId, Callbacks> = HashMap::new();
@ -436,7 +440,10 @@ impl TTS {
/** /**
* Called when this speech synthesizer begins speaking an utterance. * Called when this speech synthesizer begins speaking an utterance.
*/ */
pub fn on_utterance_begin(&self, callback: Option<fn(UtteranceId)>) -> Result<(), Error> { pub fn on_utterance_begin(
&self,
callback: Option<Box<dyn FnMut(UtteranceId)>>,
) -> Result<(), Error> {
let Features { let Features {
utterance_callbacks, utterance_callbacks,
.. ..
@ -455,7 +462,10 @@ impl TTS {
/** /**
* Called when this speech synthesizer finishes speaking an utterance. * Called when this speech synthesizer finishes speaking an utterance.
*/ */
pub fn on_utterance_end(&self, callback: Option<fn(UtteranceId)>) -> Result<(), Error> { pub fn on_utterance_end(
&self,
callback: Option<Box<dyn FnMut(UtteranceId)>>,
) -> Result<(), Error> {
let Features { let Features {
utterance_callbacks, utterance_callbacks,
.. ..