mirror of https://github.com/ndarilek/tts-rs.git
Implement callbacks for WinRT.
This commit is contained in:
parent
a22242af50
commit
96e5d21e24
|
@ -1,16 +1,19 @@
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
|
use winrt::ComInterface;
|
||||||
|
|
||||||
use tts_winrt_bindings::windows::media::core::MediaSource;
|
|
||||||
use tts_winrt_bindings::windows::media::playback::{
|
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::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 {
|
impl From<winrt::Error> for Error {
|
||||||
fn from(e: winrt::Error) -> Self {
|
fn from(e: winrt::Error) -> Self {
|
||||||
|
@ -27,6 +30,18 @@ pub struct WinRT {
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref NEXT_BACKEND_ID: Mutex<u64> = Mutex::new(0);
|
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 {
|
impl WinRT {
|
||||||
|
@ -37,14 +52,16 @@ impl WinRT {
|
||||||
player.set_auto_play(true)?;
|
player.set_auto_play(true)?;
|
||||||
player.set_source(&playback_list)?;
|
player.set_source(&playback_list)?;
|
||||||
let mut backend_id = NEXT_BACKEND_ID.lock().unwrap();
|
let mut backend_id = NEXT_BACKEND_ID.lock().unwrap();
|
||||||
let rv = Ok(Self {
|
let bid = BackendId::WinRT(*backend_id);
|
||||||
id: BackendId::WinRT(*backend_id),
|
let mut rv = Self {
|
||||||
|
id: bid,
|
||||||
synth: SpeechSynthesizer::new()?,
|
synth: SpeechSynthesizer::new()?,
|
||||||
player: player,
|
player: player,
|
||||||
playback_list: playback_list,
|
playback_list: playback_list,
|
||||||
});
|
};
|
||||||
*backend_id += 1;
|
*backend_id += 1;
|
||||||
rv
|
Self::init_callbacks(&mut rv)?;
|
||||||
|
Ok(rv)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reinit_player(&mut self) -> std::result::Result<(), Error> {
|
fn reinit_player(&mut self) -> std::result::Result<(), Error> {
|
||||||
|
@ -52,6 +69,61 @@ impl WinRT {
|
||||||
self.player = MediaPlayer::new()?;
|
self.player = MediaPlayer::new()?;
|
||||||
self.player.set_auto_play(true)?;
|
self.player.set_auto_play(true)?;
|
||||||
self.player.set_source(&self.playback_list)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +140,7 @@ impl Backend for WinRT {
|
||||||
pitch: true,
|
pitch: true,
|
||||||
volume: true,
|
volume: true,
|
||||||
is_speaking: true,
|
is_speaking: true,
|
||||||
..Default::default()
|
utterance_callbacks: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +169,8 @@ impl Backend for WinRT {
|
||||||
if !self.is_speaking()? {
|
if !self.is_speaking()? {
|
||||||
self.player.play()?;
|
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> {
|
fn stop(&mut self) -> std::result::Result<(), Error> {
|
||||||
|
@ -178,3 +251,15 @@ impl Backend for WinRT {
|
||||||
Ok(playing)
|
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"))]
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
Backends::AvFoundation => Ok(TTS(Box::new(backends::AvFoundation::new()))),
|
Backends::AvFoundation => Ok(TTS(Box::new(backends::AvFoundation::new()))),
|
||||||
};
|
};
|
||||||
let mut callbacks = CALLBACKS.lock().unwrap();
|
|
||||||
if backend.is_ok() {
|
if backend.is_ok() {
|
||||||
let backend = backend.unwrap();
|
let backend = backend.unwrap();
|
||||||
if let Some(id) = backend.0.id() {
|
if let Some(id) = backend.0.id() {
|
||||||
|
let mut callbacks = CALLBACKS.lock().unwrap();
|
||||||
callbacks.insert(id, Callbacks::default());
|
callbacks.insert(id, Callbacks::default());
|
||||||
}
|
}
|
||||||
Ok(backend)
|
Ok(backend)
|
||||||
|
|
Loading…
Reference in New Issue