ndarilek / tts-rs

115 stars 25 forks source link

Provide function to wait until the voice finished speaking #52

Open Enyium opened 11 months ago

Enyium commented 11 months ago

In a use case (like automated UI tests to be monitored by a human) where you want to start the TTS, then perform actions, and then wait for the TTS to finish, there should be a waiting function Tts::wait().

You can incorporate the significant parts of this type into the Tts type:

struct SyncableTts {
    tts: Tts,
    last_utterance_id_with_condvar: Arc<(Mutex<Option<UtteranceId>>, Condvar)>,
}

impl SyncableTts {
    fn new() -> Result<Self> {
        let mut tts = Tts::default()?;

        let last_utterance_id_with_condvar = Arc::new((Mutex::new(None), Condvar::new()));
        let last_utterance_id_with_condvar_in_cb = last_utterance_id_with_condvar.clone();

        tts.on_utterance_end(Some(Box::new(move |utterance_id| {
            let (last_utterance_id, condvar) = &*last_utterance_id_with_condvar_in_cb;
            let mut last_utterance_id = last_utterance_id.lock().unwrap();
            if Some(utterance_id) == *last_utterance_id {
                *last_utterance_id = None;
                condvar.notify_all();
            }
        })))?;

        Ok(Self {
            tts,
            last_utterance_id_with_condvar,
        })
    }

    fn speak<S: Into<String>>(&mut self, text: S) -> Result<()> {
        let mut last_utterance_id = self.last_utterance_id_with_condvar.0.lock().unwrap();
        *last_utterance_id = Some(
            self.tts
                .speak(text, false)?
                .ok_or_else(|| anyhow!("got `None` utterance ID"))?,
        );

        Ok(())
    }

    fn wait(&self) {
        let (last_utterance_id, condvar) = &*self.last_utterance_id_with_condvar;
        let _guard = condvar
            .wait_while(last_utterance_id.lock().unwrap(), |last_utterance_id| {
                last_utterance_id.is_some()
            })
            .unwrap();
    }
}

Alternatively, the API could use async/await.