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