sapi_lite/tts/synthesizer/
event.rs

1use std::ops::Deref;
2
3use windows as Windows;
4use Windows::core::Interface;
5use Windows::Win32::Media::Speech::{SPEI_END_INPUT_STREAM, SPF_ASYNC};
6
7use crate::event::{Event, EventSink, EventSource};
8use crate::tts::Speech;
9use crate::Result;
10
11use super::Synthesizer;
12
13/// The handler [`EventfulSynthesizer`] will call.
14pub trait EventHandler: Sync {
15    /// Called when the synthesizer has finished rendering the speech with the given identifier.
16    fn on_speech_finished(&self, id: u32);
17}
18
19impl<F: Fn(u32) + Sync> EventHandler for F {
20    fn on_speech_finished(&self, id: u32) {
21        self(id)
22    }
23}
24
25/// A speech synthesizer that calls the supplied event handler every time it finishes rendering
26/// speech.
27pub struct EventfulSynthesizer {
28    base: Synthesizer,
29}
30
31impl EventfulSynthesizer {
32    /// Creates a new synthesizer that will output to the default audio device and call the supplied
33    /// event handler.
34    pub fn new<E: EventHandler + 'static>(handler: E) -> Result<Self> {
35        let base = Synthesizer::new()?;
36        EventSink::new(EventSource::from_sapi(base.intf.0.cast()?), move |event| {
37            if let Event::SpeechFinished(id) = event {
38                handler.on_speech_finished(id);
39            }
40            Ok(())
41        })
42        .install(Some(&[SPEI_END_INPUT_STREAM]))?;
43        Ok(Self { base })
44    }
45
46    /// Schedules the rendering of the given speech and returns a numeric identifier for it. The
47    /// identifier will be passed to the event handler when the speech has been rendered.
48    pub fn speak<'s, S: Into<Speech<'s>>>(&self, speech: S) -> Result<u32> {
49        self.base.speak(speech, SPF_ASYNC.0 as _)
50    }
51}
52
53impl Deref for EventfulSynthesizer {
54    type Target = Synthesizer;
55    fn deref(&self) -> &Self::Target {
56        &self.base
57    }
58}