sapi_lite/tokio/
tts.rs

1use std::collections::HashMap;
2use std::ops::Deref;
3use std::sync::{Arc, Mutex};
4
5use tokio::sync::oneshot::{channel, Receiver, Sender};
6
7use crate::tts::{EventfulSynthesizer, Speech, Synthesizer};
8use crate::Result;
9
10enum PendingSpeech {
11    Waiting(Sender<()>),
12    Finished,
13}
14
15#[cfg_attr(docsrs, doc(cfg(feature = "tokio-tts")))]
16/// A speech synthesizer that returns a future for every speech it renders.
17pub struct AsyncSynthesizer {
18    base: EventfulSynthesizer,
19    pending_speeches: Arc<Mutex<HashMap<u32, PendingSpeech>>>,
20}
21
22impl AsyncSynthesizer {
23    /// Creates a new synthesizer, configured to output its speech to the default audio device.
24    pub fn new() -> Result<Self> {
25        let pending_speeches = Arc::new(Mutex::new(HashMap::<u32, PendingSpeech>::new()));
26        let handler = {
27            let pending_speeches = pending_speeches.clone();
28            move |id| {
29                let mut map = pending_speeches.lock().unwrap();
30                if let Some(PendingSpeech::Waiting(tx)) = map.remove(&id) {
31                    let _ = tx.send(());
32                } else {
33                    map.insert(id, PendingSpeech::Finished);
34                }
35            }
36        };
37        Ok(Self {
38            base: EventfulSynthesizer::new(handler)?,
39            pending_speeches,
40        })
41    }
42
43    /// Completes when the synthesizer finished rendering the given speech.
44    pub async fn speak<'s, S: Into<Speech<'s>>>(&self, speech: S) -> Result<()> {
45        let id = self.base.speak(speech)?;
46        if let Some(rx) = self.awaiter_for_speech_id(id) {
47            let _ = rx.await;
48        }
49        Ok(())
50    }
51
52    /// Queues up the rendering of the given speech and forgets about it.
53    ///
54    /// Note that this function can be used from both async and synchronous code. The speech will
55    /// be rendered, but there is no way to await its completion.
56    pub fn speak_and_forget<'s, S: Into<Speech<'s>>>(&self, speech: S) -> Result<()> {
57        let id = self.base.speak(speech)?;
58        let _ = self.awaiter_for_speech_id(id);
59        Ok(())
60    }
61
62    fn awaiter_for_speech_id(&self, id: u32) -> Option<Receiver<()>> {
63        let mut map = self.pending_speeches.lock().unwrap();
64        if let Some(PendingSpeech::Finished) = map.remove(&id) {
65            return None;
66        }
67        let (tx, rx) = channel();
68        map.insert(id, PendingSpeech::Waiting(tx));
69        Some(rx)
70    }
71}
72
73impl Deref for AsyncSynthesizer {
74    type Target = Synthesizer;
75    fn deref(&self) -> &Self::Target {
76        &self.base
77    }
78}