voice_engine/
lib.rs

1use crate::{
2    media::{recorder::RecorderOption, track::media_pass::MediaPassOption, vad::VADOption},
3    synthesis::SynthesisOption,
4    transcription::TranscriptionOption,
5};
6use anyhow::Result;
7use rsipstack::dialog::{authenticate::Credential, invitation::InviteOption};
8use serde::{Deserialize, Serialize};
9use serde_with::skip_serializing_none;
10use std::collections::HashMap;
11
12pub mod event;
13pub mod media;
14pub mod net_tool;
15pub mod synthesis;
16pub mod transcription;
17
18#[derive(Default, Debug, Serialize, Deserialize, Clone)]
19pub struct IceServer {
20    pub urls: Vec<String>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub username: Option<String>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub credential: Option<String>,
25}
26
27#[derive(Debug, Deserialize, Serialize, Default, Clone)]
28#[serde(default)]
29pub struct SipOption {
30    pub username: Option<String>,
31    pub password: Option<String>,
32    pub realm: Option<String>,
33    pub contact: Option<String>,
34    pub headers: Option<HashMap<String, String>>,
35}
36
37#[skip_serializing_none]
38#[derive(Debug, Deserialize, Serialize, Clone)]
39#[serde(rename_all = "camelCase")]
40pub struct CallOption {
41    pub denoise: Option<bool>,
42    pub offer: Option<String>,
43    pub callee: Option<String>,
44    pub caller: Option<String>,
45    pub recorder: Option<RecorderOption>,
46    pub vad: Option<VADOption>,
47    pub asr: Option<TranscriptionOption>,
48    pub tts: Option<SynthesisOption>,
49    pub media_pass: Option<MediaPassOption>,
50    pub handshake_timeout: Option<String>,
51    pub enable_ipv6: Option<bool>,
52    pub sip: Option<SipOption>,
53    pub extra: Option<HashMap<String, String>>,
54    pub codec: Option<String>, // pcmu, pcma, g722, pcm, only for websocket call
55    pub eou: Option<EouOption>,
56}
57
58impl Default for CallOption {
59    fn default() -> Self {
60        Self {
61            denoise: None,
62            offer: None,
63            callee: None,
64            caller: None,
65            recorder: None,
66            asr: None,
67            vad: None,
68            tts: None,
69            media_pass: None,
70            handshake_timeout: None,
71            enable_ipv6: None,
72            sip: None,
73            extra: None,
74            codec: None,
75            eou: None,
76        }
77    }
78}
79
80impl CallOption {
81    pub fn check_default(&mut self) {
82        if let Some(tts) = &mut self.tts {
83            tts.check_default();
84        }
85        if let Some(asr) = &mut self.asr {
86            asr.check_default();
87        }
88    }
89
90    pub fn build_invite_option(&self) -> Result<InviteOption> {
91        let mut invite_option = InviteOption::default();
92        if let Some(offer) = &self.offer {
93            invite_option.offer = Some(offer.clone().into());
94        }
95        if let Some(callee) = &self.callee {
96            invite_option.callee = callee.clone().try_into()?;
97        }
98        if let Some(caller) = &self.caller {
99            invite_option.caller = caller.clone().try_into()?;
100            invite_option.contact = invite_option.caller.clone();
101        }
102
103        if let Some(sip) = &self.sip {
104            invite_option.credential = Some(Credential {
105                username: sip.username.clone().unwrap_or_default(),
106                password: sip.password.clone().unwrap_or_default(),
107                realm: sip.realm.clone(),
108            });
109            invite_option.headers = sip.headers.as_ref().map(|h| {
110                h.iter()
111                    .map(|(k, v)| rsip::Header::Other(k.clone(), v.clone()))
112                    .collect::<Vec<_>>()
113            });
114            sip.contact.as_ref().map(|c| match c.clone().try_into() {
115                Ok(u) => {
116                    invite_option.contact = u;
117                }
118                Err(_) => {}
119            });
120        }
121        Ok(invite_option)
122    }
123}
124
125#[skip_serializing_none]
126#[derive(Debug, Deserialize, Serialize, Clone)]
127#[serde(rename_all = "camelCase")]
128pub struct ReferOption {
129    pub denoise: Option<bool>,
130    pub timeout: Option<u32>,
131    pub moh: Option<String>,
132    pub asr: Option<TranscriptionOption>,
133    /// hangup after the call is ended
134    pub auto_hangup: Option<bool>,
135    pub sip: Option<SipOption>,
136}
137
138#[skip_serializing_none]
139#[derive(Clone, Debug, Deserialize, Serialize)]
140#[serde(rename_all = "camelCase")]
141pub struct EouOption {
142    pub r#type: Option<String>,
143    pub endpoint: Option<String>,
144    pub secret_key: Option<String>,
145    pub secret_id: Option<String>,
146    /// max timeout in milliseconds
147    pub timeout: Option<u32>,
148    pub extra: Option<HashMap<String, String>>,
149}