sapi_lite/stt/context/
sync.rs

1use std::ops::Deref;
2use std::time::Duration;
3
4use windows as Windows;
5use Windows::core::Interface;
6
7use crate::event::{Event, EventSource};
8use crate::stt::{Phrase, Recognizer};
9use crate::Result;
10
11use super::Context;
12
13/// A recognition context that blocks the current thread until the engine recognizes a phrase.
14pub struct SyncContext {
15    base: Context,
16    event_src: EventSource,
17}
18
19impl SyncContext {
20    /// Creates a new recognition context for the given recognizer.
21    pub fn new(recognizer: &Recognizer) -> Result<Self> {
22        let intf = unsafe { recognizer.intf.CreateRecoContext() }?;
23        unsafe { intf.SetNotifyWin32Event() }?;
24        Ok(SyncContext {
25            event_src: EventSource::from_sapi(intf.cast()?),
26            base: Context::new(intf, recognizer.pauser.clone()),
27        })
28    }
29
30    /// Blocks the current thread until the engine recognizes a phrase or until the given timeout
31    /// expires.
32    pub fn recognize(&self, timeout: Duration) -> Result<Option<Phrase>> {
33        let result = self.next_phrase()?;
34        if result.is_some() {
35            return Ok(result);
36        }
37
38        let timeout_ms: u32 = timeout.as_millis().try_into().unwrap_or(u32::MAX - 1);
39        unsafe { self.base.intf.WaitForNotifyEvent(timeout_ms) }?;
40
41        return self.next_phrase();
42    }
43
44    fn next_phrase(&self) -> Result<Option<Phrase>> {
45        while let Some(event) = self.event_src.next_event()? {
46            if let Event::Recognition(result) = event {
47                let phrase = Phrase::from_sapi(result)?;
48                return Ok(Some(phrase));
49            }
50        }
51        Ok(None)
52    }
53}
54
55impl Deref for SyncContext {
56    type Target = Context;
57    fn deref(&self) -> &Self::Target {
58        &self.base
59    }
60}