1use std::collections::HashMap;
2
3pub type InviteHeaders = HashMap<String, Vec<(String, String)>>;
6
7#[derive(Debug, Clone, Copy)]
10pub struct MediaStats {
11 pub rtt_ms: f64,
13 pub jitter_ms: f64,
15 pub rx_lost: i32,
17 pub packet_loss_pct: f64,
19 pub mos: f64,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct CodecInfo {
26 pub name: String,
28 pub srate: u32,
30 pub ch: u8,
32}
33
34#[derive(Debug, Clone)]
35pub enum AppEvent {
36 Registering {
37 account: String,
38 },
39 RegisterOk {
40 account: String,
41 },
42 RegisterFailed {
43 reason: String,
44 },
45 Unregistered {
46 account: String,
47 },
48 CallIncoming {
49 call_id: String,
50 number: String,
51 display_name: Option<String>,
52 },
53 CallOutgoing {
54 call_id: String,
55 number: String,
56 },
57 CallRinging {
58 call_id: String,
59 },
60 CallEstablished {
61 call_id: String,
62 },
63 CallClosed {
64 call_id: String,
65 reason: String,
66 error: bool,
67 },
68 CallDeflected {
69 from: String,
70 display_name: Option<String>,
71 target: String,
72 },
73 CallHold {
76 call_id: String,
77 },
78 CallResume {
80 call_id: String,
81 },
82 CallTransferFailed {
85 call_id: String,
86 },
87 VoicemailStatus {
88 waiting: bool,
89 new_count: u32,
90 },
91 Response {
92 ok: bool,
93 data: String,
94 },
95 Unknown {
96 class: String,
97 type_: String,
98 },
99 BackendConnectFailed {
100 reason: String,
101 },
102}
103
104pub fn is_error_reason(reason: &str) -> bool {
107 if reason.is_empty() {
108 return false;
109 }
110 const NORMAL: &[&str] = &[
111 "Connection reset by peer",
112 "Connection closed",
113 "Rejected by user",
114 "Call transfered",
115 ];
116 !NORMAL
117 .iter()
118 .any(|n| reason.to_lowercase().starts_with(&n.to_lowercase()))
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
128 fn empty_reason_is_not_error() {
129 assert!(!is_error_reason(""));
130 }
131
132 #[test]
133 fn connection_reset_is_not_error() {
134 assert!(!is_error_reason("Connection reset by peer"));
135 }
136
137 #[test]
138 fn connection_reset_with_errno_is_not_error() {
139 assert!(!is_error_reason("Connection reset by peer [104]"));
140 }
141
142 #[test]
143 fn connection_closed_is_not_error() {
144 assert!(!is_error_reason("Connection closed"));
145 }
146
147 #[test]
148 fn rejected_by_user_is_not_error() {
149 assert!(!is_error_reason("Rejected by user"));
150 }
151
152 #[test]
153 fn sip_busy_is_error() {
154 assert!(is_error_reason("486 Busy Here"));
155 }
156
157 #[test]
158 fn sip_not_found_is_error() {
159 assert!(is_error_reason("404 Not Found"));
160 }
161}