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