1use livekit_protocol as proto;
16use std::collections::HashMap;
17use std::time::Duration;
18
19use crate::access_token::SIPGrants;
20use crate::get_env_keys;
21use crate::services::twirp_client::TwirpClient;
22use crate::services::{ServiceBase, ServiceResult, LIVEKIT_PACKAGE};
23use pbjson_types::Duration as ProtoDuration;
24
25const SVC: &str = "SIP";
26
27#[derive(Debug)]
28pub struct SIPClient {
29 base: ServiceBase,
30 client: TwirpClient,
31}
32
33#[deprecated]
34#[derive(Default, Clone, Debug)]
35pub struct CreateSIPTrunkOptions {
36 pub name: String,
38 pub metadata: String,
40 pub inbound_addresses: Vec<String>,
43 pub inbound_numbers: Vec<String>,
47 pub inbound_username: String,
50 pub inbound_password: String,
51
52 pub outbound_address: String,
54 pub outbound_username: String,
57 pub outbound_password: String,
58}
59
60#[derive(Default, Clone, Debug)]
61pub struct CreateSIPInboundTrunkOptions {
62 pub metadata: Option<String>,
64 pub allowed_addresses: Option<Vec<String>>,
67 pub allowed_numbers: Option<Vec<String>>,
71 pub auth_username: Option<String>,
74 pub auth_password: Option<String>,
75 pub headers: Option<HashMap<String, String>>,
76 pub headers_to_attributes: Option<HashMap<String, String>>,
77 pub attributes_to_headers: Option<HashMap<String, String>>,
78 pub max_call_duration: Option<Duration>,
79 pub ringing_timeout: Option<Duration>,
80 pub krisp_enabled: Option<bool>,
81}
82
83#[derive(Default, Clone, Debug)]
84pub struct CreateSIPOutboundTrunkOptions {
85 pub transport: proto::SipTransport,
86 pub metadata: String,
88 pub auth_username: String,
91 pub auth_password: String,
92
93 pub headers: Option<HashMap<String, String>>,
94 pub headers_to_attributes: Option<HashMap<String, String>>,
95 pub attributes_to_headers: Option<HashMap<String, String>>,
96}
97
98#[deprecated]
99#[derive(Debug, Clone, PartialEq, Eq)]
100pub enum ListSIPTrunkFilter {
101 All,
102}
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub enum ListSIPInboundTrunkFilter {
105 All,
106}
107#[derive(Debug, Clone, PartialEq, Eq)]
108pub enum ListSIPOutboundTrunkFilter {
109 All,
110}
111
112#[derive(Default, Clone, Debug)]
113pub struct CreateSIPDispatchRuleOptions {
114 pub name: String,
115 pub metadata: String,
116 pub attributes: HashMap<String, String>,
117 pub trunk_ids: Vec<String>,
120 pub allowed_numbers: Vec<String>,
121 pub hide_phone_number: bool,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub enum ListSIPDispatchRuleFilter {
126 All,
127}
128
129#[derive(Default, Clone, Debug)]
130pub struct CreateSIPParticipantOptions {
131 pub participant_identity: String,
133 pub participant_name: Option<String>,
135 pub participant_metadata: Option<String>,
137 pub participant_attributes: Option<HashMap<String, String>>,
138 pub sip_number: Option<String>,
140 pub dtmf: Option<String>,
143 pub wait_until_answered: Option<bool>,
149 pub play_dialtone: Option<bool>,
151 pub hide_phone_number: Option<bool>,
152 pub ringing_timeout: Option<Duration>,
153 pub max_call_duration: Option<Duration>,
154 pub enable_krisp: Option<bool>,
155}
156
157impl SIPClient {
158 pub fn with_api_key(host: &str, api_key: &str, api_secret: &str) -> Self {
159 Self {
160 base: ServiceBase::with_api_key(api_key, api_secret),
161 client: TwirpClient::new(host, LIVEKIT_PACKAGE, None),
162 }
163 }
164
165 pub fn new(host: &str) -> ServiceResult<Self> {
166 let (api_key, api_secret) = get_env_keys()?;
167 Ok(Self::with_api_key(host, &api_key, &api_secret))
168 }
169
170 fn duration_to_proto(d: Option<Duration>) -> Option<ProtoDuration> {
171 d.map(|d| ProtoDuration { seconds: d.as_secs() as i64, nanos: d.subsec_nanos() as i32 })
172 }
173
174 pub async fn create_sip_inbound_trunk(
175 &self,
176 name: String,
177 numbers: Vec<String>,
178 options: CreateSIPInboundTrunkOptions,
179 ) -> ServiceResult<proto::SipInboundTrunkInfo> {
180 self.client
181 .request(
182 SVC,
183 "CreateSIPInboundTrunk",
184 proto::CreateSipInboundTrunkRequest {
185 trunk: Some(proto::SipInboundTrunkInfo {
186 sip_trunk_id: Default::default(),
187 name,
188 numbers,
189 metadata: options.metadata.unwrap_or_default(),
190 allowed_numbers: options.allowed_numbers.unwrap_or_default(),
191 allowed_addresses: options.allowed_addresses.unwrap_or_default(),
192 auth_username: options.auth_username.unwrap_or_default(),
193 auth_password: options.auth_password.unwrap_or_default(),
194 headers: options.headers.unwrap_or_default(),
195 headers_to_attributes: options.headers_to_attributes.unwrap_or_default(),
196 attributes_to_headers: options.attributes_to_headers.unwrap_or_default(),
197 krisp_enabled: options.krisp_enabled.unwrap_or(false),
198 max_call_duration: Self::duration_to_proto(options.max_call_duration),
199 ringing_timeout: Self::duration_to_proto(options.ringing_timeout),
200
201 include_headers: Default::default(),
203 media_encryption: Default::default(),
204 }),
205 },
206 self.base.auth_header(
207 Default::default(),
208 Some(SIPGrants { admin: true, ..Default::default() }),
209 )?,
210 )
211 .await
212 .map_err(Into::into)
213 }
214
215 pub async fn create_sip_outbound_trunk(
216 &self,
217 name: String,
218 address: String,
219 numbers: Vec<String>,
220 options: CreateSIPOutboundTrunkOptions,
221 ) -> ServiceResult<proto::SipOutboundTrunkInfo> {
222 self.client
223 .request(
224 SVC,
225 "CreateSIPOutboundTrunk",
226 proto::CreateSipOutboundTrunkRequest {
227 trunk: Some(proto::SipOutboundTrunkInfo {
228 sip_trunk_id: Default::default(),
229 name,
230 address,
231 numbers,
232 transport: options.transport as i32,
233 metadata: options.metadata,
234
235 auth_username: options.auth_username.to_owned(),
236 auth_password: options.auth_password.to_owned(),
237
238 headers: options.headers.unwrap_or_default(),
239 headers_to_attributes: options.headers_to_attributes.unwrap_or_default(),
240 attributes_to_headers: options.attributes_to_headers.unwrap_or_default(),
241
242 include_headers: Default::default(),
244 media_encryption: Default::default(),
245 destination_country: Default::default(),
246 }),
247 },
248 self.base.auth_header(
249 Default::default(),
250 Some(SIPGrants { admin: true, ..Default::default() }),
251 )?,
252 )
253 .await
254 .map_err(Into::into)
255 }
256
257 #[deprecated]
258 pub async fn list_sip_trunk(
259 &self,
260 filter: ListSIPTrunkFilter,
261 ) -> ServiceResult<Vec<proto::SipTrunkInfo>> {
262 let resp: proto::ListSipTrunkResponse = self
263 .client
264 .request(
265 SVC,
266 "ListSIPTrunk",
267 proto::ListSipTrunkRequest {
268 page: Default::default(),
270 },
271 self.base.auth_header(
272 Default::default(),
273 Some(SIPGrants { admin: true, ..Default::default() }),
274 )?,
275 )
276 .await?;
277
278 Ok(resp.items)
279 }
280
281 pub async fn list_sip_inbound_trunk(
282 &self,
283 filter: ListSIPInboundTrunkFilter,
284 ) -> ServiceResult<Vec<proto::SipInboundTrunkInfo>> {
285 let resp: proto::ListSipInboundTrunkResponse = self
286 .client
287 .request(
288 SVC,
289 "ListSIPInboundTrunk",
290 proto::ListSipInboundTrunkRequest {
291 page: Default::default(),
293 trunk_ids: Default::default(),
294 numbers: Default::default(),
295 },
296 self.base.auth_header(
297 Default::default(),
298 Some(SIPGrants { admin: true, ..Default::default() }),
299 )?,
300 )
301 .await?;
302
303 Ok(resp.items)
304 }
305
306 pub async fn list_sip_outbound_trunk(
307 &self,
308 filter: ListSIPOutboundTrunkFilter,
309 ) -> ServiceResult<Vec<proto::SipOutboundTrunkInfo>> {
310 let resp: proto::ListSipOutboundTrunkResponse = self
311 .client
312 .request(
313 SVC,
314 "ListSIPOutboundTrunk",
315 proto::ListSipOutboundTrunkRequest {
316 page: Default::default(),
318 trunk_ids: Default::default(),
319 numbers: Default::default(),
320 },
321 self.base.auth_header(
322 Default::default(),
323 Some(SIPGrants { admin: true, ..Default::default() }),
324 )?,
325 )
326 .await?;
327
328 Ok(resp.items)
329 }
330
331 pub async fn delete_sip_trunk(&self, sip_trunk_id: &str) -> ServiceResult<proto::SipTrunkInfo> {
332 self.client
333 .request(
334 SVC,
335 "DeleteSIPTrunk",
336 proto::DeleteSipTrunkRequest { sip_trunk_id: sip_trunk_id.to_owned() },
337 self.base.auth_header(
338 Default::default(),
339 Some(SIPGrants { admin: true, ..Default::default() }),
340 )?,
341 )
342 .await
343 .map_err(Into::into)
344 }
345
346 pub async fn create_sip_dispatch_rule(
347 &self,
348 rule: proto::sip_dispatch_rule::Rule,
349 options: CreateSIPDispatchRuleOptions,
350 ) -> ServiceResult<proto::SipDispatchRuleInfo> {
351 self.client
352 .request(
353 SVC,
354 "CreateSIPDispatchRule",
355 proto::CreateSipDispatchRuleRequest {
356 name: options.name,
357 metadata: options.metadata,
358 attributes: options.attributes,
359 trunk_ids: options.trunk_ids.to_owned(),
360 inbound_numbers: options.allowed_numbers.to_owned(),
361 hide_phone_number: options.hide_phone_number,
362 rule: Some(proto::SipDispatchRule { rule: Some(rule.to_owned()) }),
363
364 ..Default::default()
365 },
366 self.base.auth_header(
367 Default::default(),
368 Some(SIPGrants { admin: true, ..Default::default() }),
369 )?,
370 )
371 .await
372 .map_err(Into::into)
373 }
374
375 pub async fn list_sip_dispatch_rule(
376 &self,
377 filter: ListSIPDispatchRuleFilter,
378 ) -> ServiceResult<Vec<proto::SipDispatchRuleInfo>> {
379 let resp: proto::ListSipDispatchRuleResponse = self
380 .client
381 .request(
382 SVC,
383 "ListSIPDispatchRule",
384 proto::ListSipDispatchRuleRequest {
385 page: Default::default(),
387 dispatch_rule_ids: Default::default(),
388 trunk_ids: Default::default(),
389 },
390 self.base.auth_header(
391 Default::default(),
392 Some(SIPGrants { admin: true, ..Default::default() }),
393 )?,
394 )
395 .await?;
396
397 Ok(resp.items)
398 }
399
400 pub async fn delete_sip_dispatch_rule(
401 &self,
402 sip_dispatch_rule_id: &str,
403 ) -> ServiceResult<proto::SipDispatchRuleInfo> {
404 self.client
405 .request(
406 SVC,
407 "DeleteSIPDispatchRule",
408 proto::DeleteSipDispatchRuleRequest {
409 sip_dispatch_rule_id: sip_dispatch_rule_id.to_owned(),
410 },
411 self.base.auth_header(
412 Default::default(),
413 Some(SIPGrants { admin: true, ..Default::default() }),
414 )?,
415 )
416 .await
417 .map_err(Into::into)
418 }
419
420 pub async fn create_sip_participant(
421 &self,
422 sip_trunk_id: String,
423 call_to: String,
424 room_name: String,
425 options: CreateSIPParticipantOptions,
426 outbound_trunk_config: Option<proto::SipOutboundConfig>,
427 ) -> ServiceResult<proto::SipParticipantInfo> {
428 self.client
429 .request(
430 SVC,
431 "CreateSIPParticipant",
432 proto::CreateSipParticipantRequest {
433 sip_trunk_id: sip_trunk_id.to_owned(),
434 trunk: outbound_trunk_config,
435 sip_call_to: call_to.to_owned(),
436 sip_number: options.sip_number.to_owned().unwrap_or_default(),
437 room_name: room_name.to_owned(),
438 participant_identity: options.participant_identity.to_owned(),
439 participant_name: options.participant_name.to_owned().unwrap_or_default(),
440 participant_metadata: options
441 .participant_metadata
442 .to_owned()
443 .unwrap_or_default(),
444 participant_attributes: options
445 .participant_attributes
446 .to_owned()
447 .unwrap_or_default(),
448 dtmf: options.dtmf.to_owned().unwrap_or_default(),
449 wait_until_answered: options.wait_until_answered.unwrap_or(false),
450 play_ringtone: options.play_dialtone.unwrap_or(false),
451 play_dialtone: options.play_dialtone.unwrap_or(false),
452 hide_phone_number: options.hide_phone_number.unwrap_or(false),
453 max_call_duration: Self::duration_to_proto(options.max_call_duration),
454 ringing_timeout: Self::duration_to_proto(options.ringing_timeout),
455
456 krisp_enabled: options.enable_krisp.unwrap_or(false),
458
459 headers: Default::default(),
461 include_headers: Default::default(),
462 media_encryption: Default::default(),
463 ..Default::default()
464 },
465 self.base.auth_header(
466 Default::default(),
467 Some(SIPGrants { call: true, ..Default::default() }),
468 )?,
469 )
470 .await
471 .map_err(Into::into)
472 }
473}