mirror of
https://github.com/ndarilek/tts-rs.git
synced 2024-11-17 11:09:37 +00:00
Implement callbacks for WinRT.
This commit is contained in:
parent
a22242af50
commit
96e5d21e24
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user