From 96e5d21e24877880e2d7aad9052e80be53e3a427 Mon Sep 17 00:00:00 2001 From: Nolan Darilek Date: Thu, 24 Sep 2020 17:56:46 -0500 Subject: [PATCH] Implement callbacks for WinRT. --- src/backends/winrt.rs | 103 ++++++++++++++++++++++++++++++++++++++---- src/lib.rs | 2 +- 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/backends/winrt.rs b/src/backends/winrt.rs index c72040c..815607a 100644 --- a/src/backends/winrt.rs +++ b/src/backends/winrt.rs @@ -1,16 +1,19 @@ #[cfg(windows)] +use std::collections::HashMap; use std::sync::Mutex; use lazy_static::lazy_static; use log::{info, trace}; +use winrt::ComInterface; -use tts_winrt_bindings::windows::media::core::MediaSource; use tts_winrt_bindings::windows::media::playback::{ - MediaPlaybackItem, MediaPlaybackList, MediaPlaybackState, MediaPlayer, + CurrentMediaPlaybackItemChangedEventArgs, MediaPlaybackItem, MediaPlaybackList, + MediaPlaybackState, MediaPlayer, }; use tts_winrt_bindings::windows::media::speech_synthesis::SpeechSynthesizer; +use tts_winrt_bindings::windows::{foundation::TypedEventHandler, media::core::MediaSource}; -use crate::{Backend, BackendId, Error, Features, UtteranceId}; +use crate::{Backend, BackendId, Error, Features, UtteranceId, CALLBACKS}; impl From for Error { fn from(e: winrt::Error) -> Self { @@ -27,6 +30,18 @@ pub struct WinRT { lazy_static! { static ref NEXT_BACKEND_ID: Mutex = Mutex::new(0); + static ref BACKEND_TO_MEDIA_PLAYER: Mutex> = { + let v: HashMap = HashMap::new(); + Mutex::new(v) + }; + static ref BACKEND_TO_PLAYBACK_LIST: Mutex> = { + let v: HashMap = HashMap::new(); + Mutex::new(v) + }; + static ref LAST_SPOKEN_UTTERANCE: Mutex> = { + let v: HashMap = HashMap::new(); + Mutex::new(v) + }; } impl WinRT { @@ -37,14 +52,16 @@ impl WinRT { player.set_auto_play(true)?; player.set_source(&playback_list)?; let mut backend_id = NEXT_BACKEND_ID.lock().unwrap(); - let rv = Ok(Self { - id: BackendId::WinRT(*backend_id), + let bid = BackendId::WinRT(*backend_id); + let mut rv = Self { + id: bid, synth: SpeechSynthesizer::new()?, player: player, playback_list: playback_list, - }); + }; *backend_id += 1; - rv + Self::init_callbacks(&mut rv)?; + Ok(rv) } fn reinit_player(&mut self) -> std::result::Result<(), Error> { @@ -52,6 +69,61 @@ impl WinRT { self.player = MediaPlayer::new()?; self.player.set_auto_play(true)?; self.player.set_source(&self.playback_list)?; + self.init_callbacks()?; + Ok(()) + } + + fn init_callbacks(&mut self) -> Result<(), winrt::Error> { + let id = self.id().unwrap(); + let mut backend_to_media_player = BACKEND_TO_MEDIA_PLAYER.lock().unwrap(); + backend_to_media_player.insert(id, self.player.clone()); + self.player + .media_ended(TypedEventHandler::new(|sender, _args| { + let backend_to_media_player = BACKEND_TO_MEDIA_PLAYER.lock().unwrap(); + let id = backend_to_media_player.iter().find(|v| v.1 == sender); + if let Some(id) = id { + let id = id.0; + let callbacks = CALLBACKS.lock().unwrap(); + let callbacks = callbacks.get(&id).unwrap(); + if let Some(callback) = callbacks.utterance_end { + let last_spoken_utterance = LAST_SPOKEN_UTTERANCE.lock().unwrap(); + if let Some(utterance_id) = last_spoken_utterance.get(&id) { + callback(utterance_id.clone()); + } + } + } + Ok(()) + }))?; + let mut backend_to_playback_list = BACKEND_TO_PLAYBACK_LIST.lock().unwrap(); + backend_to_playback_list.insert(id, self.playback_list.clone()); + self.playback_list + .current_item_changed(TypedEventHandler::new( + |sender: &MediaPlaybackList, args: &CurrentMediaPlaybackItemChangedEventArgs| { + let backend_to_playback_list = BACKEND_TO_PLAYBACK_LIST.lock().unwrap(); + let id = backend_to_playback_list.iter().find(|v| v.1 == sender); + if let Some(id) = id { + let id = id.0; + let callbacks = CALLBACKS.lock().unwrap(); + let callbacks = callbacks.get(&id).unwrap(); + let old_item = args.old_item()?; + if !old_item.is_null() { + if let Some(callback) = callbacks.utterance_end { + callback(UtteranceId::WinRT(old_item)); + } + } + let new_item = args.new_item()?; + if !new_item.is_null() { + let utterance_id = UtteranceId::WinRT(new_item); + let mut last_spoken_utterance = LAST_SPOKEN_UTTERANCE.lock().unwrap(); + last_spoken_utterance.insert(*id, utterance_id.clone()); + if let Some(callback) = callbacks.utterance_begin { + callback(utterance_id); + } + } + } + Ok(()) + }, + ))?; Ok(()) } } @@ -68,7 +140,7 @@ impl Backend for WinRT { pitch: true, volume: true, is_speaking: true, - ..Default::default() + utterance_callbacks: true, } } @@ -97,7 +169,8 @@ impl Backend for WinRT { if !self.is_speaking()? { self.player.play()?; } - Ok(Some(UtteranceId::WinRT(item))) + let utterance_id = UtteranceId::WinRT(item); + Ok(Some(utterance_id)) } fn stop(&mut self) -> std::result::Result<(), Error> { @@ -178,3 +251,15 @@ impl Backend for WinRT { Ok(playing) } } + +impl Drop for WinRT { + fn drop(&mut self) { + let id = self.id().unwrap(); + 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); + } +} diff --git a/src/lib.rs b/src/lib.rs index 622df31..5560ed1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -186,10 +186,10 @@ impl TTS { #[cfg(any(target_os = "macos", target_os = "ios"))] Backends::AvFoundation => Ok(TTS(Box::new(backends::AvFoundation::new()))), }; - let mut callbacks = CALLBACKS.lock().unwrap(); if backend.is_ok() { let backend = backend.unwrap(); if let Some(id) = backend.0.id() { + let mut callbacks = CALLBACKS.lock().unwrap(); callbacks.insert(id, Callbacks::default()); } Ok(backend)