clawft_plugin/voice/
wake_daemon.rs1use tracing::info;
11
12use crate::error::PluginError;
13use crate::traits::CancellationToken;
14
15use super::wake::{WakeWordConfig, WakeWordDetector};
16
17pub struct WakeDaemon {
22 detector: WakeWordDetector,
23 active: bool,
24}
25
26impl WakeDaemon {
27 pub fn new(config: WakeWordConfig) -> Result<Self, PluginError> {
29 let detector = WakeWordDetector::new(config)?;
30 Ok(Self {
31 detector,
32 active: false,
33 })
34 }
35
36 #[cfg(not(target_arch = "wasm32"))]
42 pub async fn run(&mut self, cancel: CancellationToken) -> Result<(), PluginError> {
43 info!("wake daemon started (stub)");
44 self.active = true;
45 self.detector.start();
46
47 cancel.cancelled().await;
49
50 self.detector.stop();
51 self.active = false;
52 info!("wake daemon stopped");
53 Ok(())
54 }
55
56 pub fn is_active(&self) -> bool {
58 self.active
59 }
60
61 pub fn detector(&self) -> &WakeWordDetector {
63 &self.detector
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn wake_daemon_create() {
73 let config = WakeWordConfig::default();
74 let daemon = WakeDaemon::new(config).unwrap();
75 assert!(!daemon.is_active());
76 }
77
78 #[test]
79 fn wake_daemon_detector_access() {
80 let config = WakeWordConfig {
81 threshold: 0.3,
82 ..Default::default()
83 };
84 let daemon = WakeDaemon::new(config).unwrap();
85 assert!((daemon.detector().config().threshold - 0.3).abs() < f32::EPSILON);
86 }
87
88 #[tokio::test]
89 async fn wake_daemon_run_and_cancel() {
90 let config = WakeWordConfig::default();
91 let mut daemon = WakeDaemon::new(config).unwrap();
92 let cancel = CancellationToken::new();
93 let cancel_clone = cancel.clone();
94
95 let handle = tokio::spawn(async move { daemon.run(cancel_clone).await });
96
97 tokio::time::sleep(std::time::Duration::from_millis(50)).await;
99
100 cancel.cancel();
102 let result = handle.await.unwrap();
103 assert!(result.is_ok());
104 }
105}