1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::time::Duration;
4
5#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
7pub enum CandidatePairState {
8 #[default]
9 #[serde(rename = "unspecified")]
10 Unspecified = 0,
11
12 #[serde(rename = "waiting")]
14 Waiting = 1,
15
16 #[serde(rename = "in-progress")]
18 InProgress = 2,
19
20 #[serde(rename = "failed")]
23 Failed = 3,
24
25 #[serde(rename = "succeeded")]
27 Succeeded = 4,
28}
29
30impl From<u8> for CandidatePairState {
31 fn from(v: u8) -> Self {
32 match v {
33 1 => Self::Waiting,
34 2 => Self::InProgress,
35 3 => Self::Failed,
36 4 => Self::Succeeded,
37 _ => Self::Unspecified,
38 }
39 }
40}
41
42impl fmt::Display for CandidatePairState {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 let s = match *self {
45 Self::Waiting => "waiting",
46 Self::InProgress => "in-progress",
47 Self::Failed => "failed",
48 Self::Succeeded => "succeeded",
49 Self::Unspecified => "unspecified",
50 };
51
52 write!(f, "{s}")
53 }
54}
55
56#[derive(Clone, Copy)]
58pub struct CandidatePair {
59 pub local_index: usize,
60 pub remote_index: usize,
61 pub local_priority: u32,
62 pub remote_priority: u32,
63 pub(crate) ice_role_controlling: bool,
64 pub(crate) binding_request_count: u16,
65 pub(crate) state: CandidatePairState,
66 pub(crate) nominated: bool,
67
68 pub(crate) requests_sent: u64,
71 pub(crate) requests_received: u64,
73 pub(crate) responses_sent: u64,
75 pub(crate) responses_received: u64,
77 pub(crate) consent_requests_sent: u64,
79
80 pub(crate) total_round_trip_time: Duration,
83 pub(crate) current_round_trip_time: Duration,
85}
86
87impl fmt::Debug for CandidatePair {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 write!(
90 f,
91 "prio {} (local, prio {}) {} <-> {} (remote, prio {})",
92 self.priority(),
93 self.local_priority,
94 self.local_index,
95 self.remote_index,
96 self.remote_priority,
97 )
98 }
99}
100
101impl fmt::Display for CandidatePair {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(
104 f,
105 "prio {} (local, prio {}) {} <-> {} (remote, prio {})",
106 self.priority(),
107 self.local_priority,
108 self.local_index,
109 self.remote_index,
110 self.remote_priority,
111 )
112 }
113}
114
115impl PartialEq for CandidatePair {
116 fn eq(&self, other: &Self) -> bool {
117 self.local_index == other.local_index && self.remote_index == other.remote_index
118 }
119}
120
121impl CandidatePair {
122 #[must_use]
123 pub fn new(
124 local_index: usize,
125 remote_index: usize,
126 local_priority: u32,
127 remote_priority: u32,
128 ice_role_controlling: bool,
129 ) -> Self {
130 Self {
131 local_index,
132 remote_index,
133 local_priority,
134 remote_priority,
135 ice_role_controlling,
136 state: CandidatePairState::Waiting,
137 binding_request_count: 0,
138 nominated: false,
139 requests_sent: 0,
141 requests_received: 0,
142 responses_sent: 0,
143 responses_received: 0,
144 consent_requests_sent: 0,
145 total_round_trip_time: Duration::ZERO,
147 current_round_trip_time: Duration::ZERO,
148 }
149 }
150
151 pub fn priority(&self) -> u64 {
157 let (g, d) = if self.ice_role_controlling {
158 (self.local_priority, self.remote_priority)
159 } else {
160 (self.remote_priority, self.local_priority)
161 };
162
163 ((1 << 32_u64) - 1) * u64::from(std::cmp::min(g, d))
166 + 2 * u64::from(std::cmp::max(g, d))
167 + u64::from(g > d)
168 }
169
170 pub fn on_request_sent(&mut self) {
172 self.requests_sent += 1;
173 }
174
175 pub fn on_request_received(&mut self) {
177 self.requests_received += 1;
178 }
179
180 pub fn on_response_sent(&mut self) {
182 self.responses_sent += 1;
183 }
184
185 pub fn on_response_received(&mut self, rtt: Duration) {
188 self.responses_received += 1;
189 self.current_round_trip_time = rtt;
190 self.total_round_trip_time += rtt;
191 }
192
193 pub fn on_consent_request_sent(&mut self) {
195 self.consent_requests_sent += 1;
196 }
197}