rtc_ice/agent/agent_stats.rs
1use crate::agent::Agent;
2use std::time::Instant;
3
4use crate::candidate::{CandidateType, candidate_pair::CandidatePairState};
5use crate::network_type::NetworkType;
6
7/// Contains ICE candidate pair statistics.
8pub struct CandidatePairStats {
9 /// The timestamp associated with this struct.
10 /// When this snapshot was taken.
11 pub timestamp: Instant,
12
13 /// The id of the local candidate.
14 pub local_candidate_id: String,
15
16 /// The id of the remote candidate.
17 pub remote_candidate_id: String,
18
19 /// The state of the checklist for the local and remote candidates in a pair.
20 pub state: CandidatePairState,
21
22 /// It is true when this valid pair that should be used for media,
23 /// if it is the highest-priority one amongst those whose nominated flag is set.
24 pub nominated: bool,
25
26 /// The total number of packets sent on this candidate pair.
27 pub packets_sent: u32,
28
29 /// The total number of packets received on this candidate pair.
30 pub packets_received: u32,
31
32 /// The total number of payload bytes sent on this candidate pair not including headers or
33 /// padding.
34 pub bytes_sent: u64,
35
36 /// The total number of payload bytes received on this candidate pair not including headers or
37 /// padding.
38 pub bytes_received: u64,
39
40 /// The timestamp at which the last packet was sent on this particular candidate pair, excluding
41 /// STUN packets.
42 pub last_packet_sent_timestamp: Instant,
43
44 /// The timestamp at which the last packet was received on this particular candidate pair,
45 /// excluding STUN packets.
46 pub last_packet_received_timestamp: Instant,
47
48 /// The timestamp at which the first STUN request was sent on this particular candidate pair.
49 pub first_request_timestamp: Instant,
50
51 /// The timestamp at which the last STUN request was sent on this particular candidate pair.
52 /// The average interval between two consecutive connectivity checks sent can be calculated with
53 /// (last_request_timestamp - first_request_timestamp) / requests_sent.
54 pub last_request_timestamp: Instant,
55
56 /// Timestamp at which the last STUN response was received on this particular candidate pair.
57 pub last_response_timestamp: Instant,
58
59 /// The sum of all round trip time measurements in seconds since the beginning of the session,
60 /// based on STUN connectivity check responses (responses_received), including those that reply
61 /// to requests that are sent in order to verify consent. The average round trip time can be
62 /// computed from total_round_trip_time by dividing it by responses_received.
63 pub total_round_trip_time: f64,
64
65 /// The latest round trip time measured in seconds, computed from both STUN connectivity checks,
66 /// including those that are sent for consent verification.
67 pub current_round_trip_time: f64,
68
69 /// It is calculated by the underlying congestion control by combining the available bitrate for
70 /// all the outgoing RTP streams using this candidate pair. The bitrate measurement does not
71 /// count the size of the IP or other transport layers like TCP or UDP. It is similar to the
72 /// TIAS defined in RFC 3890, i.e., it is measured in bits per second and the bitrate is
73 /// calculated over a 1 second window.
74 pub available_outgoing_bitrate: f64,
75
76 /// It is calculated by the underlying congestion control by combining the available bitrate for
77 /// all the incoming RTP streams using this candidate pair. The bitrate measurement does not
78 /// count the size of the IP or other transport layers like TCP or UDP. It is similar to the
79 /// TIAS defined in RFC 3890, i.e., it is measured in bits per second and the bitrate is
80 /// calculated over a 1 second window.
81 pub available_incoming_bitrate: f64,
82
83 /// The number of times the circuit breaker is triggered for this particular 5-tuple,
84 /// ceasing transmission.
85 pub circuit_breaker_trigger_count: u32,
86
87 /// The total number of connectivity check requests received (including retransmissions).
88 /// It is impossible for the receiver to tell whether the request was sent in order to check
89 /// connectivity or check consent, so all connectivity checks requests are counted here.
90 pub requests_received: u64,
91
92 /// The total number of connectivity check requests sent (not including retransmissions).
93 pub requests_sent: u64,
94
95 /// The total number of connectivity check responses received.
96 pub responses_received: u64,
97
98 /// The total number of connectivity check responses sent. Since we cannot distinguish
99 /// connectivity check requests and consent requests, all responses are counted.
100 pub responses_sent: u64,
101
102 /// The total number of connectivity check request retransmissions received.
103 pub retransmissions_received: u64,
104
105 /// The total number of connectivity check request retransmissions sent.
106 pub retransmissions_sent: u64,
107
108 /// The total number of consent requests sent.
109 pub consent_requests_sent: u64,
110
111 /// The timestamp at which the latest valid STUN binding response expired.
112 pub consent_expired_timestamp: Instant,
113}
114
115impl Default for CandidatePairStats {
116 fn default() -> Self {
117 Self {
118 timestamp: Instant::now(),
119 local_candidate_id: String::new(),
120 remote_candidate_id: String::new(),
121 state: CandidatePairState::default(),
122 nominated: false,
123 packets_sent: 0,
124 packets_received: 0,
125 bytes_sent: 0,
126 bytes_received: 0,
127 last_packet_sent_timestamp: Instant::now(),
128 last_packet_received_timestamp: Instant::now(),
129 first_request_timestamp: Instant::now(),
130 last_request_timestamp: Instant::now(),
131 last_response_timestamp: Instant::now(),
132 total_round_trip_time: 0.0,
133 current_round_trip_time: 0.0,
134 available_outgoing_bitrate: 0.0,
135 available_incoming_bitrate: 0.0,
136 circuit_breaker_trigger_count: 0,
137 requests_received: 0,
138 requests_sent: 0,
139 responses_received: 0,
140 responses_sent: 0,
141 retransmissions_received: 0,
142 retransmissions_sent: 0,
143 consent_requests_sent: 0,
144 consent_expired_timestamp: Instant::now(),
145 }
146 }
147}
148
149/// Contains ICE candidate statistics related to the `ICETransport` objects.
150#[derive(Debug, Clone)]
151pub struct CandidateStats {
152 /// The timestamp associated with this struct.
153 pub timestamp: Instant,
154
155 /// The candidate id.
156 pub id: String,
157
158 /// The type of network interface used by the base of a local candidate (the address the ICE
159 /// agent sends from). Only present for local candidates; it's not possible to know what type of
160 /// network interface a remote candidate is using.
161 ///
162 /// Note: This stat only tells you about the network interface used by the first "hop"; it's
163 /// possible that a connection will be bottlenecked by another type of network. For example,
164 /// when using Wi-Fi tethering, the networkType of the relevant candidate would be "wifi", even
165 /// when the next hop is over a cellular connection.
166 pub network_type: NetworkType,
167
168 /// The IP address of the candidate, allowing for IPv4 addresses and IPv6 addresses, but fully
169 /// qualified domain names (FQDNs) are not allowed.
170 pub ip: String,
171
172 /// The port number of the candidate.
173 pub port: u16,
174
175 /// The `Type` field of the ICECandidate.
176 pub candidate_type: CandidateType,
177
178 /// The `priority` field of the ICECandidate.
179 pub priority: u32,
180
181 /// The url of the TURN or STUN server indicated in the that translated this IP address.
182 /// It is the url address surfaced in an PeerConnectionICEEvent.
183 pub url: String,
184
185 /// The protocol used by the endpoint to communicate with the TURN server. This is only present
186 /// for local candidates. Valid values for the TURN url protocol is one of udp, tcp, or tls.
187 pub relay_protocol: String,
188
189 /// It is true if the candidate has been deleted/freed. For host candidates, this means that any
190 /// network resources (typically a socket) associated with the candidate have been released. For
191 /// TURN candidates, this means the TURN allocation is no longer active.
192 ///
193 /// Only defined for local candidates. For remote candidates, this property is not applicable.
194 pub deleted: bool,
195}
196
197impl Default for CandidateStats {
198 fn default() -> Self {
199 Self {
200 timestamp: Instant::now(),
201 id: String::new(),
202 network_type: NetworkType::default(),
203 ip: String::new(),
204 port: 0,
205 candidate_type: CandidateType::default(),
206 priority: 0,
207 url: String::new(),
208 relay_protocol: String::new(),
209 deleted: false,
210 }
211 }
212}
213
214impl Agent {
215 /// Returns a list of candidate pair stats.
216 pub fn get_candidate_pairs_stats(&self) -> Vec<CandidatePairStats> {
217 let mut res = Vec::with_capacity(self.candidate_pairs.len());
218 for cp in &self.candidate_pairs {
219 let stat = CandidatePairStats {
220 timestamp: Instant::now(),
221 local_candidate_id: self.local_candidates[cp.local_index].id().to_string(),
222 remote_candidate_id: self.remote_candidates[cp.remote_index].id().to_string(),
223 state: cp.state,
224 nominated: cp.nominated,
225 // STUN transaction stats
226 requests_sent: cp.requests_sent,
227 requests_received: cp.requests_received,
228 responses_sent: cp.responses_sent,
229 responses_received: cp.responses_received,
230 consent_requests_sent: cp.consent_requests_sent,
231 // RTT tracking (convert Duration to seconds as f64)
232 total_round_trip_time: cp.total_round_trip_time.as_secs_f64(),
233 current_round_trip_time: cp.current_round_trip_time.as_secs_f64(),
234 ..CandidatePairStats::default()
235 };
236 res.push(stat);
237 }
238 res
239 }
240
241 /// Returns a list of local candidates stats.
242 pub fn get_local_candidates_stats(&self) -> Vec<CandidateStats> {
243 let mut res = Vec::with_capacity(self.local_candidates.len());
244 for c in &self.local_candidates {
245 let stat = CandidateStats {
246 timestamp: Instant::now(),
247 id: c.id().to_string(),
248 network_type: c.network_type(),
249 ip: c.address().to_owned(),
250 port: c.port(),
251 candidate_type: c.candidate_type(),
252 priority: c.priority(),
253 // URL string
254 relay_protocol: "udp".to_owned(),
255 // Deleted bool
256 ..CandidateStats::default()
257 };
258 res.push(stat);
259 }
260 res
261 }
262
263 /// Returns a list of remote candidates stats.
264 pub fn get_remote_candidates_stats(&self) -> Vec<CandidateStats> {
265 let mut res = Vec::with_capacity(self.remote_candidates.len());
266 for c in &self.remote_candidates {
267 let stat = CandidateStats {
268 timestamp: Instant::now(),
269 id: c.id().to_string(),
270 network_type: c.network_type(),
271 ip: c.address().to_owned(),
272 port: c.port(),
273 candidate_type: c.candidate_type(),
274 priority: c.priority(),
275 // URL string
276 relay_protocol: "udp".to_owned(),
277 // Deleted bool
278 ..CandidateStats::default()
279 };
280 res.push(stat);
281 }
282 res
283 }
284}