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