clawft_plugin/voice/
talk_mode.rs1use std::sync::Arc;
7
8use tracing::info;
9
10use crate::error::PluginError;
11use crate::traits::{CancellationToken, ChannelAdapter, ChannelAdapterHost};
12
13use super::channel::{VoiceChannel, VoiceStatus};
14
15pub struct TalkModeController {
21 channel: Arc<VoiceChannel>,
22 cancel: CancellationToken,
23}
24
25impl TalkModeController {
26 pub fn new(channel: Arc<VoiceChannel>, cancel: CancellationToken) -> Self {
33 Self { channel, cancel }
34 }
35
36 pub async fn run(&self, host: Arc<dyn ChannelAdapterHost>) -> Result<(), PluginError> {
43 info!("Talk Mode starting");
44 let result = self.channel.start(host, self.cancel.clone()).await;
45 info!("Talk Mode ended");
46 result
47 }
48
49 pub async fn status(&self) -> VoiceStatus {
51 self.channel.current_status().await
52 }
53
54 pub fn channel(&self) -> &Arc<VoiceChannel> {
56 &self.channel
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use std::collections::HashMap;
64
65 use async_trait::async_trait;
66 use crate::message::MessagePayload;
67
68 struct StubHost;
69
70 #[async_trait]
71 impl ChannelAdapterHost for StubHost {
72 async fn deliver_inbound(
73 &self,
74 _channel: &str,
75 _sender_id: &str,
76 _chat_id: &str,
77 _payload: MessagePayload,
78 _metadata: HashMap<String, serde_json::Value>,
79 ) -> Result<(), PluginError> {
80 Ok(())
81 }
82 }
83
84 #[tokio::test]
85 async fn talk_mode_status_starts_idle() {
86 let (channel, _rx) = VoiceChannel::new();
87 let cancel = CancellationToken::new();
88 let controller = TalkModeController::new(Arc::new(channel), cancel);
89 assert_eq!(controller.status().await, VoiceStatus::Idle);
90 }
91
92 #[tokio::test]
93 async fn talk_mode_run_and_cancel() {
94 let (channel, _rx) = VoiceChannel::new();
95 let cancel = CancellationToken::new();
96 let cancel_clone = cancel.clone();
97 let controller = Arc::new(TalkModeController::new(Arc::new(channel), cancel_clone));
98 let host: Arc<dyn ChannelAdapterHost> = Arc::new(StubHost);
99
100 let handle = tokio::spawn({
101 let controller = Arc::clone(&controller);
102 async move { controller.run(host).await }
103 });
104
105 tokio::time::sleep(std::time::Duration::from_millis(50)).await;
107
108 cancel.cancel();
109 let result = handle.await.unwrap();
110 assert!(result.is_ok());
111 }
112}