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 headers: Option<HashMap<String, String>>,
34}
35
36#[skip_serializing_none]
37#[derive(Debug, Deserialize, Serialize, Clone)]
38#[serde(rename_all = "camelCase")]
39pub struct CallOption {
40    pub denoise: Option<bool>,
41    pub offer: Option<String>,
42    pub callee: Option<String>,
43    pub caller: Option<String>,
44    pub recorder: Option<RecorderOption>,
45    pub vad: Option<VADOption>,
46    pub asr: Option<TranscriptionOption>,
47    pub tts: Option<SynthesisOption>,
48    pub media_pass: Option<MediaPassOption>,
49    pub handshake_timeout: Option<String>,
50    pub enable_ipv6: Option<bool>,
51    pub sip: Option<SipOption>,
52    pub extra: Option<HashMap<String, String>>,
53    pub codec: Option<String>, // pcmu, pcma, g722, pcm, only for websocket call
54    pub eou: Option<EouOption>,
55}
56
57impl Default for CallOption {
58    fn default() -> Self {
59        Self {
60            denoise: None,
61            offer: None,
62            callee: None,
63            caller: None,
64            recorder: None,
65            asr: None,
66            vad: None,
67            tts: None,
68            media_pass: None,
69            handshake_timeout: None,
70            enable_ipv6: None,
71            sip: None,
72            extra: None,
73            codec: None,
74            eou: None,
75        }
76    }
77}
78
79impl CallOption {
80    pub fn check_default(&mut self) {
81        if let Some(tts) = &mut self.tts {
82            tts.check_default();
83        }
84        if let Some(asr) = &mut self.asr {
85            asr.check_default();
86        }
87    }
88
89    pub fn build_invite_option(&self) -> Result<InviteOption> {
90        let mut invite_option = InviteOption::default();
91        if let Some(offer) = &self.offer {
92            invite_option.offer = Some(offer.clone().into());
93        }
94        if let Some(callee) = &self.callee {
95            invite_option.callee = callee.clone().try_into()?;
96        }
97        if let Some(caller) = &self.caller {
98            invite_option.caller = caller.clone().try_into()?;
99            invite_option.contact = invite_option.caller.clone();
100        }
101
102        if let Some(sip) = &self.sip {
103            invite_option.credential = Some(Credential {
104                username: sip.username.clone().unwrap_or_default(),
105                password: sip.password.clone().unwrap_or_default(),
106                realm: sip.realm.clone(),
107            });
108            invite_option.headers = sip.headers.as_ref().map(|h| {
109                h.iter()
110                    .map(|(k, v)| rsip::Header::Other(k.clone(), v.clone()))
111                    .collect::<Vec<_>>()
112            });
113        }
114        Ok(invite_option)
115    }
116}
117
118#[skip_serializing_none]
119#[derive(Debug, Deserialize, Serialize, Clone)]
120#[serde(rename_all = "camelCase")]
121pub struct ReferOption {
122    pub denoise: Option<bool>,
123    pub timeout: Option<u32>,
124    pub moh: Option<String>,
125    pub asr: Option<TranscriptionOption>,
126    /// hangup after the call is ended
127    pub auto_hangup: Option<bool>,
128    pub sip: Option<SipOption>,
129}
130
131#[skip_serializing_none]
132#[derive(Clone, Debug, Deserialize, Serialize)]
133#[serde(rename_all = "camelCase")]
134pub struct EouOption {
135    pub r#type: Option<String>,
136    pub endpoint: Option<String>,
137    pub secret_key: Option<String>,
138    pub secret_id: Option<String>,
139    /// max timeout in milliseconds
140    pub timeout: Option<u32>,
141    pub extra: Option<HashMap<String, String>>,
142}