1use serde::{Deserialize, Serialize};
11use std::fmt;
12use std::time::Duration;
13
14#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub enum CandidatePairState {
17 #[default]
18 #[serde(rename = "unspecified")]
19 Unspecified = 0,
21
22 #[serde(rename = "waiting")]
24 Waiting = 1,
25
26 #[serde(rename = "in-progress")]
28 InProgress = 2,
29
30 #[serde(rename = "failed")]
33 Failed = 3,
34
35 #[serde(rename = "succeeded")]
37 Succeeded = 4,
38}
39
40impl From<u8> for CandidatePairState {
41 fn from(v: u8) -> Self {
42 match v {
43 1 => Self::Waiting,
44 2 => Self::InProgress,
45 3 => Self::Failed,
46 4 => Self::Succeeded,
47 _ => Self::Unspecified,
48 }
49 }
50}
51
52impl fmt::Display for CandidatePairState {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 let s = match *self {
55 Self::Waiting => "waiting",
56 Self::InProgress => "in-progress",
57 Self::Failed => "failed",
58 Self::Succeeded => "succeeded",
59 Self::Unspecified => "unspecified",
60 };
61
62 write!(f, "{s}")
63 }
64}
65
66#[derive(Clone, Copy)]
68pub struct CandidatePair {
69 pub local_index: usize,
71 pub remote_index: usize,
73 pub local_priority: u32,
75 pub remote_priority: u32,
77 pub(crate) ice_role_controlling: bool,
78 pub(crate) binding_request_count: u16,
79 pub(crate) state: CandidatePairState,
80 pub(crate) nominated: bool,
81
82 pub(crate) requests_sent: u64,
85 pub(crate) requests_received: u64,
87 pub(crate) responses_sent: u64,
89 pub(crate) responses_received: u64,
91 pub(crate) consent_requests_sent: u64,
93
94 pub(crate) total_round_trip_time: Duration,
97 pub(crate) current_round_trip_time: Duration,
99}
100
101impl fmt::Debug 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 fmt::Display for CandidatePair {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 write!(
118 f,
119 "prio {} (local, prio {}) {} <-> {} (remote, prio {})",
120 self.priority(),
121 self.local_priority,
122 self.local_index,
123 self.remote_index,
124 self.remote_priority,
125 )
126 }
127}
128
129impl PartialEq for CandidatePair {
130 fn eq(&self, other: &Self) -> bool {
131 self.local_index == other.local_index && self.remote_index == other.remote_index
132 }
133}
134
135impl CandidatePair {
136 #[must_use]
137 pub fn new(
141 local_index: usize,
142 remote_index: usize,
143 local_priority: u32,
144 remote_priority: u32,
145 ice_role_controlling: bool,
146 ) -> Self {
147 Self {
148 local_index,
149 remote_index,
150 local_priority,
151 remote_priority,
152 ice_role_controlling,
153 state: CandidatePairState::Waiting,
154 binding_request_count: 0,
155 nominated: false,
156 requests_sent: 0,
158 requests_received: 0,
159 responses_sent: 0,
160 responses_received: 0,
161 consent_requests_sent: 0,
162 total_round_trip_time: Duration::ZERO,
164 current_round_trip_time: Duration::ZERO,
165 }
166 }
167
168 pub fn priority(&self) -> u64 {
174 let (g, d) = if self.ice_role_controlling {
175 (self.local_priority, self.remote_priority)
176 } else {
177 (self.remote_priority, self.local_priority)
178 };
179
180 ((1 << 32_u64) - 1) * u64::from(std::cmp::min(g, d))
183 + 2 * u64::from(std::cmp::max(g, d))
184 + u64::from(g > d)
185 }
186
187 pub fn on_request_sent(&mut self) {
189 self.requests_sent += 1;
190 }
191
192 pub fn on_request_received(&mut self) {
194 self.requests_received += 1;
195 }
196
197 pub fn on_response_sent(&mut self) {
199 self.responses_sent += 1;
200 }
201
202 pub fn on_response_received(&mut self, rtt: Duration) {
205 self.responses_received += 1;
206 self.current_round_trip_time = rtt;
207 self.total_round_trip_time += rtt;
208 }
209
210 pub fn on_consent_request_sent(&mut self) {
212 self.consent_requests_sent += 1;
213 }
214}