Make `UtteranceId` use `u64` on most platforms, and add additional derives.

This commit is contained in:
Nolan Darilek 2020-10-08 07:16:10 -05:00
parent c2bbc5ac04
commit 174011bbb4
3 changed files with 63 additions and 19 deletions

View File

@ -18,6 +18,8 @@ pub struct Web {
lazy_static! {
static ref NEXT_BACKEND_ID: Mutex<u64> = Mutex::new(0);
static ref UTTERANCE_MAPPINGS: Mutex<Vec<(BackendId, UtteranceId)>> = Mutex::new(Vec::new());
static ref NEXT_UTTERANCE_ID: Mutex<u64> = Mutex::new(0);
}
impl Web {
@ -58,23 +60,29 @@ impl Backend for Web {
utterance.set_pitch(self.pitch);
utterance.set_volume(self.volume);
let id = self.id().unwrap();
let utterance_id = UtteranceId::Web(utterance.clone());
let callback = Closure::wrap(Box::new(move |evt: SpeechSynthesisEvent| {
let mut uid = NEXT_UTTERANCE_ID.lock().unwrap();
let utterance_id = UtteranceId::Web(*uid);
*uid += 1;
drop(uid);
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap();
mappings.push((self.id, utterance_id));
drop(mappings);
let callback = Closure::wrap(Box::new(move |_evt: SpeechSynthesisEvent| {
let mut callbacks = CALLBACKS.lock().unwrap();
let callback = callbacks.get_mut(&id).unwrap();
if let Some(f) = callback.utterance_begin.as_mut() {
let utterance_id = UtteranceId::Web(evt.utterance());
f(utterance_id);
}
}) as Box<dyn Fn(_)>);
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 mut callbacks = CALLBACKS.lock().unwrap();
let callback = callbacks.get_mut(&id).unwrap();
if let Some(f) = callback.utterance_end.as_mut() {
let utterance_id = UtteranceId::Web(evt.utterance());
f(utterance_id);
}
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap();
mappings.retain(|v| v.1 != utterance_id);
}) as Box<dyn Fn(_)>);
utterance.set_onend(Some(callback.as_ref().unchecked_ref()));
if interrupt {
@ -173,3 +181,10 @@ impl Backend for Web {
}
}
}
impl Drop for Web {
fn drop(&mut self) {
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap();
mappings.retain(|v| v.0 != self.id);
}
}

View File

@ -30,6 +30,9 @@ pub struct WinRT {
lazy_static! {
static ref NEXT_BACKEND_ID: Mutex<u64> = Mutex::new(0);
static ref NEXT_UTTERANCE_ID: Mutex<u64> = Mutex::new(0);
static ref UTTERANCE_MAPPINGS: Mutex<Vec<(BackendId, MediaPlaybackItem, UtteranceId)>> =
Mutex::new(Vec::new());
static ref BACKEND_TO_MEDIA_PLAYER: Mutex<HashMap<BackendId, MediaPlayer>> = {
let v: HashMap<BackendId, MediaPlayer> = HashMap::new();
Mutex::new(v)
@ -70,6 +73,16 @@ impl WinRT {
self.player.set_auto_play(true)?;
self.player.set_source(&self.playback_list)?;
self.init_callbacks()?;
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap();
let mut callbacks = CALLBACKS.lock().unwrap();
let callbacks = callbacks.get_mut(&self.id).unwrap();
if let Some(callback) = callbacks.utterance_end.as_mut() {
let mappings = UTTERANCE_MAPPINGS.lock().unwrap();
for mapping in &*mappings {
callback(mapping.2);
}
}
mappings.retain(|v| v.0 != self.id);
Ok(())
}
@ -107,17 +120,31 @@ impl WinRT {
let callbacks = callbacks.get_mut(&id).unwrap();
let old_item = args.old_item()?;
if !old_item.is_null() {
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap();
if let Some(callback) = callbacks.utterance_end.as_mut() {
callback(UtteranceId::WinRT(old_item));
for mapping in &*mappings {
if mapping.1 == old_item {
callback(mapping.2);
}
}
mappings.retain(|v| v.1 != old_item);
}
}
let new_item = args.new_item()?;
if !new_item.is_null() {
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());
let mappings = UTTERANCE_MAPPINGS.lock().unwrap();
for mapping in &*mappings {
if mapping.1 == new_item {
last_spoken_utterance.insert(*id, mapping.2);
}
}
if let Some(callback) = callbacks.utterance_begin.as_mut() {
callback(utterance_id);
for mapping in &*mappings {
if mapping.1 == new_item {
callback(mapping.2);
}
}
}
}
}
@ -169,7 +196,12 @@ impl Backend for WinRT {
if !self.is_speaking()? {
self.player.play()?;
}
let utterance_id = UtteranceId::WinRT(item);
let mut uid = NEXT_UTTERANCE_ID.lock().unwrap();
let utterance_id = UtteranceId::WinRT(*uid);
*uid += 1;
drop(uid);
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap();
mappings.push((self.id, item, utterance_id));
Ok(Some(utterance_id))
}
@ -254,12 +286,14 @@ impl Backend for WinRT {
impl Drop for WinRT {
fn drop(&mut self) {
let id = self.id().unwrap();
let id = self.id;
let mut backend_to_playback_list = BACKEND_TO_PLAYBACK_LIST.lock().unwrap();
backend_to_playback_list.remove(&id);
let mut backend_to_media_player = BACKEND_TO_MEDIA_PLAYER.lock().unwrap();
backend_to_media_player.remove(&id);
let mut last_spoken_utterance = LAST_SPOKEN_UTTERANCE.lock().unwrap();
last_spoken_utterance.remove(&id);
let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap();
mappings.retain(|v| v.0 != id);
}
}

View File

@ -25,11 +25,6 @@ use libc::c_char;
#[cfg(target_os = "macos")]
use objc::{class, msg_send, sel, sel_impl};
use thiserror::Error;
#[cfg(target_arch = "wasm32")]
use web_sys::SpeechSynthesisUtterance;
#[cfg(windows)]
use tts_winrt_bindings::windows::media::playback::MediaPlaybackItem;
mod backends;
@ -60,14 +55,14 @@ pub enum BackendId {
AvFoundation(u64),
}
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum UtteranceId {
#[cfg(target_os = "linux")]
SpeechDispatcher(u64),
#[cfg(target_arch = "wasm32")]
Web(SpeechSynthesisUtterance),
Web(u64),
#[cfg(windows)]
WinRT(MediaPlaybackItem),
WinRT(u64),
#[cfg(any(target_os = "macos", target_os = "ios"))]
AvFoundation(id),
}