Skip to main content

videosdk/resources/sip/
mod.rs

1//! The SIP / telephony API.
2//!
3//! To route inbound calls to a room, provision numbers with
4//! [`PhoneNumbersResource`] and bind them with a
5//! [routing rule](SipRoutingRulesResource::create).
6
7pub mod calls;
8pub mod phone_numbers;
9pub mod routing_rules;
10pub mod trunks;
11pub mod webhooks;
12
13use serde::{Deserialize, Serialize};
14
15use crate::client::Client;
16use crate::common::string_enum;
17
18pub use calls::{
19    CreateSipCallParams, SipCall, SipCallListParams, SipCallsResource, SwitchRoomParams,
20    TransferSipCallParams,
21};
22pub use phone_numbers::{
23    CreatePhoneNumbersParams, PhoneNumberInboundConfig, PhoneNumberInfo, PhoneNumberListParams,
24    PhoneNumberOutboundConfig, PhoneNumberWithGateways, PhoneNumbersResource,
25    UpdatePhoneNumberGatewayParams,
26};
27pub use routing_rules::{
28    CreateRoutingRuleParams, RoutingRuleTarget, SipRoomConfig, SipRoutingRule,
29    SipRoutingRuleListParams, SipRoutingRulesResource, UpdateRoutingRuleParams,
30};
31pub use trunks::{
32    CreateInboundTrunkParams, CreateOutboundTrunkParams, InboundTrunkResource,
33    OutboundTrunkResource, SipTrunk, SipTrunkListParams, SipTrunksResource,
34    UpdateInboundTrunkParams, UpdateOutboundTrunkParams,
35};
36pub use webhooks::{CreateSipWebhookParams, SipWebhook, SipWebhookListParams, SipWebhooksResource};
37
38string_enum! {
39    /// A SIP transport protocol.
40    SipTransport {
41        /// UDP.
42        UDP => "udp",
43        /// TCP.
44        TCP => "tcp",
45        /// TLS. The default for outbound trunks.
46        TLS => "tls",
47    }
48}
49
50string_enum! {
51    /// Whether media is encrypted.
52    SipMediaEncryption {
53        /// Encrypt media.
54        ENABLE => "enable",
55        /// Do not encrypt media.
56        DISABLE => "disable",
57    }
58}
59
60string_enum! {
61    /// Which SIP headers to forward.
62    SipIncludeHeaders {
63        /// Forward every header.
64        ALL => "ALL",
65        /// Forward only `X-` headers.
66        SIP_X_HEADERS => "SIP_X_HEADERS",
67        /// Forward no headers.
68        NONE => "NONE",
69    }
70}
71
72string_enum! {
73    /// A routing-rule or call direction.
74    SipDirection {
75        /// Calls arriving from the provider.
76        INBOUND => "inbound",
77        /// Calls placed to the provider.
78        OUTBOUND => "outbound",
79    }
80}
81
82string_enum! {
83    /// How a routing rule allocates its destination room.
84    SipRoomType {
85        /// Every call lands in one fixed room.
86        STATIC => "static",
87        /// Each call gets a fresh room.
88        DYNAMIC => "dynamic",
89    }
90}
91
92string_enum! {
93    /// How a per-call room id is generated. A strategy, not a literal prefix.
94    SipRoomPrefix {
95        /// No prefix.
96        BLANK => "blank",
97        /// Prefix with the participant's number.
98        PARTICIPANT_NUMBER => "participantNumber",
99        /// Prefix with the SIP number.
100        SIP_NUMBER => "sipNumber",
101        /// Prefix randomly.
102        RANDOM => "random",
103    }
104}
105
106string_enum! {
107    /// A SIP-capable region.
108    SipRegion {
109        /// Pick the closest region automatically.
110        AUTO => "auto",
111        /// `us002`
112        US002 => "us002",
113        /// `in002`
114        IN002 => "in002",
115    }
116}
117
118string_enum! {
119    /// A call's lifecycle status.
120    SipCallStatus {
121        /// The call has been created.
122        INITIATED => "initiated",
123        /// The destination is ringing.
124        RINGING => "ringing",
125        /// Nobody answered in time.
126        MISSED => "missed",
127        /// The call was not answered.
128        NOT_ANSWERED => "not-answered",
129        /// The call failed.
130        FAILED => "failed",
131        /// An inbound call is arriving.
132        INCOMING => "incoming",
133        /// The caller was verified.
134        VERIFIED => "verified",
135        /// The call was rejected.
136        REJECTED => "rejected",
137        /// The caller hung up before it was answered.
138        ABANDONED => "abandoned",
139        /// The call was answered.
140        ANSWERED => "answered",
141        /// The call has ended.
142        ENDED => "ended",
143        /// A transfer has started.
144        TRANSFER_INITIATED => "transfer-initiated",
145        /// The transfer was accepted.
146        TRANSFER_ACCEPTED => "transfer-accepted",
147        /// The transfer is in progress.
148        TRANSFERRING => "transferring",
149        /// The transfer destination is ringing.
150        TRANSFER_RINGING => "transfer-ringing",
151        /// The call was transferred.
152        TRANSFERRED => "transferred",
153        /// The transfer failed.
154        TRANSFER_FAILED => "transfer-failed",
155        /// A room switch has started.
156        SWITCH_ROOM_INITIATED => "switch-room-initiated",
157        /// The room switch completed.
158        SWITCH_ROOM_COMPLETED => "switch-room-completed",
159        /// The room switch failed.
160        SWITCH_ROOM_FAILED => "switch-room-failed",
161    }
162}
163
164string_enum! {
165    /// A SIP call-lifecycle webhook event.
166    SipWebhookEvent {
167        /// A call started.
168        CALL_STARTED => "call-started",
169        /// A call was answered.
170        CALL_ANSWERED => "call-answered",
171        /// A call hung up.
172        CALL_HANGUP => "call-hangup",
173        /// A call was transferred.
174        CALL_TRANSFERRED => "call-transferred",
175        /// A call was missed.
176        CALL_MISSED => "call-missed",
177        /// A call was updated.
178        CALL_UPDATE => "call-update",
179        /// A call is ringing.
180        CALL_RINGING => "call-ringing",
181        /// A transfer has started.
182        CALL_TRANSFER_INITIATED => "call-transfer-initiated",
183        /// A transfer was accepted.
184        CALL_TRANSFER_ACCEPTED => "call-transfer-accepted",
185        /// A transfer is in progress.
186        CALL_TRANSFERRING => "call-transferring",
187        /// A transfer destination is ringing.
188        CALL_TRANSFER_RINGING => "call-transfer-ringing",
189        /// A transfer failed.
190        CALL_TRANSFER_FAILED => "call-transfer-failed",
191        /// A room switch has started.
192        SWITCH_ROOM_INITIATED => "switch-room-initiated",
193        /// A room switch completed.
194        SWITCH_ROOM_COMPLETED => "switch-room-completed",
195        /// A room switch failed.
196        SWITCH_ROOM_FAILED => "switch-room-failed",
197    }
198}
199
200/// SIP credentials.
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct SipAuth {
203    /// The SIP username.
204    pub username: String,
205    /// The SIP password.
206    pub password: String,
207}
208
209/// The SIP / telephony API. Reached via [`Client::sip`].
210#[derive(Debug, Clone, Copy)]
211pub struct SipResource<'a> {
212    client: &'a Client,
213}
214
215impl<'a> SipResource<'a> {
216    pub(crate) fn new(client: &'a Client) -> Self {
217        Self { client }
218    }
219
220    /// SIP trunks: the inbound and outbound connections to your provider.
221    pub fn trunks(&self) -> SipTrunksResource<'a> {
222        SipTrunksResource::new(self.client)
223    }
224
225    /// SIP routing rules, which bind provisioned numbers to a dispatch target.
226    pub fn routing_rules(&self) -> SipRoutingRulesResource<'a> {
227        SipRoutingRulesResource::new(self.client)
228    }
229
230    /// Provisioned phone numbers, and the gateways attached to them.
231    pub fn phone_numbers(&self) -> PhoneNumbersResource<'a> {
232        PhoneNumbersResource::new(self.client)
233    }
234
235    /// Places and manages SIP calls.
236    pub fn calls(&self) -> SipCallsResource<'a> {
237        SipCallsResource::new(self.client)
238    }
239
240    /// Webhooks delivering SIP call-event notifications.
241    ///
242    /// This manages webhook *configuration*. It is unrelated to verifying the
243    /// signature of an inbound webhook.
244    pub fn webhooks(&self) -> SipWebhooksResource<'a> {
245        SipWebhooksResource::new(self.client)
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252    use serde_json::json;
253
254    #[test]
255    fn string_enums_round_trip_their_wire_values() {
256        assert_eq!(SipTransport::TLS.as_str(), "tls");
257        assert_eq!(SipIncludeHeaders::SIP_X_HEADERS.as_str(), "SIP_X_HEADERS");
258        assert_eq!(
259            SipRoomPrefix::PARTICIPANT_NUMBER.as_str(),
260            "participantNumber"
261        );
262        assert_eq!(SipCallStatus::NOT_ANSWERED.as_str(), "not-answered");
263        assert_eq!(
264            SipWebhookEvent::SWITCH_ROOM_COMPLETED.as_str(),
265            "switch-room-completed"
266        );
267        assert_eq!(
268            serde_json::to_value(SipDirection::INBOUND).unwrap(),
269            json!("inbound")
270        );
271    }
272
273    /// A closed enum would fail here, taking the whole response with it.
274    #[test]
275    fn an_unknown_value_still_deserializes() {
276        let status: SipCallStatus = serde_json::from_value(json!("some-future-status")).unwrap();
277        assert_eq!(status.as_str(), "some-future-status");
278        assert_eq!(
279            serde_json::to_value(&status).unwrap(),
280            json!("some-future-status")
281        );
282    }
283}