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 created_at: Default::default(),
205 updated_at: Default::default(),
206 }),
207 },
208 self.base.auth_header(
209 Default::default(),
210 Some(SIPGrants { admin: true, ..Default::default() }),
211 )?,
212 )
213 .await
214 .map_err(Into::into)
215 }
216
217 pub async fn create_sip_outbound_trunk(
218 &self,
219 name: String,
220 address: String,
221 numbers: Vec<String>,
222 options: CreateSIPOutboundTrunkOptions,
223 ) -> ServiceResult<proto::SipOutboundTrunkInfo> {
224 self.client
225 .request(
226 SVC,
227 "CreateSIPOutboundTrunk",
228 proto::CreateSipOutboundTrunkRequest {
229 trunk: Some(proto::SipOutboundTrunkInfo {
230 sip_trunk_id: Default::default(),
231 name,
232 address,
233 numbers,
234 transport: options.transport as i32,
235 metadata: options.metadata,
236
237 auth_username: options.auth_username.to_owned(),
238 auth_password: options.auth_password.to_owned(),
239
240 headers: options.headers.unwrap_or_default(),
241 headers_to_attributes: options.headers_to_attributes.unwrap_or_default(),
242 attributes_to_headers: options.attributes_to_headers.unwrap_or_default(),
243
244 include_headers: Default::default(),
246 media_encryption: Default::default(),
247 destination_country: Default::default(),
248 created_at: Default::default(),
249 updated_at: Default::default(),
250 from_host: Default::default(),
251 }),
252 },
253 self.base.auth_header(
254 Default::default(),
255 Some(SIPGrants { admin: true, ..Default::default() }),
256 )?,
257 )
258 .await
259 .map_err(Into::into)
260 }
261
262 #[deprecated]
263 pub async fn list_sip_trunk(
264 &self,
265 filter: ListSIPTrunkFilter,
266 ) -> ServiceResult<Vec<proto::SipTrunkInfo>> {
267 let resp: proto::ListSipTrunkResponse = self
268 .client
269 .request(
270 SVC,
271 "ListSIPTrunk",
272 proto::ListSipTrunkRequest {
273 page: Default::default(),
275 },
276 self.base.auth_header(
277 Default::default(),
278 Some(SIPGrants { admin: true, ..Default::default() }),
279 )?,
280 )
281 .await?;
282
283 Ok(resp.items)
284 }
285
286 pub async fn list_sip_inbound_trunk(
287 &self,
288 filter: ListSIPInboundTrunkFilter,
289 ) -> ServiceResult<Vec<proto::SipInboundTrunkInfo>> {
290 let resp: proto::ListSipInboundTrunkResponse = self
291 .client
292 .request(
293 SVC,
294 "ListSIPInboundTrunk",
295 proto::ListSipInboundTrunkRequest {
296 page: Default::default(),
298 trunk_ids: Default::default(),
299 numbers: Default::default(),
300 },
301 self.base.auth_header(
302 Default::default(),
303 Some(SIPGrants { admin: true, ..Default::default() }),
304 )?,
305 )
306 .await?;
307
308 Ok(resp.items)
309 }
310
311 pub async fn list_sip_outbound_trunk(
312 &self,
313 filter: ListSIPOutboundTrunkFilter,
314 ) -> ServiceResult<Vec<proto::SipOutboundTrunkInfo>> {
315 let resp: proto::ListSipOutboundTrunkResponse = self
316 .client
317 .request(
318 SVC,
319 "ListSIPOutboundTrunk",
320 proto::ListSipOutboundTrunkRequest {
321 page: Default::default(),
323 trunk_ids: Default::default(),
324 numbers: Default::default(),
325 },
326 self.base.auth_header(
327 Default::default(),
328 Some(SIPGrants { admin: true, ..Default::default() }),
329 )?,
330 )
331 .await?;
332
333 Ok(resp.items)
334 }
335
336 pub async fn delete_sip_trunk(&self, sip_trunk_id: &str) -> ServiceResult<proto::SipTrunkInfo> {
337 self.client
338 .request(
339 SVC,
340 "DeleteSIPTrunk",
341 proto::DeleteSipTrunkRequest { sip_trunk_id: sip_trunk_id.to_owned() },
342 self.base.auth_header(
343 Default::default(),
344 Some(SIPGrants { admin: true, ..Default::default() }),
345 )?,
346 )
347 .await
348 .map_err(Into::into)
349 }
350
351 pub async fn create_sip_dispatch_rule(
352 &self,
353 rule: proto::sip_dispatch_rule::Rule,
354 options: CreateSIPDispatchRuleOptions,
355 ) -> ServiceResult<proto::SipDispatchRuleInfo> {
356 self.client
357 .request(
358 SVC,
359 "CreateSIPDispatchRule",
360 proto::CreateSipDispatchRuleRequest {
361 name: options.name,
362 metadata: options.metadata,
363 attributes: options.attributes,
364 trunk_ids: options.trunk_ids.to_owned(),
365 inbound_numbers: options.allowed_numbers.to_owned(),
366 hide_phone_number: options.hide_phone_number,
367 rule: Some(proto::SipDispatchRule { rule: Some(rule.to_owned()) }),
368
369 ..Default::default()
370 },
371 self.base.auth_header(
372 Default::default(),
373 Some(SIPGrants { admin: true, ..Default::default() }),
374 )?,
375 )
376 .await
377 .map_err(Into::into)
378 }
379
380 pub async fn list_sip_dispatch_rule(
381 &self,
382 filter: ListSIPDispatchRuleFilter,
383 ) -> ServiceResult<Vec<proto::SipDispatchRuleInfo>> {
384 let resp: proto::ListSipDispatchRuleResponse = self
385 .client
386 .request(
387 SVC,
388 "ListSIPDispatchRule",
389 proto::ListSipDispatchRuleRequest {
390 page: Default::default(),
392 dispatch_rule_ids: Default::default(),
393 trunk_ids: Default::default(),
394 },
395 self.base.auth_header(
396 Default::default(),
397 Some(SIPGrants { admin: true, ..Default::default() }),
398 )?,
399 )
400 .await?;
401
402 Ok(resp.items)
403 }
404
405 pub async fn delete_sip_dispatch_rule(
406 &self,
407 sip_dispatch_rule_id: &str,
408 ) -> ServiceResult<proto::SipDispatchRuleInfo> {
409 self.client
410 .request(
411 SVC,
412 "DeleteSIPDispatchRule",
413 proto::DeleteSipDispatchRuleRequest {
414 sip_dispatch_rule_id: sip_dispatch_rule_id.to_owned(),
415 },
416 self.base.auth_header(
417 Default::default(),
418 Some(SIPGrants { admin: true, ..Default::default() }),
419 )?,
420 )
421 .await
422 .map_err(Into::into)
423 }
424
425 pub async fn create_sip_participant(
426 &self,
427 sip_trunk_id: String,
428 call_to: String,
429 room_name: String,
430 options: CreateSIPParticipantOptions,
431 outbound_trunk_config: Option<proto::SipOutboundConfig>,
432 ) -> ServiceResult<proto::SipParticipantInfo> {
433 self.client
434 .request(
435 SVC,
436 "CreateSIPParticipant",
437 proto::CreateSipParticipantRequest {
438 sip_trunk_id: sip_trunk_id.to_owned(),
439 trunk: outbound_trunk_config,
440 sip_call_to: call_to.to_owned(),
441 sip_number: options.sip_number.to_owned().unwrap_or_default(),
442 room_name: room_name.to_owned(),
443 participant_identity: options.participant_identity.to_owned(),
444 participant_name: options.participant_name.to_owned().unwrap_or_default(),
445 participant_metadata: options
446 .participant_metadata
447 .to_owned()
448 .unwrap_or_default(),
449 participant_attributes: options
450 .participant_attributes
451 .to_owned()
452 .unwrap_or_default(),
453 dtmf: options.dtmf.to_owned().unwrap_or_default(),
454 wait_until_answered: options.wait_until_answered.unwrap_or(false),
455 play_ringtone: options.play_dialtone.unwrap_or(false),
456 play_dialtone: options.play_dialtone.unwrap_or(false),
457 hide_phone_number: options.hide_phone_number.unwrap_or(false),
458 max_call_duration: Self::duration_to_proto(options.max_call_duration),
459 ringing_timeout: Self::duration_to_proto(options.ringing_timeout),
460
461 krisp_enabled: options.enable_krisp.unwrap_or(false),
463
464 headers: Default::default(),
466 include_headers: Default::default(),
467 media_encryption: Default::default(),
468 ..Default::default()
469 },
470 self.base.auth_header(
471 Default::default(),
472 Some(SIPGrants { call: true, ..Default::default() }),
473 )?,
474 )
475 .await
476 .map_err(Into::into)
477 }
478}