xref: /webrtc/ice/src/agent/agent_stats.rs (revision ffe74184)
1 use crate::candidate::{CandidatePairState, CandidateType};
2 
3 use crate::agent::agent_internal::AgentInternal;
4 use crate::network_type::NetworkType;
5 use std::sync::atomic::Ordering;
6 use tokio::time::Instant;
7 
8 /// Contains ICE candidate pair statistics.
9 pub struct CandidatePairStats {
10     /// The timestamp associated with this struct.
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 
115 impl Default for CandidatePairStats {
default() -> Self116     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)]
151 pub 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 
197 impl Default for CandidateStats {
default() -> Self198     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 
214 impl AgentInternal {
215     /// Returns a list of candidate pair stats.
get_candidate_pairs_stats(&self) -> Vec<CandidatePairStats>216     pub(crate) async fn get_candidate_pairs_stats(&self) -> Vec<CandidatePairStats> {
217         let checklist = self.agent_conn.checklist.lock().await;
218         let mut res = Vec::with_capacity(checklist.len());
219         for cp in &*checklist {
220             let stat = CandidatePairStats {
221                 timestamp: Instant::now(),
222                 local_candidate_id: cp.local.id(),
223                 remote_candidate_id: cp.remote.id(),
224                 state: cp.state.load(Ordering::SeqCst).into(),
225                 nominated: cp.nominated.load(Ordering::SeqCst),
226                 ..CandidatePairStats::default()
227             };
228             res.push(stat);
229         }
230         res
231     }
232 
233     /// Returns a list of local candidates stats.
get_local_candidates_stats(&self) -> Vec<CandidateStats>234     pub(crate) async fn get_local_candidates_stats(&self) -> Vec<CandidateStats> {
235         let local_candidates = self.local_candidates.lock().await;
236         let mut res = Vec::with_capacity(local_candidates.len());
237         for (network_type, local_candidates) in &*local_candidates {
238             for c in local_candidates {
239                 let stat = CandidateStats {
240                     timestamp: Instant::now(),
241                     id: c.id(),
242                     network_type: *network_type,
243                     ip: c.address(),
244                     port: c.port(),
245                     candidate_type: c.candidate_type(),
246                     priority: c.priority(),
247                     // URL string
248                     relay_protocol: "udp".to_owned(),
249                     // Deleted bool
250                     ..CandidateStats::default()
251                 };
252                 res.push(stat);
253             }
254         }
255         res
256     }
257 
258     /// Returns a list of remote candidates stats.
get_remote_candidates_stats(&self) -> Vec<CandidateStats>259     pub(crate) async fn get_remote_candidates_stats(&self) -> Vec<CandidateStats> {
260         let remote_candidates = self.remote_candidates.lock().await;
261         let mut res = Vec::with_capacity(remote_candidates.len());
262         for (network_type, remote_candidates) in &*remote_candidates {
263             for c in remote_candidates {
264                 let stat = CandidateStats {
265                     timestamp: Instant::now(),
266                     id: c.id(),
267                     network_type: *network_type,
268                     ip: c.address(),
269                     port: c.port(),
270                     candidate_type: c.candidate_type(),
271                     priority: c.priority(),
272                     // URL string
273                     relay_protocol: "udp".to_owned(),
274                     // Deleted bool
275                     ..CandidateStats::default()
276                 };
277                 res.push(stat);
278             }
279         }
280         res
281     }
282 }
283