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