Implement callbacks for WinRT.

This commit is contained in:
Nolan Darilek 2020-09-24 17:56:46 -05:00
parent a22242af50
commit 96e5d21e24
2 changed files with 95 additions and 10 deletions

View File

@ -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<winrt::Error> for Error {
fn from(e: winrt::Error) -> Self {
@ -27,6 +30,18 @@ pub struct WinRT {
lazy_static! {
static ref NEXT_BACKEND_ID: Mutex<u64> = Mutex::new(0);
static ref BACKEND_TO_MEDIA_PLAYER: Mutex<HashMap<BackendId, MediaPlayer>> = {
let v: HashMap<BackendId, MediaPlayer> = HashMap::new();
Mutex::new(v)
};
static ref BACKEND_TO_PLAYBACK_LIST: Mutex<HashMap<BackendId, MediaPlaybackList>> = {
let v: HashMap<BackendId, MediaPlaybackList> = HashMap::new();
Mutex::new(v)
};
static ref LAST_SPOKEN_UTTERANCE: Mutex<HashMap<BackendId, UtteranceId>> = {
let v: HashMap<BackendId, UtteranceId> = 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);
}
}

View File

@ -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)