medea_client_api_proto/
stats.rs

1//! Contains DTOs for [RTCPeerConnection] metrics.
2//!
3//! [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
4
5// TODO: Needs refactoring.
6#![expect(clippy::module_name_repetitions, reason = "needs refactoring")]
7
8use std::{
9    hash::{Hash, Hasher},
10    time::{Duration, SystemTime, SystemTimeError},
11};
12
13use derive_more::with_trait::{Display, From};
14use serde::{Deserialize, Serialize};
15
16/// Enum with which you can try to deserialize some known enum and if it
17/// isn't known, then unknown data will be stored as [`String`] in the
18/// [`NonExhaustive::Unknown`] variant.
19#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
20#[serde(untagged)]
21pub enum NonExhaustive<T> {
22    /// Will store known enum variant if it successfully deserialized.
23    Known(T),
24
25    /// Will store unknown enum variant with it's data as [`String`].
26    Unknown(String),
27}
28
29/// Unique ID that is associated with the object that was inspected to produce
30/// [`RtcStat`] object.
31///
32/// Two [`RtcStat`]s objects, extracted from two different [RTCStatsReport]
33/// objects, MUST have the same ID if they were produced by inspecting the same
34/// underlying object.
35///
36/// [RTCStatsReport]: https://w3.org/TR/webrtc#dom-rtcstatsreport
37#[derive(
38    Clone, Debug, Deserialize, Display, Eq, From, Hash, PartialEq, Serialize,
39)]
40#[from(forward)]
41pub struct StatId(pub String);
42
43/// Represents the [stats object] constructed by inspecting a specific
44/// [monitored object].
45///
46/// [Full doc on W3C][1].
47///
48/// [stats object]: https://w3.org/TR/webrtc-stats/#dfn-stats-object
49/// [monitored object]: https://w3.org/TR/webrtc-stats/#dfn-monitored-object
50/// [1]: https://w3.org/TR/webrtc#rtcstats-dictionary
51#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
52pub struct RtcStat {
53    /// Unique ID that is associated with the object that was inspected to
54    /// produce this [RTCStats] object.
55    ///
56    /// [RTCStats]: https://w3.org/TR/webrtc#dom-rtcstats
57    pub id: StatId,
58
59    /// Timestamp associated with this object.
60    ///
61    /// The time is relative to the UNIX epoch (Jan 1, 1970, UTC).
62    ///
63    /// For statistics that came from a remote source (e.g., from received RTCP
64    /// packets), timestamp represents the time at which the information
65    /// arrived at the local endpoint. The remote timestamp can be found in an
66    /// additional field in an [`RtcStat`]-derived dictionary, if applicable.
67    pub timestamp: HighResTimeStamp,
68
69    /// Actual stats of this [`RtcStat`].
70    ///
71    /// All possible stats are described in the [`RtcStatsType`] enum.
72    #[serde(flatten)]
73    pub stats: RtcStatsType,
74}
75
76/// All known types of [`RtcStat`]s.
77///
78/// [List of all RTCStats types on W3C][1].
79///
80/// [1]: https://w3.org/TR/webrtc-stats/#rtctatstype-%2A
81/// [`RtcStat`]: super::RtcStat
82#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
83#[serde(tag = "type", rename_all = "kebab-case")]
84pub enum RtcStatsType {
85    /// Statistics for a codec that is currently used by [RTP] streams
86    /// being sent or received by [RTCPeerConnection] object.
87    ///
88    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
89    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
90    #[cfg(feature = "extended-stats")]
91    Codec(Box<RtcCodecStats>),
92
93    /// Statistics for an inbound [RTP] stream that is currently received
94    /// with [RTCPeerConnection] object.
95    ///
96    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
97    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
98    InboundRtp(Box<RtcInboundRtpStreamStats>),
99
100    /// Statistics for an outbound [RTP] stream that is currently sent with
101    /// [RTCPeerConnection] object.
102    ///
103    /// When there are multiple [RTP] streams connected to the same sender,
104    /// such as when using simulcast or RTX, there will be one
105    /// [`RtcOutboundRtpStreamStats`] per RTP stream, with distinct values
106    /// of the `ssrc` attribute, and all these senders will have a
107    /// reference to the same "sender" object (of type
108    /// [RTCAudioSenderStats][1] or [RTCVideoSenderStats][2]) and
109    /// "track" object (of type
110    /// [RTCSenderAudioTrackAttachmentStats][3] or
111    /// [RTCSenderVideoTrackAttachmentStats][4]).
112    ///
113    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
114    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
115    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcaudiosenderstats
116    /// [2]: https://w3.org/TR/webrtc-stats/#dom-rtcvideosenderstats
117    /// [3]: https://tinyurl.com/sefa5z4
118    /// [4]: https://tinyurl.com/rkuvpl4
119    OutboundRtp(Box<RtcOutboundRtpStreamStats>),
120
121    /// Statistics for the remote endpoint's inbound [RTP] stream
122    /// corresponding to an outbound stream that is currently sent with
123    /// [RTCPeerConnection] object.
124    ///
125    /// It is measured at the remote endpoint and reported in a RTCP
126    /// Receiver Report (RR) or RTCP Extended Report (XR).
127    ///
128    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
129    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
130    RemoteInboundRtp(Box<RtcRemoteInboundRtpStreamStats>),
131
132    /// Statistics for the remote endpoint's outbound [RTP] stream
133    /// corresponding to an inbound stream that is currently received with
134    /// [RTCPeerConnection] object.
135    ///
136    /// It is measured at the remote endpoint and reported in an RTCP
137    /// Sender Report (SR).
138    ///
139    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
140    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
141    RemoteOutboundRtp(Box<RtcRemoteOutboundRtpStreamStats>),
142
143    /// Statistics for the media produced by a [MediaStreamTrack][1] that
144    /// is currently attached to an [RTCRtpSender]. This reflects
145    /// the media that is fed to the encoder after [getUserMedia]
146    /// constraints have been applied (i.e. not the raw media
147    /// produced by the camera).
148    ///
149    /// [RTCRtpSender]: https://w3.org/TR/webrtc#rtcrtpsender-interface
150    /// [getUserMedia]: https://tinyurl.com/sngpyr6
151    /// [1]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
152    MediaSource(Box<MediaSourceStats>),
153
154    /// Statistics for a contributing source (CSRC) that contributed to an
155    /// inbound [RTP] stream.
156    ///
157    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
158    #[cfg(feature = "extended-stats")]
159    Csrc(Box<RtpContributingSourceStats>),
160
161    /// Statistics related to the [RTCPeerConnection] object.
162    ///
163    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
164    #[cfg(feature = "extended-stats")]
165    PeerConnection(Box<RtcPeerConnectionStats>),
166
167    /// Statistics related to each [RTCDataChannel] ID.
168    ///
169    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
170    #[cfg(feature = "extended-stats")]
171    DataChannel(Box<DataChannelStats>),
172
173    /// Contains statistics related to a specific [MediaStream].
174    ///
175    /// This is now obsolete.
176    ///
177    /// [MediaStream]: https://w3.org/TR/mediacapture-streams#mediastream
178    #[cfg(feature = "extended-stats")]
179    Stream(Box<MediaStreamStats>),
180
181    /// Statistics related to a specific [MediaStreamTrack][1]'s attachment
182    /// to an [RTCRtpSender] and the corresponding media-level
183    /// metrics.
184    ///
185    /// [RTCRtpSender]: https://w3.org/TR/webrtc#rtcrtpsender-interface
186    /// [1]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
187    Track(Box<TrackStats>),
188
189    /// Statistics related to a specific [RTCRtpTransceiver].
190    ///
191    /// [RTCRtpTransceiver]: https://w3.org/TR/webrtc#dom-rtcrtptransceiver
192    #[cfg(feature = "extended-stats")]
193    Transceiver(Box<RtcRtpTransceiverStats>),
194
195    /// Statistics related to a specific [RTCRtpSender] and the
196    /// corresponding media-level metrics.
197    ///
198    /// [RTCRtpSender]: https://w3.org/TR/webrtc#rtcrtpsender-interface
199    #[cfg(feature = "extended-stats")]
200    Sender(Box<SenderStatsKind>),
201
202    /// Statistics related to a specific [RTCRtpReceiver] and the
203    /// corresponding media-level metrics.
204    ///
205    /// [RTCRtpReceiver]: https://w3.org/TR/webrtc#dom-rtcrtpreceiver
206    #[cfg(feature = "extended-stats")]
207    Receiver(Box<ReceiverStatsKind>),
208
209    /// Transport statistics related to the [RTCPeerConnection] object.
210    ///
211    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
212    Transport(Box<RtcTransportStats>),
213
214    /// SCTP transport statistics related to an [RTCSctpTransport] object.
215    ///
216    /// [RTCSctpTransport]: https://w3.org/TR/webrtc#dom-rtcsctptransport
217    SctpTransport(Box<RtcSctpTransportStats>),
218
219    /// ICE candidate pair statistics related to the [RTCIceTransport]
220    /// objects.
221    ///
222    /// A candidate pair that is not the current pair for a transport is
223    /// [deleted][1] when the [RTCIceTransport] does an ICE restart, at the
224    /// time the state changes to `new`.
225    ///
226    /// The candidate pair that is the current pair for a transport is
227    /// deleted after an ICE restart when the [RTCIceTransport]
228    /// switches to using a candidate pair generated from the new
229    /// candidates; this time doesn't correspond to any other
230    /// externally observable event.
231    ///
232    /// [RTCIceTransport]: https://w3.org/TR/webrtc#dom-rtcicetransport
233    /// [1]: https://w3.org/TR/webrtc-stats/#dfn-deleted
234    CandidatePair(Box<RtcIceCandidatePairStats>),
235
236    /// ICE local candidate statistics related to the [RTCIceTransport]
237    /// objects.
238    ///
239    /// A local candidate is [deleted][1] when the [RTCIceTransport] does
240    /// an ICE restart, and the candidate is no longer a member of
241    /// any non-deleted candidate pair.
242    ///
243    /// [RTCIceTransport]: https://w3.org/TR/webrtc#dom-rtcicetransport
244    /// [1]: https://w3.org/TR/webrtc-stats/#dfn-deleted
245    LocalCandidate(Box<RtcIceCandidateStats>),
246
247    /// ICE remote candidate statistics related to the [RTCIceTransport]
248    /// objects.
249    ///
250    /// A remote candidate is [deleted][1] when the [RTCIceTransport] does
251    /// an ICE restart, and the candidate is no longer a member of
252    /// any non-deleted candidate pair.
253    ///
254    /// [RTCIceTransport]: https://w3.org/TR/webrtc#dom-rtcicetransport
255    /// [1]: https://w3.org/TR/webrtc-stats/#dfn-deleted
256    RemoteCandidate(Box<RtcIceCandidateStats>),
257
258    /// Information about a certificate used by [RTCIceTransport].
259    ///
260    /// [RTCIceTransport]: https://w3.org/TR/webrtc#dom-rtcicetransport
261    #[cfg(feature = "extended-stats")]
262    Certificate(Box<RtcCertificateStats>),
263
264    /// Information about the connection to an ICE server (e.g. STUN or
265    /// TURN).
266    #[cfg(feature = "extended-stats")]
267    IceServer(Box<RtcIceServerStats>),
268
269    /// Disabled or unknown variants of stats will be deserialized as
270    /// [`RtcStatsType::Other`].
271    #[serde(other)]
272    Other,
273}
274
275#[cfg(feature = "extended-stats")]
276/// Contains statistics related to a specific [MediaStream].
277///
278/// This is now obsolete.
279///
280/// [`RtcStatsType::Stream`] variant.
281///
282/// [Full doc on W3C][1].
283///
284/// [MediaStream]: https://w3.org/TR/mediacapture-streams#mediastream
285/// [1]: https://w3.org/TR/webrtc-stats/#idl-def-rtcmediastreamstats
286#[serde_with::skip_serializing_none]
287#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
288#[serde(rename_all = "camelCase")]
289pub struct MediaStreamStats {
290    /// [`stream.id`][1] property.
291    ///
292    /// [1]: https://w3.org/TR/mediacapture-streams#dom-mediastream-id
293    pub stream_identifier: String,
294
295    /// ID of the stats object, not the `track.id`.
296    pub track_ids: Vec<StatId>,
297}
298
299#[cfg(feature = "extended-stats")]
300/// Statistics related to each [RTCDataChannel] ID.
301///
302/// [`RtcStatsType::DataChannel`] variant.
303///
304/// [Full doc on W3C][1].
305///
306/// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
307/// [1]: https://w3.org/TR/webrtc-stats/#dcstats-dict%2A
308#[serde_with::skip_serializing_none]
309#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
310#[serde(rename_all = "camelCase")]
311pub struct DataChannelStats {
312    /// [`label`][1] value of the [RTCDataChannel] object.
313    ///
314    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
315    /// [1]: https://w3.org/TR/webrtc#dom-datachannel-label
316    pub label: Option<String>,
317
318    /// [`protocol`][1] value of the [RTCDataChannel] object.
319    ///
320    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
321    /// [1]: https://w3.org/TR/webrtc#dom-datachannel-protocol
322    pub protocol: Option<Protocol>,
323
324    /// [`id`][1] attribute of the [RTCDataChannel] object.
325    ///
326    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
327    /// [1]: https://w3.org/TR/webrtc#dom-rtcdatachannel-id
328    pub data_channel_identifier: Option<u64>,
329
330    /// [Stats object reference][1] for the transport used to carry
331    /// [RTCDataChannel].
332    ///
333    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
334    /// [1]: https://w3.org/TR/webrtc-stats/#dfn-stats-object-reference
335    pub transport_id: Option<String>,
336
337    /// [`readyState`][1] value of the [RTCDataChannel] object.
338    ///
339    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
340    /// [1]: https://w3.org/TR/webrtc#dom-datachannel-readystate
341    pub state: Option<DataChannelState>,
342
343    /// Total number of API `message` events sent.
344    pub messages_sent: Option<u64>,
345
346    /// Total number of payload bytes sent on this [RTCDataChannel], i.e. not
347    /// including headers or padding.
348    ///
349    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
350    pub bytes_sent: Option<u64>,
351
352    /// Total number of API `message` events received.
353    pub messages_received: Option<u64>,
354
355    /// Total number of bytes received on this [RTCDataChannel], i.e. not
356    /// including headers or padding.
357    ///
358    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
359    pub bytes_received: Option<u64>,
360}
361
362/// Non-exhaustive version of [`KnownDataChannelState`].
363pub type DataChannelState = NonExhaustive<KnownDataChannelState>;
364
365/// State of the [RTCDataChannel]'s underlying data connection.
366///
367/// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
368#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
369#[serde(rename_all = "kebab-case")]
370pub enum KnownDataChannelState {
371    /// User agent is attempting to establish the underlying data transport.
372    /// This is the initial state of [RTCDataChannel] object, whether created
373    /// with [createDataChannel][1], or dispatched as a part of an
374    /// [RTCDataChannelEvent].
375    ///
376    /// [RTCDataChannel]: https://w3.org/TR/webrtc#dom-rtcdatachannel
377    /// [RTCDataChannelEvent]: https://w3.org/TR/webrtc#dom-rtcdatachannelevent
378    /// [1]: https://w3.org/TR/webrtc#dom-peerconnection-createdatachannel
379    Connecting,
380
381    /// [Underlying data transport][1] is established and communication is
382    /// possible.
383    ///
384    /// [1]: https://w3.org/TR/webrtc#dfn-data-transport
385    Open,
386
387    /// [`procedure`][2] to close down the [underlying data transport][1] has
388    /// started.
389    ///
390    /// [1]: https://w3.org/TR/webrtc#dfn-data-transport
391    /// [2]: https://w3.org/TR/webrtc#data-transport-closing-procedure
392    Closing,
393
394    /// [Underlying data transport][1] has been [`closed`][2] or could not be
395    /// established.
396    ///
397    /// [1]: https://w3.org/TR/webrtc#dfn-data-transport
398    /// [2]: https://w3.org/TR/webrtc#dom-rtcdatachannelstate-closed
399    Closed,
400}
401
402#[cfg(feature = "extended-stats")]
403/// Stats for the [RTCPeerConnection] object.
404///
405/// [`RtcStatsType::PeerConnection`] variant.
406///
407/// [Full doc on W3C][1].
408///
409/// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
410/// [1]: https://w3.org/TR/webrtc-stats/#pcstats-dict%2A
411#[serde_with::skip_serializing_none]
412#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
413#[serde(rename_all = "camelCase")]
414pub struct RtcPeerConnectionStats {
415    /// Number of unique `DataChannel`s that have entered the `open` state
416    /// during their lifetime.
417    pub data_channels_opened: Option<u64>,
418
419    /// Number of unique `DataChannel`s that have left the `open` state during
420    /// their lifetime (due to being closed by either end or the underlying
421    /// transport being closed). `DataChannel`s that transition from
422    /// `connecting` to `closing` or `closed` without ever being `open` are not
423    /// counted in this number.
424    pub data_channels_closed: Option<u64>,
425
426    /// Number of unique `DataChannel`s returned from a successful
427    /// [createDataChannel][1] call on the [RTCPeerConnection].
428    /// If the underlying data transport is not established, these may be in
429    /// the `connecting` state.
430    ///
431    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
432    /// [1]: https://w3.org/TR/webrtc#dom-peerconnection-createdatachannel
433    pub data_channels_requested: Option<u64>,
434
435    /// Number of unique `DataChannel`s signaled in a `datachannel` event on
436    /// the [RTCPeerConnection].
437    ///
438    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
439    pub data_channels_accepted: Option<u64>,
440}
441
442#[cfg(feature = "extended-stats")]
443/// Statistics for a contributing source (CSRC) that contributed to an inbound
444/// [RTP] stream.
445///
446/// [`RtcStatsType::Csrc`] variant.
447///
448/// [Full doc on W3C][1].
449///
450/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
451/// [1]: https://w3.org/TR/webrtc-stats/#contributingsourcestats-dict%2A
452#[serde_with::skip_serializing_none]
453#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
454#[serde(rename_all = "camelCase")]
455pub struct RtpContributingSourceStats {
456    /// SSRC identifier of the contributing source represented by the stats
457    /// object, as defined by [RFC 3550]. It is a 32-bit unsigned integer that
458    /// appears in the CSRC list of any packets the relevant source contributed
459    /// to.
460    ///
461    /// [RFC 3550]: https://tools.ietf.org/html/rfc3550
462    pub contributor_ssrc: Option<u32>,
463
464    /// ID of the [RTCInboundRtpStreamStats][1] object representing the inbound
465    /// [RTP] stream that this contributing source is contributing to.
466    ///
467    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
468    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats
469    pub inbound_rtp_stream_id: Option<String>,
470
471    /// Total number of [RTP] packets that this contributing source contributed
472    /// to.
473    ///
474    /// This value is incremented each time a packet is counted by
475    /// [RTCInboundRtpStreamStats.packetsReceived][2], and the packet's CSRC
476    /// list (as defined by [Section 5.1 in RFC 3550][3]) contains the SSRC
477    /// identifier of this contributing source, [`contributorSsrc`].
478    ///
479    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
480    /// [`contributorSsrc`]: https://tinyurl.com/tf8c7j4
481    /// [2]: https://tinyurl.com/rreuf49
482    /// [3]: https://tools.ietf.org/html/rfc3550#section-5.1
483    pub packets_contributed_to: Option<u64>,
484
485    /// Present if the last received RTP packet that this source contributed to
486    /// contained an [RFC 6465] mixer-to-client audio level header extension.
487    ///
488    /// The value of [`audioLevel`] is between `0..1` (linear), where `1.0`
489    /// represents `0 dBov`, `0` represents silence, and `0.5` represents
490    /// approximately `6 dBSPL` change in the sound pressure level from 0
491    /// dBov. The [RFC 6465] header extension contains values in the range
492    /// `0..127`, in units of `-dBov`, where `127` represents silence. To
493    /// convert these values to the linear `0..1` range of `audioLevel`, a
494    /// value of `127` is converted to `0`, and all other values are
495    /// converted using the equation:
496    ///
497    /// `f(rfc6465_level) = 10^(-rfc6465_level/20)`
498    ///
499    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
500    /// [RFC 6465]: https://tools.ietf.org/html/rfc6465
501    /// [`audioLevel`]: https://tinyurl.com/sfy699q
502    pub audio_level: Option<Float>,
503}
504
505/// Statistics for the remote endpoint's outbound [RTP] stream corresponding
506/// to an inbound stream that is currently received with [RTCPeerConnection]
507/// object.
508///
509/// It is measured at the remote endpoint and reported in an RTCP Sender Report
510/// (SR).
511///
512/// [`RtcStatsType::RemoteOutboundRtp`] variant.
513///
514/// [Full doc on W3C][1].
515///
516/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
517/// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
518/// [1]: https://w3.org/TR/webrtc-stats/#remoteoutboundrtpstats-dict%2A
519#[serde_with::skip_serializing_none]
520#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
521#[serde(rename_all = "camelCase")]
522pub struct RtcRemoteOutboundRtpStreamStats {
523    /// [`localId`] is used for looking up the local
524    /// [RTCInboundRtpStreamStats][1] object for the same SSRC.
525    ///
526    /// [`localId`]: https://tinyurl.com/vu9tb2e
527    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats
528    pub local_id: Option<String>,
529
530    /// [`remoteTimestamp`] (as [HIGHRES-TIME]) is the remote timestamp at
531    /// which these statistics were sent by the remote endpoint. This
532    /// differs from timestamp, which represents the time at which the
533    /// statistics were generated or received by the local endpoint. The
534    /// [`remoteTimestamp`], if present, is derived from the NTP timestamp
535    /// in an RTCP Sender Report (SR) block, which reflects the remote
536    /// endpoint's clock. That clock may not be synchronized with the local
537    /// clock.
538    ///
539    /// [`remoteTimestamp`]: https://tinyurl.com/rzlhs87
540    /// [HIGRES-TIME]: https://w3.org/TR/webrtc-stats/#bib-highres-time
541    pub remote_timestamp: Option<HighResTimeStamp>,
542
543    /// Total number of RTCP SR blocks sent for this SSRC.
544    pub reports_sent: Option<u64>,
545}
546
547/// Statistics for the remote endpoint's inbound [RTP] stream corresponding
548/// to an outbound stream that is currently sent with [RTCPeerConnection]
549/// object.
550///
551/// It is measured at the remote endpoint and reported in a RTCP Receiver
552/// Report (RR) or RTCP Extended Report (XR).
553///
554/// [`RtcStatsType::RemoteInboundRtp`] variant.
555///
556/// [Full doc on W3C][1].
557///
558/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
559/// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
560/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats
561#[serde_with::skip_serializing_none]
562#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
563#[serde(rename_all = "camelCase")]
564pub struct RtcRemoteInboundRtpStreamStats {
565    /// [`localId`] is used for looking up the local
566    /// [RTCOutboundRtpStreamStats] object for the same SSRC.
567    ///
568    /// [`localId`]: https://tinyurl.com/r8uhbo9
569    /// [RTCOutBoundRtpStreamStats]: https://tinyurl.com/r6f5vqg
570    pub local_id: Option<String>,
571
572    /// Packet [jitter] measured in seconds for this SSRC.
573    ///
574    /// [jitter]: https://en.wikipedia.org/wiki/Jitter
575    pub jitter: Option<Float>,
576
577    /// Estimated round trip time for this SSRC based on the RTCP timestamps in
578    /// the RTCP Receiver Report (RR) and measured in seconds. Calculated as
579    /// defined in [Section 6.4.1 of RFC 3550][1]. If no RTCP Receiver Report
580    /// is received with a DLSR value other than 0, the round trip time is
581    /// left undefined.
582    ///
583    /// [1]: https://tools.ietf.org/html/rfc3550#section-6.4.1
584    pub round_trip_time: Option<Float>,
585
586    /// Fraction packet loss reported for this SSRC. Calculated as defined in
587    /// [Section 6.4.1 of RFC 3550][1] and [Appendix A.3][2].
588    ///
589    /// [1]: https://tools.ietf.org/html/rfc3550#section-6.4.1
590    /// [2]: https://tools.ietf.org/html/rfc3550#appendix-A.3
591    pub fraction_lost: Option<Float>,
592
593    /// Total number of RTCP RR blocks received for this SSRC.
594    pub reports_received: Option<u64>,
595
596    /// Total number of RTCP RR blocks received for this SSRC that contain a
597    /// valid round trip time. This counter will increment if the
598    /// [`roundTripTime`] is undefined.
599    ///
600    /// [`roundTripTime`]: https://tinyurl.com/ssg83hq
601    pub round_trip_time_measurements: Option<Float>,
602}
603
604#[cfg(feature = "extended-stats")]
605/// [RTCRtpTransceiverStats][1] object representing an [RTCRtpTransceiver] of an
606/// [RTCPeerConnection].
607///
608/// It appears as soon as the monitored [RTCRtpTransceiver] object is created,
609/// such as by invoking [addTransceiver][2], [addTrack][3] or
610/// [setRemoteDescription][4]. [RTCRtpTransceiverStats][1] objects can only be
611/// deleted if the corresponding [RTCRtpTransceiver] is removed (this can only
612/// happen if a remote description is rolled back).
613///
614/// [`RtcStatsType::Transceiver`] variant.
615///
616/// [Full doc on W3C][1].
617///
618/// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
619/// [RTCRtpTransceiver]: https://w3.org/TR/webrtc#dom-rtcrtptransceiver
620/// [1]: https://w3.org/TR/webrtc-stats/#transceiver-dict%2A
621/// [2]: https://w3.org/TR/webrtc#dom-rtcpeerconnection-addtransceiver
622/// [3]: https://w3.org/TR/webrtc#dom-rtcpeerconnection-addtrack
623/// [4]: https://tinyurl.com/vejym8v
624#[serde_with::skip_serializing_none]
625#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
626#[serde(rename_all = "camelCase")]
627pub struct RtcRtpTransceiverStats {
628    /// ID of the stats object representing the
629    /// [RTCRtpSender associated with the RTCRtpTransceiver][1] represented by
630    /// this stats object.
631    ///
632    /// [1]: https://w3.org/TR/webrtc#dom-rtcrtptransceiver-sender
633    pub sender_id: Option<String>,
634
635    /// ID of the stats object representing the
636    /// [RTCRtpReceiver associated with the RTCRtpTransceiver][1] represented
637    /// by this stats object.
638    ///
639    /// [1]: https://w3.org/TR/webrtc#dom-rtcrtptransceiver-receiver
640    pub receiver_id: Option<String>,
641
642    /// If the [RTCRtpTransceiver] that this stats object represents has a
643    /// [`mid` value][1] that is not null, this is that value, otherwise this
644    /// value is undefined.
645    ///
646    /// [RTCRtpTransceiver]: https://w3.org/TR/webrtc#dom-rtcrtptransceiver
647    /// [1]: https://w3.org/TR/webrtc#dom-rtptransceiver-mid
648    pub mid: Option<String>,
649}
650
651/// Representation of the stats corresponding to an [RTCSctpTransport].
652///
653/// [`RtcStatsType::SctpTransport`] variant.
654///
655/// [Full doc on W3C][1].
656///
657/// [RTCSctpTransport]: https://w3.org/TR/webrtc#dom-rtcsctptransport
658/// [1]: https://w3.org/TR/webrtc-stats/#sctptransportstats-dict%2A
659#[serde_with::skip_serializing_none]
660#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
661#[serde(rename_all = "camelCase")]
662pub struct RtcSctpTransportStats {
663    /// Latest smoothed round-trip time value, corresponding to
664    /// [`spinfo_srtt` defined in RFC 6458][1] but converted to seconds.
665    ///
666    /// If there has been no round-trip time measurements yet, this value is
667    /// undefined.
668    ///
669    /// [1]: https://tools.ietf.org/html/rfc6458#page-83
670    pub smoothed_round_trip_time: Option<HighResTimeStamp>,
671}
672
673/// Representation of the stats corresponding to an [RTCDtlsTransport] and its
674/// underlying [RTCIceTransport].
675///
676/// When RTCP multiplexing is used, one transport is used for both RTP and RTCP.
677/// Otherwise, RTP and RTCP will be sent on separate transports, and
678/// `rtcpTransportStatsId` can be used to pair the resulting
679/// [`RtcTransportStats`] objects. Additionally, when bundling is used, a single
680/// transport will be used for all [MediaStreamTrack][2]s in the bundle group.
681/// If bundling is not used, different [MediaStreamTrack][2]s will use different
682/// transports. RTCP multiplexing and bundling are described in [WebRTC].
683///
684/// [`RtcStatsType::Transport`] variant.
685///
686/// [Full doc on W3C][1].
687///
688/// [RTCDtlsTransport]: https://w3.org/TR/webrtc#dom-rtcdtlstransport
689/// [RTCIceTransport]: https://w3.org/TR/webrtc#dom-rtcicetransport
690/// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
691/// [WebRTC]: https://w3.org/TR/webrtc
692/// [1]: https://w3.org/TR/webrtc-stats/#transportstats-dict%2A
693/// [2]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
694#[serde_with::skip_serializing_none]
695#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
696#[serde(rename_all = "camelCase")]
697pub struct RtcTransportStats {
698    /// Total number of packets sent over this transport.
699    pub packets_sent: Option<u64>,
700
701    /// Total number of packets received on this transport.
702    pub packets_received: Option<u64>,
703
704    /// Total number of payload bytes sent on this [RTCPeerConnection], i.e.
705    /// not including headers or padding.
706    ///
707    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
708    pub bytes_sent: Option<u64>,
709
710    /// Total number of bytes received on this [RTCPeerConnection], i.e. not
711    /// including headers or padding.
712    ///
713    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
714    pub bytes_received: Option<u64>,
715
716    /// Set to the current value of the [`role` attribute][1] of the
717    /// [underlying RTCDtlsTransport's `transport`][2].
718    ///
719    /// [1]: https://w3.org/TR/webrtc#dom-icetransport-role
720    /// [2]: https://w3.org/TR/webrtc#dom-rtcdtlstransport-icetransport
721    pub ice_role: Option<IceRole>,
722}
723
724/// Variants of [ICE roles][1].
725///
726/// More info in the [RFC 5245].
727///
728/// [RFC 5245]: https://tools.ietf.org/html/rfc5245
729/// [1]: https://w3.org/TR/webrtc#dom-icetransport-role
730#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
731#[serde(rename_all = "camelCase")]
732pub enum IceRole {
733    /// Agent whose role as defined by [Section 3 in RFC 5245][1], has not yet
734    /// been determined.
735    ///
736    /// [1]: https://tools.ietf.org/html/rfc5245#section-3
737    Unknown,
738
739    /// Controlling agent as defined by [Section 3 in RFC 5245][1].
740    ///
741    /// [1]: https://tools.ietf.org/html/rfc5245#section-3
742    Controlling,
743
744    /// Controlled agent as defined by [Section 3 in RFC 5245][1].
745    ///
746    /// [1]: https://tools.ietf.org/html/rfc5245#section-3
747    Controlled,
748}
749
750#[cfg(feature = "extended-stats")]
751/// Statistics related to a specific [RTCRtpSender] and the corresponding
752/// media-level metrics.
753///
754/// [`RtcStatsType::Sender`] variant.
755///
756/// [Full doc on W3C][1].
757///
758/// [RTCRtpSender]: https://w3.org/TR/webrtc#rtcrtpsender-interface
759/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcstatstype-sender
760#[serde_with::skip_serializing_none]
761#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
762#[serde(tag = "kind", rename_all = "camelCase")]
763pub enum SenderStatsKind {
764    /// [RTCAudioSenderStats][1] object.
765    ///
766    /// [1]: https://tinyurl.com/w5ow5xs
767    Audio {
768        /// ID of the related media source.
769        media_source_id: Option<String>,
770    },
771
772    /// [RTCVideoSenderStats][1] object.
773    ///
774    /// [1]: https://tinyurl.com/ry39vnw
775    Video {
776        /// ID of the related media source.
777        media_source_id: Option<String>,
778    },
779}
780
781#[cfg(feature = "extended-stats")]
782/// Statistics related to a specific [RTCRtpReceiver] and the corresponding
783/// media-level metrics.
784///
785/// [`RtcStatsType::Receiver`] variant.
786///
787/// [Full doc on W3C][1].
788///
789/// [RTCRtpReceiver]: https://w3.org/TR/webrtc#dom-rtcrtpreceiver
790/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcstatstype-receiver
791#[expect( // required by `serde`
792    clippy::empty_enum_variants_with_brackets,
793    reason = "required by `serde`"
794)]
795#[serde_with::skip_serializing_none]
796#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
797#[serde(tag = "kind", rename_all = "camelCase")]
798pub enum ReceiverStatsKind {
799    /// [RTCAudioReceiverStats] object.
800    ///
801    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcaudioreceiverstats
802    Audio {},
803
804    /// [RTCVideoReceiverStats] object.
805    ///
806    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcvideoreceiverstats
807    Video {},
808}
809
810/// ICE candidate pair statistics related to the [RTCIceTransport] objects.
811///
812/// A candidate pair that is not the current pair for a transport is
813/// [deleted][1] when the [RTCIceTransport] does an ICE restart, at the time
814/// the state changes to `new`.
815///
816/// The candidate pair that is the current pair for a transport is deleted after
817/// an ICE restart when the [RTCIceTransport] switches to using a candidate pair
818/// generated from the new candidates; this time doesn't correspond to any other
819/// externally observable event.
820///
821/// [`RtcStatsType::CandidatePair`] variant.
822///
823/// [Full doc on W3C][2].
824///
825/// [RTCIceTransport]: https://w3.org/TR/webrtc#dom-rtcicetransport
826/// [1]: https://w3.org/TR/webrtc-stats/#dfn-deleted
827/// [2]: https://w3.org/TR/webrtc-stats/#candidatepair-dict%2A
828#[serde_with::skip_serializing_none]
829#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
830#[serde(rename_all = "camelCase")]
831pub struct RtcIceCandidatePairStats {
832    /// Unique identifier associated to the object that was inspected to
833    /// produce the [`RtcTransportStats`] associated with this candidates
834    /// pair.
835    pub transport_id: Option<String>,
836
837    /// Unique identifier associated to the object that was inspected to
838    /// produce the [`RtcIceCandidateStats`] for the local candidate
839    /// associated with this candidates pair.
840    pub local_candidate_id: Option<String>,
841
842    /// Unique identifier associated to the object that was inspected to
843    /// produce the [`RtcIceCandidateStats`] for the remote candidate
844    /// associated with this candidates pair.
845    pub remote_candidate_id: Option<String>,
846
847    /// State of the checklist for the local and remote candidates in a pair.
848    pub state: IceCandidatePairState,
849
850    /// Related to updating the nominated flag described in
851    /// [Section 7.1.3.2.4 of RFC 5245][1].
852    ///
853    /// [1]: https://tools.ietf.org/html/rfc5245#section-7.1.3.2.4
854    pub nominated: bool,
855
856    /// Total number of payload bytes sent on this candidate pair, i.e. not
857    /// including headers or padding.
858    pub bytes_sent: u64,
859
860    /// Total number of payload bytes received on this candidate pair, i.e. not
861    /// including headers or padding.
862    pub bytes_received: u64,
863
864    /// Sum of all round trip time measurements in seconds since the beginning
865    /// of the session, based on STUN connectivity check [STUN-PATH-CHAR]
866    /// responses (responsesReceived), including those that reply to requests
867    /// that are sent in order to verify consent [RFC 7675].
868    ///
869    /// The average round trip time can be computed from
870    /// [`totalRoundTripTime`][1] by dividing it by [`responsesReceived`][2].
871    ///
872    /// [STUN-PATH-CHAR]: https://w3.org/TR/webrtc-stats/#bib-stun-path-char
873    /// [RFC 7675]: https://tools.ietf.org/html/rfc7675
874    /// [1]: https://tinyurl.com/tgr543a
875    /// [2]: https://tinyurl.com/r3zo2um
876    pub total_round_trip_time: Option<HighResTimeStamp>,
877
878    /// Latest round trip time measured in seconds, computed from both STUN
879    /// connectivity checks [STUN-PATH-CHAR], including those that are sent for
880    /// consent verification [RFC 7675].
881    ///
882    /// [STUN-PATH-CHAR]: https://w3.org/TR/webrtc-stats/#bib-stun-path-char
883    /// [RFC 7675]: https://tools.ietf.org/html/rfc7675
884    pub current_round_trip_time: Option<HighResTimeStamp>,
885
886    /// Calculated by the underlying congestion control by combining the
887    /// available bitrate for all the outgoing RTP streams using this candidate
888    /// pair. The bitrate measurement does not count the size of the IP or
889    /// other transport layers like TCP or UDP. It is similar to the TIAS
890    /// defined in [RFC 3890], i.e. it is measured in bits per second and the
891    /// bitrate is calculated over a 1 second window.
892    ///
893    /// Implementations that do not calculate a sender-side estimate MUST leave
894    /// this undefined. Additionally, the value MUST be undefined for candidate
895    /// pairs that were never used. For pairs in use, the estimate is normally
896    /// no lower than the bitrate for the packets sent at
897    /// [`lastPacketSentTimestamp`][1], but might be higher. For candidate
898    /// pairs that are not currently in use but were used before,
899    /// implementations MUST return undefined.
900    ///
901    /// [RFC 3890]: https://tools.ietf.org/html/rfc3890
902    /// [1]: https://tinyurl.com/rfc72eh
903    pub available_outgoing_bitrate: Option<u64>,
904}
905
906/// Possible states of a candidate pair.
907///
908/// > Each candidate pair in the check list has a foundation and a state.
909/// > The foundation is the combination of the foundations of the local and
910/// > remote candidates in the pair.  The state is assigned once the check
911/// > list for each media stream has been computed.  There are five
912/// > potential values that the state can have.
913#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
914#[serde(rename_all = "kebab-case")]
915pub enum KnownIceCandidatePairState {
916    /// Check has not been performed for this pair, and can be performed as
917    /// soon as it is the highest-priority Waiting pair on the check list.
918    Waiting,
919
920    /// Check has been sent for this pair, but the transaction is in progress.
921    InProgress,
922
923    /// Check for this pair was already done and produced a successful result.
924    Succeeded,
925
926    /// Check for this pair was already done and failed, either never producing
927    /// any response or producing an unrecoverable failure response.
928    Failed,
929
930    /// Check for this pair hasn't been performed, and it can't yet be
931    /// performed until some other check succeeds, allowing this pair to
932    /// unfreeze and move into the [`KnownIceCandidatePairState::Waiting`]
933    /// state.
934    Frozen,
935
936    /// Other Candidate pair was nominated.
937    ///
938    /// This state is **obsolete and not spec compliant**, however, it still
939    /// may be emitted by some implementations.
940    Cancelled,
941}
942
943/// Non-exhaustive version of [`KnownIceCandidatePairState`].
944pub type IceCandidatePairState = NonExhaustive<KnownIceCandidatePairState>;
945
946/// Known protocols used in the WebRTC.
947#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
948#[serde(rename_all = "lowercase")]
949pub enum KnownProtocol {
950    /// [User Datagram Protocol][1].
951    ///
952    /// [1]: https://en.wikipedia.org/wiki/User_Datagram_Protocol
953    Udp,
954
955    /// [Transmission Control Protocol][1].
956    ///
957    /// [1]: https://en.wikipedia.org/wiki/Transmission_Control_Protocol
958    Tcp,
959}
960
961/// Non-exhaustive version of [`KnownProtocol`].
962pub type Protocol = NonExhaustive<KnownProtocol>;
963
964/// [RTCIceCandidateType] represents the type of the ICE candidate, as
965/// defined in [Section 15.1 of RFC 5245][1].
966///
967/// [RTCIceCandidateType]: https://w3.org/TR/webrtc#rtcicecandidatetype-enum
968/// [1]: https://tools.ietf.org/html/rfc5245#section-15.1
969#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
970#[serde(rename_all = "lowercase")]
971pub enum KnownCandidateType {
972    /// Host candidate, as defined in [Section 4.1.1.1 of RFC 5245][1].
973    ///
974    /// [1]: https://tools.ietf.org/html/rfc5245#section-4.1.1.1
975    Host,
976
977    /// Server reflexive candidate, as defined in
978    /// [Section 4.1.1.2 of RFC 5245][1].
979    ///
980    /// [1]: https://tools.ietf.org/html/rfc5245#section-4.1.1.2
981    Srlfx,
982
983    /// Peer reflexive candidate, as defined in
984    /// [Section 4.1.1.2 of RFC 5245][1].
985    ///
986    /// [1]: https://tools.ietf.org/html/rfc5245#section-4.1.1.2
987    Prflx,
988
989    /// Relay candidate, as defined in [Section 7.1.3.2.1 of RFC 5245][1].
990    ///
991    /// [1]: https://tools.ietf.org/html/rfc5245#section-7.1.3.2.1
992    Relay,
993}
994
995/// Non-exhaustive version of [`KnownCandidateType`].
996pub type CandidateType = NonExhaustive<KnownCandidateType>;
997
998/// Fields of [`RtcStatsType::InboundRtp`] variant.
999#[serde_with::skip_serializing_none]
1000#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
1001#[serde(tag = "kind", rename_all = "camelCase")]
1002pub enum RtcInboundRtpStreamMediaType {
1003    /// Fields when the `kind` is `audio`.
1004    #[serde(rename_all = "camelCase")]
1005    Audio {
1006        /// Indicator whether the last RTP packet whose frame was delivered to
1007        /// the [RTCRtpReceiver]'s [MediaStreamTrack][1] for playout contained
1008        /// voice activity or not based on the presence of the V bit in the
1009        /// extension header, as defined in [RFC 6464].
1010        ///
1011        /// [RTCRtpReceiver]: https://w3.org/TR/webrtc#rtcrtpreceiver-interface
1012        /// [RFC 6464]: https://tools.ietf.org/html/rfc6464#page-3
1013        /// [1]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
1014        voice_activity_flag: Option<bool>,
1015
1016        /// Total number of samples that have been received on this RTP stream.
1017        /// This includes [`concealedSamples`].
1018        ///
1019        /// [`concealedSamples`]: https://tinyurl.com/s6c4qe4
1020        total_samples_received: Option<u64>,
1021
1022        /// Total number of samples that are concealed samples.
1023        ///
1024        /// A concealed sample is a sample that was replaced with synthesized
1025        /// samples generated locally before being played out.
1026        /// Examples of samples that have to be concealed are samples from lost
1027        /// packets (reported in [`packetsLost`]) or samples from packets that
1028        /// arrive too late to be played out (reported in
1029        /// [`packetsDiscarded`]).
1030        ///
1031        /// [`packetsLost`]: https://tinyurl.com/u2gq965
1032        /// [`packetsDiscarded`]: https://tinyurl.com/yx7qyox3
1033        concealed_samples: Option<u64>,
1034
1035        /// Total number of concealed samples inserted that are "silent".
1036        ///
1037        /// Playing out silent samples results in silence or comfort noise.
1038        /// This is a subset of [`concealedSamples`].
1039        ///
1040        /// [`concealedSamples`]: https://tinyurl.com/s6c4qe4
1041        silent_concealed_samples: Option<u64>,
1042
1043        /// Audio level of the receiving track.
1044        audio_level: Option<Float>,
1045
1046        /// Audio energy of the receiving track.
1047        total_audio_energy: Option<Float>,
1048
1049        /// Audio duration of the receiving track.
1050        ///
1051        /// For audio durations of tracks attached locally, see
1052        /// [RTCAudioSourceStats][1] instead.
1053        ///
1054        /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcaudiosourcestats
1055        total_samples_duration: Option<HighResTimeStamp>,
1056    },
1057
1058    /// Fields when the `kind` is `video`.
1059    #[serde(rename_all = "camelCase")]
1060    Video {
1061        /// Total number of frames correctly decoded for this RTP stream, i.e.
1062        /// frames that would be displayed if no frames are dropped.
1063        frames_decoded: Option<u64>,
1064
1065        /// Total number of key frames, such as key frames in VP8 [RFC 6386] or
1066        /// IDR-frames in H.264 [RFC 6184], successfully decoded for this RTP
1067        /// media stream.
1068        ///
1069        /// This is a subset of [`framesDecoded`].
1070        /// [`framesDecoded`] - [`keyFramesDecoded`] gives you the number of
1071        /// delta frames decoded.
1072        ///
1073        /// [RFC 6386]: https://w3.org/TR/webrtc-stats/#bib-rfc6386
1074        /// [RFC 6184]: https://w3.org/TR/webrtc-stats/#bib-rfc6184
1075        /// [`framesDecoded`]: https://tinyurl.com/srfwrwt
1076        /// [`keyFramesDecoded`]: https://tinyurl.com/qtdmhtm
1077        key_frames_decoded: Option<u64>,
1078
1079        /// Width of the last decoded frame.
1080        ///
1081        /// Before the first frame is decoded this attribute is missing.
1082        frame_width: Option<u64>,
1083
1084        /// Height of the last decoded frame.
1085        ///
1086        /// Before the first frame is decoded this attribute is missing.
1087        frame_height: Option<u64>,
1088
1089        /// Sum of the interframe delays in seconds between consecutively
1090        /// decoded frames, recorded just after a frame has been decoded.
1091        total_inter_frame_delay: Option<Float>,
1092
1093        /// Number of decoded frames in the last second.
1094        frames_per_second: Option<Float>,
1095
1096        /// Bit depth per pixel of the last decoded frame.
1097        ///
1098        /// Typical values are 24, 30, or 36 bits. Before the first frame is
1099        /// decoded this attribute is missing.
1100        frame_bit_depth: Option<u64>,
1101
1102        /// Total number of Full Intra Request (FIR) packets sent by this
1103        /// receiver.
1104        fir_count: Option<u64>,
1105
1106        /// Total number of Picture Loss Indication (PLI) packets sent by this
1107        /// receiver.
1108        pli_count: Option<u64>,
1109
1110        /// Total number of Slice Loss Indication (SLI) packets sent by this
1111        /// receiver.
1112        sli_count: Option<u64>,
1113
1114        /// Number of concealment events.
1115        ///
1116        /// This counter increases every time a concealed sample is synthesized
1117        /// after a non-concealed sample. That is, multiple consecutive
1118        /// concealed samples will increase the [`concealedSamples`] count
1119        /// multiple times but is a single concealment event.
1120        ///
1121        /// [`concealedSamples`]: https://tinyurl.com/s6c4qe4
1122        concealment_events: Option<u64>,
1123
1124        /// Total number of complete frames received on this RTP stream.
1125        ///
1126        /// This metric is incremented when the complete frame is received.
1127        frames_received: Option<u64>,
1128    },
1129}
1130
1131/// Representation of the measurement metrics for the incoming [RTP] media
1132/// stream. The timestamp reported in the statistics object is the time at which
1133/// the data was sampled.
1134///
1135/// [`RtcStatsType::InboundRtp`] variant.
1136///
1137/// [Full doc on W3C][1].
1138///
1139/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
1140/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats
1141#[serde_with::skip_serializing_none]
1142#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
1143#[serde(rename_all = "camelCase")]
1144pub struct RtcInboundRtpStreamStats {
1145    /// ID of the stats object representing the receiving track.
1146    pub track_id: Option<String>,
1147
1148    /// Fields which should be in the [`RtcStat`] based on its `kind`.
1149    #[serde(flatten)]
1150    pub media_specific_stats: RtcInboundRtpStreamMediaType,
1151
1152    /// Total number of bytes received for this SSRC.
1153    pub bytes_received: u64,
1154
1155    /// Total number of RTP data packets received for this SSRC.
1156    pub packets_received: u64,
1157
1158    /// Total number of RTP data packets for this SSRC that have been lost
1159    /// since the beginning of reception.
1160    ///
1161    /// This number is defined to be the number of packets expected less the
1162    /// number of packets actually received, where the number of packets
1163    /// received includes any which are late or duplicates. Thus, packets that
1164    /// arrive late are not counted as lost, and the loss __may be negative__
1165    /// if there are duplicates.
1166    pub packets_lost: Option<i64>,
1167
1168    /// Packet jitter measured in seconds for this SSRC.
1169    pub jitter: Option<Float>,
1170
1171    /// Total number of seconds that have been spent decoding the
1172    /// [`framesDecoded`] frames of this stream.
1173    ///
1174    /// The average decode time can be calculated by dividing this value with
1175    /// [`framesDecoded`]. The time it takes to decode one frame is the time
1176    /// passed between feeding the decoder a frame and the decoder returning
1177    /// decoded data for that frame.
1178    ///
1179    /// [`framesDecoded`]: https://tinyurl.com/srfwrwt
1180    pub total_decode_time: Option<HighResTimeStamp>,
1181
1182    /// Total number of audio samples or video frames that have come out of the
1183    /// jitter buffer (increasing [`jitterBufferDelay`]).
1184    ///
1185    /// [`jitterBufferDelay`]: https://tinyurl.com/qvoojt5
1186    pub jitter_buffer_emitted_count: Option<u64>,
1187}
1188
1189/// Statistics related to a specific [MediaStreamTrack][1]'s attachment to an
1190/// [RTCRtpSender] and the corresponding media-level metrics.
1191///
1192/// [`RtcStatsType::Track`] variant.
1193///
1194/// [Full doc on W3C][1].
1195///
1196/// [RTCRtpSender]: https://w3.org/TR/webrtc#rtcrtpsender-interface
1197/// [1]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
1198/// [2]: https://w3.org/TR/webrtc-stats/#dom-rtcstatstype-track
1199#[serde_with::skip_serializing_none]
1200#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
1201#[serde(rename_all = "camelCase")]
1202pub struct TrackStats {
1203    /// [`id` property][1] of the track.
1204    ///
1205    /// [1]: https://w3.org/TR/mediacapture-streams#dom-mediastreamtrack-id
1206    pub track_identifier: String,
1207
1208    /// `true` if the source is remote, for instance if it is sourced from
1209    /// another host via an [RTCPeerConnection]. `false` otherwise.
1210    ///
1211    /// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
1212    pub remote_source: Option<bool>,
1213
1214    /// Reflection of the "ended" state of the track.
1215    pub ended: Option<bool>,
1216
1217    /// Either `audio` or `video`.
1218    ///
1219    /// This reflects the [`kind` attribute][2] of the [MediaStreamTrack][1].
1220    ///
1221    /// [1]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
1222    /// [2]: https://w3.org/TR/mediacapture-streams#dom-mediastreamtrack-kind
1223    pub kind: Option<TrackStatsKind>,
1224}
1225
1226/// [`kind` attribute] values of the [MediaStreamTrack][1].
1227///
1228/// [1]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
1229/// [2]: https://w3.org/TR/mediacapture-streams#dom-mediastreamtrack-kind
1230#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
1231#[serde(rename_all = "camelCase")]
1232pub enum TrackStatsKind {
1233    /// Track is used for the audio content.
1234    Audio,
1235
1236    /// Track is used for the video content.
1237    Video,
1238}
1239
1240/// [`RtcStat`] fields of [`RtcStatsType::OutboundRtp`] type based on its
1241/// `kind`.
1242#[serde_with::skip_serializing_none]
1243#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
1244#[serde(tag = "kind", rename_all = "camelCase")]
1245pub enum RtcOutboundRtpStreamMediaType {
1246    /// Fields when the `kind` is `audio`.
1247    #[serde(rename_all = "camelCase")]
1248    Audio {
1249        /// Total number of samples that have been sent over this RTP stream.
1250        total_samples_sent: Option<u64>,
1251
1252        /// Whether the last RTP packet sent contained voice activity or not
1253        /// based on the presence of the V bit in the extension header.
1254        voice_activity_flag: Option<bool>,
1255    },
1256
1257    /// Fields when the `kind` is `video`.
1258    #[serde(rename_all = "camelCase")]
1259    Video {
1260        /// Width of the last encoded frame.
1261        ///
1262        /// The resolution of the encoded frame may be lower than the media
1263        /// source (see [RTCVideoSourceStats.width][1]).
1264        ///
1265        /// Before the first frame is encoded this attribute is missing.
1266        ///
1267        /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcvideosourcestats-width
1268        frame_width: Option<u64>,
1269
1270        /// Height of the last encoded frame.
1271        ///
1272        /// The resolution of the encoded frame may be lower than the media
1273        /// source (see [RTCVideoSourceStats.height][1]).
1274        ///
1275        /// Before the first frame is encoded this attribute is missing.
1276        ///
1277        /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcvideosourcestats-height
1278        frame_height: Option<u64>,
1279
1280        /// Number of encoded frames during the last second.
1281        ///
1282        /// This may be lower than the media source frame rate (see
1283        /// [RTCVideoSourceStats.framesPerSecond][1]).
1284        ///
1285        /// [1]: https://tinyurl.com/rrmkrfk
1286        frames_per_second: Option<Float>,
1287    },
1288}
1289
1290/// Statistics for an outbound [RTP] stream that is currently sent with this
1291/// [RTCPeerConnection] object.
1292///
1293/// When there are multiple [RTP] streams connected to the same sender, such
1294/// as when using simulcast or RTX, there will be one
1295/// [`RtcOutboundRtpStreamStats`] per RTP stream, with distinct values of
1296/// the `ssrc` attribute, and all these senders will have a reference to
1297/// the same "sender" object (of type [RTCAudioSenderStats][1] or
1298/// [RTCVideoSenderStats][2]) and "track" object (of type
1299/// [RTCSenderAudioTrackAttachmentStats][3] or
1300/// [RTCSenderVideoTrackAttachmentStats][4]).
1301///
1302/// [`RtcStatsType::OutboundRtp`] variant.
1303///
1304/// [Full doc on W3C][5].
1305///
1306/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
1307/// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
1308/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcaudiosenderstats
1309/// [2]: https://w3.org/TR/webrtc-stats/#dom-rtcvideosenderstats
1310/// [3]: https://tinyurl.com/sefa5z4
1311/// [4]: https://tinyurl.com/rkuvpl4
1312/// [5]: https://w3.org/TR/webrtc-stats/#outboundrtpstats-dict%2A
1313#[serde_with::skip_serializing_none]
1314#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
1315#[serde(rename_all = "camelCase")]
1316pub struct RtcOutboundRtpStreamStats {
1317    /// ID of the stats object representing the current track attachment to the
1318    /// sender of this stream.
1319    pub track_id: Option<String>,
1320
1321    /// Fields which should be in the [`RtcStat`] based on its `kind`.
1322    #[serde(flatten)]
1323    pub media_type: RtcOutboundRtpStreamMediaType,
1324
1325    /// Total number of bytes sent for this SSRC.
1326    pub bytes_sent: Option<u64>,
1327
1328    /// Total number of RTP packets sent for this SSRC.
1329    pub packets_sent: Option<u64>,
1330
1331    /// ID of the stats object representing the track currently
1332    /// attached to the sender of this stream.
1333    pub media_source_id: Option<String>,
1334}
1335
1336/// Properties of a `candidate` in [Section 15.1 of RFC 5245][1].
1337/// It corresponds to a [RTCIceTransport] object.
1338///
1339/// [`RtcStatsType::LocalCandidate`] or [`RtcStatsType::RemoteCandidate`]
1340/// variant.
1341///
1342/// [Full doc on W3C][2].
1343///
1344/// [RTCIceTransport]: https://w3.org/TR/webrtc#dom-rtcicetransport
1345/// [1]: https://tools.ietf.org/html/rfc5245#section-15.1
1346/// [2]: https://w3.org/TR/webrtc-stats/#icecandidate-dict%2A
1347#[serde_with::skip_serializing_none]
1348#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
1349#[serde(rename_all = "camelCase")]
1350pub struct RtcIceCandidateStats {
1351    /// Unique ID that is associated to the object that was inspected to
1352    /// produce the [RTCTransportStats][1] associated with this candidate.
1353    ///
1354    /// [1]: https://w3.org/TR/webrtc-stats/#transportstats-dict%2A
1355    pub transport_id: Option<String>,
1356
1357    /// Address of the candidate, allowing for IPv4 addresses, IPv6 addresses,
1358    /// and fully qualified domain names (FQDNs).
1359    pub address: Option<String>,
1360
1361    /// Port number of the candidate.
1362    pub port: u16,
1363
1364    /// Valid values for transport is one of `udp` and `tcp`.
1365    pub protocol: Protocol,
1366
1367    /// Type of the ICE candidate.
1368    pub candidate_type: CandidateType,
1369
1370    /// Calculated as defined in [Section 15.1 of RFC 5245][1].
1371    ///
1372    /// [1]: https://tools.ietf.org/html/rfc5245#section-15.1
1373    pub priority: u32,
1374
1375    /// For local candidates this is the URL of the ICE server from which the
1376    /// candidate was obtained. It is the same as the
1377    /// [url surfaced in the RTCPeerConnectionIceEvent][1].
1378    ///
1379    /// `None` for remote candidates.
1380    ///
1381    /// [1]: https://w3.org/TR/webrtc#rtcpeerconnectioniceevent
1382    pub url: Option<String>,
1383
1384    /// Protocol used by the endpoint to communicate with the TURN server.
1385    ///
1386    /// Only present for local candidates.
1387    pub relay_protocol: Option<Protocol>,
1388}
1389
1390/// [`RtcStat`] fields of [`RtcStatsType::MediaSource`] type based on its
1391/// `kind`.
1392#[serde_with::skip_serializing_none]
1393#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
1394#[serde(tag = "kind", rename_all = "camelCase")]
1395pub enum MediaKind {
1396    /// Fields when the `kind` is `video`.
1397    #[serde(rename_all = "camelCase")]
1398    Video {
1399        /// Width (in pixels) of the last frame originating from the source.
1400        /// Before a frame has been produced this attribute is missing.
1401        width: Option<u32>,
1402
1403        /// Height (in pixels) of the last frame originating from the source.
1404        /// Before a frame has been produced this attribute is missing.
1405        height: Option<u32>,
1406
1407        /// Number of frames originating from the source, measured during the
1408        /// last second. For the first second of this object's lifetime this
1409        /// attribute is missing.
1410        frames_per_second: Option<Float>,
1411    },
1412
1413    /// Fields when the `kind` is `audio`.
1414    #[serde(rename_all = "camelCase")]
1415    Audio {
1416        /// Audio level of the media source.
1417        audio_level: Option<Float>,
1418
1419        /// Audio energy of the media source.
1420        total_audio_energy: Option<Float>,
1421
1422        /// Audio duration of the media source.
1423        total_samples_duration: Option<Float>,
1424    },
1425}
1426
1427/// Statistics for the media produced by a [MediaStreamTrack][1] that is
1428/// currently attached to an [RTCRtpSender].
1429///
1430/// This reflects the media that is fed to the encoder after [getUserMedia]
1431/// constraints have been applied (i.e. not the raw media produced by the
1432/// camera).
1433///
1434/// [`RtcStatsType::MediaSource`] variant.
1435///
1436/// [Full doc on W3C][2].
1437///
1438/// [RTCRtpSender]: https://w3.org/TR/webrtc#rtcrtpsender-interface
1439/// [getUserMedia]: https://tinyurl.com/sngpyr6
1440/// [1]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
1441/// [2]: https://w3.org/TR/webrtc-stats/#dom-rtcstatstype-media-source
1442#[serde_with::skip_serializing_none]
1443#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
1444#[serde(rename_all = "camelCase")]
1445pub struct MediaSourceStats {
1446    /// Value of the [MediaStreamTrack][1]'s ID attribute.
1447    ///
1448    /// [1]: https://w3.org/TR/mediacapture-streams#mediastreamtrack
1449    pub track_identifier: Option<String>,
1450
1451    /// Fields which should be in the [`RtcStat`] based on `kind`.
1452    #[serde(flatten)]
1453    pub kind: MediaKind,
1454}
1455
1456#[cfg(feature = "extended-stats")]
1457/// Statistics for a codec that is currently used by [RTP] streams being sent or
1458/// received by [RTCPeerConnection] object.
1459///
1460/// [`RtcStatsType::Codec`] variant.
1461///
1462/// [Full doc on W3C][1].
1463///
1464/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
1465/// [RTCPeerConnection]: https://w3.org/TR/webrtc#dom-rtcpeerconnection
1466/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtccodecstats
1467#[serde_with::skip_serializing_none]
1468#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
1469#[serde(rename_all = "camelCase")]
1470pub struct RtcCodecStats {
1471    /// [Payload type][1] as used in [RTP] encoding or decoding.
1472    ///
1473    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
1474    /// [1]: https://tools.ietf.org/html/rfc3550#page-14
1475    pub payload_type: u32,
1476
1477    /// The codec MIME media `type/subtype` (e.g. `video/vp8` or equivalent).
1478    pub mime_type: String,
1479
1480    /// Media sampling rate.
1481    pub clock_rate: u32,
1482}
1483
1484#[cfg(feature = "extended-stats")]
1485/// Information about a certificate used by [RTCIceTransport].
1486///
1487/// [`RtcStatsType::Certificate`] variant.
1488///
1489/// [Full doc on W3C][1].
1490///
1491/// [RTCIceTransport]: https://w3.org/TR/webrtc#dom-rtcicetransport
1492/// [1]: https://w3.org/TR/webrtc-stats/#certificatestats-dict%2A
1493#[serde_with::skip_serializing_none]
1494#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
1495#[serde(rename_all = "camelCase")]
1496pub struct RtcCertificateStats {
1497    /// Fingerprint of the certificate.
1498    ///
1499    /// Only use the fingerprint value as defined in [Section 5 of RFC
1500    /// 4572][1].
1501    ///
1502    /// [1]: https://tools.ietf.org/html/rfc4572#section-5
1503    pub fingerprint: String,
1504
1505    /// Hash function used to compute the certificate fingerprint.
1506    /// For instance, `sha-256`.
1507    pub fingerprint_algorithm: String,
1508
1509    /// The DER-encoded Base64 representation of the certificate.
1510    pub base64_certificate: String,
1511}
1512
1513/// Representation of [DOMHighResTimeStamp][1].
1514///
1515/// Can be converted to the [`SystemTime`] with millisecond-wise accuracy.
1516///
1517/// [`HighResTimeStamp`] type is a [`f64`] and is used to store a time value
1518/// in milliseconds. This type can be used to describe a discrete point in time
1519/// or a time interval (the difference in time between two discrete points in
1520/// time).
1521///
1522/// The time, given in milliseconds, should be accurate to 5 µs (microseconds),
1523/// with the fractional part of the number indicating fractions of a
1524/// millisecond. However, if the browser is unable to provide a time value
1525/// accurate to 5 µs (due, for example, to hardware or software constraints),
1526/// the browser can represent the value as a time in milliseconds accurate to a
1527/// millisecond. Also note the section below on reduced time precision
1528/// controlled by browser preferences to avoid timing attacks and
1529/// fingerprinting.
1530///
1531/// Further, if the device or operating system the user agent is running on
1532/// doesn't have a clock accurate to the microsecond level, they may only be
1533/// accurate to the millisecond.
1534///
1535/// [1]: https://developer.mozilla.org/docs/Web/API/DOMHighResTimeStamp
1536#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
1537pub struct HighResTimeStamp(pub f64);
1538
1539impl From<HighResTimeStamp> for SystemTime {
1540    fn from(timestamp: HighResTimeStamp) -> Self {
1541        Self::UNIX_EPOCH + Duration::from_secs_f64(timestamp.0 / 100.0)
1542    }
1543}
1544
1545impl TryFrom<SystemTime> for HighResTimeStamp {
1546    type Error = SystemTimeError;
1547
1548    fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
1549        Ok(Self(
1550            time.duration_since(SystemTime::UNIX_EPOCH)?.as_secs_f64() * 100.0,
1551        ))
1552    }
1553}
1554
1555/// Hashing string representation.
1556///
1557/// Some people believe that such behavior is incorrect (but in some programming
1558/// languages this is a default behavior) due to `NaN`, `Inf` or `-Inf` (they
1559/// all will have the same hashes).
1560/// But in the case of [`RtcStat`] received from the client, there should be no
1561/// such situations, and the hash will always be correct.
1562impl Hash for HighResTimeStamp {
1563    fn hash<H: Hasher>(&self, state: &mut H) {
1564        self.0.to_string().hash(state);
1565    }
1566}
1567
1568/// Comparison string representations.
1569///
1570/// Such implementation is required, so that the results of comparing values and
1571/// comparing hashes match.
1572impl PartialEq for HighResTimeStamp {
1573    fn eq(&self, other: &Self) -> bool {
1574        self.0.to_string().eq(&other.0.to_string())
1575    }
1576}
1577
1578/// [`f64`] wrapper with [`Hash`] implementation.
1579#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
1580pub struct Float(pub f64);
1581
1582/// Hashing string representation.
1583///
1584/// Some people believe that such behavior is incorrect (but in some programming
1585/// languages this is a default behavior) due to `NaN`, `Inf` or `-Inf` (they
1586/// all will have the same hashes).
1587/// But in the case of [`RtcStat`] received from the client, there should be no
1588/// such situations, and the hash will always be correct.
1589impl Hash for Float {
1590    fn hash<H: Hasher>(&self, state: &mut H) {
1591        self.0.to_string().hash(state);
1592    }
1593}
1594
1595/// Comparison string representations.
1596///
1597/// Such implementation is required, so that the results of comparing values and
1598/// comparing hashes match.
1599impl PartialEq for Float {
1600    fn eq(&self, other: &Self) -> bool {
1601        self.0.to_string().eq(&other.0.to_string())
1602    }
1603}
1604
1605#[cfg(feature = "extended-stats")]
1606/// Information about the connection to an ICE server (e.g. STUN or TURN).
1607///
1608/// [`RtcStatsType::IceServer`] variant.
1609///
1610/// [Full doc on W3C][1].
1611///
1612/// [1]: https://w3.org/TR/webrtc-stats/#ice-server-dict%2A
1613#[serde_with::skip_serializing_none]
1614#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
1615#[serde(rename_all = "camelCase")]
1616pub struct RtcIceServerStats {
1617    /// URL of the ICE server (e.g. TURN or STUN server).
1618    pub url: String,
1619
1620    /// Port number used by the client.
1621    pub port: u16,
1622
1623    /// Protocol used by the client to connect to ICE server.
1624    pub protocol: Protocol,
1625
1626    /// Total amount of requests that have been sent to this server.
1627    pub total_requests_sent: Option<u64>,
1628
1629    /// Total amount of responses received from this server.
1630    pub total_responses_received: Option<u64>,
1631
1632    /// Sum of RTTs for all requests that have been sent where a response has
1633    /// been received.
1634    pub total_round_trip_time: Option<HighResTimeStamp>,
1635}