1pub use rvoip_core_traits::harness::*;
14
15use async_trait::async_trait;
16use rvoip_core_traits::error::Result;
17use rvoip_core_traits::ids::ConnectionId;
18use rvoip_core_traits::stream::MediaFrame;
19use std::sync::Mutex;
20
21pub struct NoOpAsrProvider;
22pub struct NoOpAsrStream;
23
24#[async_trait]
25impl AsrProvider for NoOpAsrProvider {
26 async fn open_stream(
27 &self,
28 _conn: ConnectionId,
29 _config: AsrConfig,
30 ) -> Result<Box<dyn AsrStream>> {
31 Ok(Box::new(NoOpAsrStream))
32 }
33}
34
35#[async_trait]
36impl AsrStream for NoOpAsrStream {
37 async fn push(&self, _frame: MediaFrame) -> Result<()> {
38 Ok(())
39 }
40 async fn next(&self) -> Option<AsrResult> {
41 None
42 }
43 async fn close(&self) -> Result<()> {
44 Ok(())
45 }
46}
47
48pub struct NoOpTtsProvider;
49pub struct NoOpTtsPlayback;
50
51#[async_trait]
52impl TtsProvider for NoOpTtsProvider {
53 async fn synthesize(&self, _request: TtsRequest) -> Result<Box<dyn TtsPlayback>> {
54 Ok(Box::new(NoOpTtsPlayback))
55 }
56}
57
58#[async_trait]
59impl TtsPlayback for NoOpTtsPlayback {
60 async fn next_frame(&self) -> Option<MediaFrame> {
61 None
62 }
63 async fn cancel(&self) -> Result<()> {
64 Ok(())
65 }
66}
67
68pub struct ListenOnlyDialog;
69
70#[async_trait]
71impl DialogManager for ListenOnlyDialog {
72 async fn turn(&self, _t: &AsrResult) -> Result<DialogAction> {
73 Ok(DialogAction::Listen)
74 }
75}
76
77pub struct VecRecordingSink {
78 inner: Mutex<Vec<u8>>,
79 url: String,
80}
81
82impl VecRecordingSink {
83 pub fn new(url: impl Into<String>) -> Self {
84 Self {
85 inner: Mutex::new(Vec::new()),
86 url: url.into(),
87 }
88 }
89
90 pub fn bytes(&self) -> Vec<u8> {
91 self.inner
92 .lock()
93 .expect("vec recording sink lock poisoned")
94 .clone()
95 }
96}
97
98#[async_trait]
99impl RecordingSink for VecRecordingSink {
100 async fn write(&self, frame: MediaFrame) -> Result<()> {
101 self.inner
102 .lock()
103 .expect("vec recording sink lock poisoned")
104 .extend_from_slice(&frame.payload);
105 Ok(())
106 }
107 async fn close(&self) -> Result<RecordingArtifact> {
108 let g = self.inner.lock().expect("vec recording sink lock poisoned");
109 Ok(RecordingArtifact {
110 url: self.url.clone(),
111 bytes_written: g.len() as u64,
112 duration_ms: 0,
113 content_hash: String::new(),
114 })
115 }
116}