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