1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
//! Contains DTOs for [RTCPeerConnection] metrics.
//!
//! [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection

#![allow(clippy::module_name_repetitions)]

use std::{
    hash::{Hash, Hasher},
    time::{Duration, SystemTime},
};

use derive_more::{Display, From};
use serde::{Deserialize, Serialize};

/// Enum with which you can try to deserialize some known enum and if it
/// isn't known, then unknown data will be stored as [`String`] in the
/// [`NonExhaustive::Unknown`] variant.
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(untagged)]
pub enum NonExhaustive<T> {
    /// Will store known enum variant if it successfully deserialized.
    Known(T),

    /// Will store unknown enum variant with it's data as [`String`].
    Unknown(String),
}

/// Unique ID that is associated with the object that was inspected to produce
/// [`RtcStat`] object.
///
/// Two [`RtcStat`]s objects, extracted from two different [RTCStatsReport]
/// objects, MUST have the same ID if they were produced by inspecting the same
/// underlying object.
///
/// [RTCStatsReport]: https://w3.org/TR/webrtc/#dom-rtcstatsreport
#[derive(
    Clone, Debug, Deserialize, Display, Eq, From, Hash, PartialEq, Serialize,
)]
#[from(forward)]
pub struct StatId(pub String);

/// Represents the [stats object] constructed by inspecting a specific
/// [monitored object].
///
/// [Full doc on W3C][1].
///
/// [stats object]: https://w3.org/TR/webrtc-stats/#dfn-stats-object
/// [monitored object]: https://w3.org/TR/webrtc-stats/#dfn-monitored-object
/// [1]: https://w3.org/TR/webrtc/#rtcstats-dictionary
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
pub struct RtcStat {
    /// Unique ID that is associated with the object that was inspected to
    /// produce this [RTCStats] object.
    ///
    /// [RTCStats]: https://w3.org/TR/webrtc/#dom-rtcstats
    pub id: StatId,

    /// Timestamp associated with this object.
    ///
    /// The time is relative to the UNIX epoch (Jan 1, 1970, UTC).
    ///
    /// For statistics that came from a remote source (e.g., from received RTCP
    /// packets), timestamp represents the time at which the information
    /// arrived at the local endpoint. The remote timestamp can be found in an
    /// additional field in an [`RtcStat`]-derived dictionary, if applicable.
    pub timestamp: HighResTimeStamp,

    /// Actual stats of this [`RtcStat`].
    ///
    /// All possible stats are described in the [`RtcStatsType`] enum.
    #[serde(flatten)]
    pub stats: RtcStatsType,
}

/// All known types of [`RtcStat`]s.
///
/// [List of all RTCStats types on W3C][1].
///
/// [1]: https://w3.org/TR/webrtc-stats/#rtctatstype-%2A
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(tag = "type")]
#[serde(rename_all = "kebab-case")]
pub enum RtcStatsType {
    /// Statistics for a codec that is currently used by [RTP] streams being
    /// sent or received by [RTCPeerConnection] object.
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    #[cfg(feature = "extended-stats")]
    Codec(Box<RtcCodecStats>),

    /// Statistics for an inbound [RTP] stream that is currently received with
    /// [RTCPeerConnection] object.
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    InboundRtp(Box<RtcInboundRtpStreamStats>),

    /// Statistics for an outbound [RTP] stream that is currently sent with
    /// [RTCPeerConnection] object.
    ///
    /// When there are multiple [RTP] streams connected to the same sender,
    /// such as when using simulcast or RTX, there will be one
    /// [`RtcOutboundRtpStreamStats`] per RTP stream, with distinct values of
    /// the `ssrc` attribute, and all these senders will have a reference to
    /// the same "sender" object (of type [RTCAudioSenderStats][1] or
    /// [RTCVideoSenderStats][2]) and "track" object (of type
    /// [RTCSenderAudioTrackAttachmentStats][3] or
    /// [RTCSenderVideoTrackAttachmentStats][4]).
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcaudiosenderstats
    /// [2]: https://w3.org/TR/webrtc-stats/#dom-rtcvideosenderstats
    /// [3]: https://tinyurl.com/sefa5z4
    /// [4]: https://tinyurl.com/rkuvpl4
    OutboundRtp(Box<RtcOutboundRtpStreamStats>),

    /// Statistics for the remote endpoint's inbound [RTP] stream corresponding
    /// to an outbound stream that is currently sent with [RTCPeerConnection]
    /// object.
    ///
    /// It is measured at the remote endpoint and reported in a RTCP Receiver
    /// Report (RR) or RTCP Extended Report (XR).
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    RemoteInboundRtp(Box<RtcRemoteInboundRtpStreamStats>),

    /// Statistics for the remote endpoint's outbound [RTP] stream
    /// corresponding to an inbound stream that is currently received with
    /// [RTCPeerConnection] object.
    ///
    /// It is measured at the remote endpoint and reported in an RTCP Sender
    /// Report (SR).
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    RemoteOutboundRtp(Box<RtcRemoteOutboundRtpStreamStats>),

    /// Statistics for the media produced by a [MediaStreamTrack][1] that is
    /// currently attached to an [RTCRtpSender]. This reflects the media that
    /// is fed to the encoder after [getUserMedia] constraints have been
    /// applied (i.e. not the raw media produced by the camera).
    ///
    /// [RTCRtpSender]: https://w3.org/TR/webrtc/#rtcrtpsender-interface
    /// [getUserMedia]: https://tinyurl.com/sngpyr6
    /// [1]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
    MediaSource(Box<MediaSourceStats>),

    /// Statistics for a contributing source (CSRC) that contributed to an
    /// inbound [RTP] stream.
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    #[cfg(feature = "extended-stats")]
    Csrc(Box<RtpContributingSourceStats>),

    /// Statistics related to the [RTCPeerConnection] object.
    ///
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    #[cfg(feature = "extended-stats")]
    PeerConnection(Box<RtcPeerConnectionStats>),

    /// Statistics related to each [RTCDataChannel] ID.
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    #[cfg(feature = "extended-stats")]
    DataChannel(Box<DataChannelStats>),

    /// Contains statistics related to a specific [MediaStream].
    ///
    /// This is now obsolete.
    ///
    /// [MediaStream]: https://w3.org/TR/mediacapture-streams/#mediastream
    #[cfg(feature = "extended-stats")]
    Stream(Box<MediaStreamStats>),

    /// Statistics related to a specific [MediaStreamTrack][1]'s attachment to
    /// an [RTCRtpSender] and the corresponding media-level metrics.
    ///
    /// [RTCRtpSender]: https://w3.org/TR/webrtc/#rtcrtpsender-interface
    /// [1]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
    Track(Box<TrackStats>),

    /// Statistics related to a specific [RTCRtpTransceiver].
    ///
    /// [RTCRtpTransceiver]: https://w3.org/TR/webrtc/#dom-rtcrtptransceiver
    #[cfg(feature = "extended-stats")]
    Transceiver(Box<RtcRtpTransceiverStats>),

    /// Statistics related to a specific [RTCRtpSender] and the corresponding
    /// media-level metrics.
    ///
    /// [RTCRtpSender]: https://w3.org/TR/webrtc/#rtcrtpsender-interface
    #[cfg(feature = "extended-stats")]
    Sender(Box<SenderStatsKind>),

    /// Statistics related to a specific [RTCRtpReceiver] and the corresponding
    /// media-level metrics.
    ///
    /// [RTCRtpReceiver]: https://w3.org/TR/webrtc/#dom-rtcrtpreceiver
    #[cfg(feature = "extended-stats")]
    Receiver(Box<ReceiverStatsKind>),

    /// Transport statistics related to the [RTCPeerConnection] object.
    ///
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    Transport(Box<RtcTransportStats>),

    /// SCTP transport statistics related to an [RTCSctpTransport] object.
    ///
    /// [RTCSctpTransport]: https://w3.org/TR/webrtc/#dom-rtcsctptransport
    SctpTransport(Box<RtcSctpTransportStats>),

    /// ICE candidate pair statistics related to the [RTCIceTransport] objects.
    ///
    /// A candidate pair that is not the current pair for a transport is
    /// [deleted][1] when the [RTCIceTransport] does an ICE restart, at the
    /// time the state changes to `new`.
    ///
    /// The candidate pair that is the current pair for a transport is deleted
    /// after an ICE restart when the [RTCIceTransport] switches to using a
    /// candidate pair generated from the new candidates; this time doesn't
    /// correspond to any other externally observable event.
    ///
    /// [RTCIceTransport]: https://w3.org/TR/webrtc/#dom-rtcicetransport
    /// [1]: https://w3.org/TR/webrtc-stats/#dfn-deleted
    CandidatePair(Box<RtcIceCandidatePairStats>),

    /// ICE local candidate statistics related to the [RTCIceTransport]
    /// objects.
    ///
    /// A local candidate is [deleted][1] when the [RTCIceTransport] does an
    /// ICE restart, and the candidate is no longer a member of any
    /// non-deleted candidate pair.
    ///
    /// [RTCIceTransport]: https://w3.org/TR/webrtc/#dom-rtcicetransport
    /// [1]: https://w3.org/TR/webrtc-stats/#dfn-deleted
    LocalCandidate(Box<RtcIceCandidateStats>),

    /// ICE remote candidate statistics related to the [RTCIceTransport]
    /// objects.
    ///
    /// A remote candidate is [deleted][1] when the [RTCIceTransport] does an
    /// ICE restart, and the candidate is no longer a member of any non-deleted
    /// candidate pair.
    ///
    /// [RTCIceTransport]: https://w3.org/TR/webrtc/#dom-rtcicetransport
    /// [1]: https://w3.org/TR/webrtc-stats/#dfn-deleted
    RemoteCandidate(Box<RtcIceCandidateStats>),

    /// Information about a certificate used by [RTCIceTransport].
    ///
    /// [RTCIceTransport]: https://w3.org/TR/webrtc/#dom-rtcicetransport
    #[cfg(feature = "extended-stats")]
    Certificate(Box<RtcCertificateStats>),

    /// Information about the connection to an ICE server (e.g. STUN or TURN).
    #[cfg(feature = "extended-stats")]
    IceServer(Box<RtcIceServerStats>),

    /// Disabled or unknown variants of stats will be deserialized as
    /// [`RtcStatsType::Other`].
    #[serde(other)]
    Other,
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// Contains statistics related to a specific [MediaStream].
///
/// This is now obsolete.
///
/// [`RtcStatsType::Stream`] variant.
///
/// [Full doc on W3C][1].
///
/// [MediaStream]: https://w3.org/TR/mediacapture-streams/#mediastream
/// [1]: https://w3.org/TR/webrtc-stats/#idl-def-rtcmediastreamstats
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MediaStreamStats {
    /// [`stream.id`][1] property.
    ///
    /// [1]: https://w3.org/TR/mediacapture-streams/#dom-mediastream-id
    pub stream_identifier: String,

    /// ID of the stats object, not the `track.id`.
    pub track_ids: Vec<StatId>,
}

#[cfg(feature = "extended-stats")]
/// Statistics related to each [RTCDataChannel] ID.
///
/// [`RtcStatsType::DataChannel`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
/// [1]: https://w3.org/TR/webrtc-stats/#dcstats-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DataChannelStats {
    /// [`label`][1] value of the [RTCDataChannel] object.
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    /// [1]: https://w3.org/TR/webrtc/#dom-datachannel-label
    pub label: Option<String>,

    /// [`protocol`][1] value of the [RTCDataChannel] object.
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    /// [1]: https://w3.org/TR/webrtc/#dom-datachannel-protocol
    pub protocol: Option<Protocol>,

    /// [`id`][1] attribute of the [RTCDataChannel] object.
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    /// [1]: https://w3.org/TR/webrtc/#dom-rtcdatachannel-id
    pub data_channel_identifier: Option<u64>,

    /// [Stats object reference][1] for the transport used to carry
    /// [RTCDataChannel].
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    /// [1]: https://w3.org/TR/webrtc-stats/#dfn-stats-object-reference
    pub transport_id: Option<String>,

    /// [`readyState`][1] value of the [RTCDataChannel] object.
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    /// [1]: https://w3.org/TR/webrtc/#dom-datachannel-readystate
    pub state: Option<DataChannelState>,

    /// Total number of API `message` events sent.
    pub messages_sent: Option<u64>,

    /// Total number of payload bytes sent on this [RTCDataChannel], i.e. not
    /// including headers or padding.
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    pub bytes_sent: Option<u64>,

    /// Total number of API `message` events received.
    pub messages_received: Option<u64>,

    /// Total number of bytes received on this [RTCDataChannel], i.e. not
    /// including headers or padding.
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    pub bytes_received: Option<u64>,
}

/// Non-exhaustive version of [`KnownDataChannelState`].
pub type DataChannelState = NonExhaustive<KnownDataChannelState>;

/// State of the [RTCDataChannel]'s underlying data connection.
///
/// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum KnownDataChannelState {
    /// User agent is attempting to establish the underlying data transport.
    /// This is the initial state of [RTCDataChannel] object, whether created
    /// with [createDataChannel][1], or dispatched as a part of an
    /// [RTCDataChannelEvent].
    ///
    /// [RTCDataChannel]: https://w3.org/TR/webrtc/#dom-rtcdatachannel
    /// [RTCDataChannelEvent]: https://w3.org/TR/webrtc/#dom-rtcdatachannelevent
    /// [1]: https://w3.org/TR/webrtc/#dom-peerconnection-createdatachannel
    Connecting,

    /// [Underlying data transport][1] is established and communication is
    /// possible.
    ///
    /// [1]: https://w3.org/TR/webrtc/#dfn-data-transport
    Open,

    /// [`procedure`][2] to close down the [underlying data transport][1] has
    /// started.
    ///
    /// [1]: https://w3.org/TR/webrtc/#dfn-data-transport
    /// [2]: https://w3.org/TR/webrtc/#data-transport-closing-procedure
    Closing,

    /// [Underlying data transport][1] has been [`closed`][2] or could not be
    /// established.
    ///
    /// [1]: https://w3.org/TR/webrtc/#dfn-data-transport
    /// [2]: https://w3.org/TR/webrtc/#dom-rtcdatachannelstate-closed
    Closed,
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// Stats for the [RTCPeerConnection] object.
///
/// [`RtcStatsType::PeerConnection`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
/// [1]: https://w3.org/TR/webrtc-stats/#pcstats-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcPeerConnectionStats {
    /// Number of unique `DataChannel`s that have entered the `open` state
    /// during their lifetime.
    pub data_channels_opened: Option<u64>,

    /// Number of unique `DataChannel`s that have left the `open` state during
    /// their lifetime (due to being closed by either end or the underlying
    /// transport being closed). `DataChannel`s that transition from
    /// `connecting` to `closing` or `closed` without ever being `open` are not
    /// counted in this number.
    pub data_channels_closed: Option<u64>,

    /// Number of unique `DataChannel`s returned from a successful
    /// [createDataChannel][1] call on the [RTCPeerConnection].
    /// If the underlying data transport is not established, these may be in
    /// the `connecting` state.
    ///
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    /// [1]: https://w3.org/TR/webrtc/#dom-peerconnection-createdatachannel
    pub data_channels_requested: Option<u64>,

    /// Number of unique `DataChannel`s signaled in a `datachannel` event on
    /// the [RTCPeerConnection].
    ///
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    pub data_channels_accepted: Option<u64>,
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// Statistics for a contributing source (CSRC) that contributed to an inbound
/// [RTP] stream.
///
/// [`RtcStatsType::Csrc`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
/// [1]: https://w3.org/TR/webrtc-stats/#contributingsourcestats-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtpContributingSourceStats {
    /// SSRC identifier of the contributing source represented by the stats
    /// object, as defined by [RFC 3550]. It is a 32-bit unsigned integer that
    /// appears in the CSRC list of any packets the relevant source contributed
    /// to.
    ///
    /// [RFC 3550]: https://tools.ietf.org/html/rfc3550
    pub contributor_ssrc: Option<u32>,

    /// ID of the [RTCInboundRtpStreamStats][1] object representing the inbound
    /// [RTP] stream that this contributing source is contributing to.
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats
    pub inbound_rtp_stream_id: Option<String>,

    /// Total number of [RTP] packets that this contributing source contributed
    /// to.
    ///
    /// This value is incremented each time a packet is counted by
    /// [RTCInboundRtpStreamStats.packetsReceived][2], and the packet's CSRC
    /// list (as defined by [Section 5.1 in RFC 3550][3]) contains the SSRC
    /// identifier of this contributing source, [`contributorSsrc`].
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [`contributorSsrc`]: https://tinyurl.com/tf8c7j4
    /// [2]: https://tinyurl.com/rreuf49
    /// [3]: https://tools.ietf.org/html/rfc3550#section-5.1
    pub packets_contributed_to: Option<u64>,

    /// Present if the last received RTP packet that this source contributed to
    /// contained an [RFC 6465] mixer-to-client audio level header extension.
    ///
    /// The value of [`audioLevel`] is between `0..1` (linear), where `1.0`
    /// represents `0 dBov`, `0` represents silence, and `0.5` represents
    /// approximately `6 dBSPL` change in the sound pressure level from 0
    /// dBov. The [RFC 6465] header extension contains values in the range
    /// `0..127`, in units of `-dBov`, where `127` represents silence. To
    /// convert these values to the linear `0..1` range of `audioLevel`, a
    /// value of `127` is converted to `0`, and all other values are
    /// converted using the equation:
    ///
    /// `f(rfc6465_level) = 10^(-rfc6465_level/20)`
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [RFC 6465]: https://tools.ietf.org/html/rfc6465
    /// [`audioLevel`]: https://tinyurl.com/sfy699q
    pub audio_level: Option<Float>,
}

/// Statistics for the remote endpoint's outbound [RTP] stream corresponding
/// to an inbound stream that is currently received with [RTCPeerConnection]
/// object.
///
/// It is measured at the remote endpoint and reported in an RTCP Sender Report
/// (SR).
///
/// [`RtcStatsType::RemoteOutboundRtp`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
/// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
/// [1]: https://w3.org/TR/webrtc-stats/#remoteoutboundrtpstats-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcRemoteOutboundRtpStreamStats {
    /// [`localId`] is used for looking up the local
    /// [RTCInboundRtpStreamStats][1] object for the same SSRC.
    ///
    /// [`localId`]: https://tinyurl.com/vu9tb2e
    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats
    pub local_id: Option<String>,

    /// [`remoteTimestamp`] (as [HIGHRES-TIME]) is the remote timestamp at
    /// which these statistics were sent by the remote endpoint. This
    /// differs from timestamp, which represents the time at which the
    /// statistics were generated or received by the local endpoint. The
    /// [`remoteTimestamp`], if present, is derived from the NTP timestamp
    /// in an RTCP Sender Report (SR) block, which reflects the remote
    /// endpoint's clock. That clock may not be synchronized with the local
    /// clock.
    ///
    /// [`remoteTimestamp`]: https://tinyurl.com/rzlhs87
    /// [HIGRES-TIME]: https://w3.org/TR/webrtc-stats/#bib-highres-time
    pub remote_timestamp: Option<HighResTimeStamp>,

    /// Total number of RTCP SR blocks sent for this SSRC.
    pub reports_sent: Option<u64>,
}

/// Statistics for the remote endpoint's inbound [RTP] stream corresponding
/// to an outbound stream that is currently sent with [RTCPeerConnection]
/// object.
///
/// It is measured at the remote endpoint and reported in a RTCP Receiver
/// Report (RR) or RTCP Extended Report (XR).
///
/// [`RtcStatsType::RemoteInboundRtp`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
/// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcRemoteInboundRtpStreamStats {
    /// [`localId`] is used for looking up the local
    /// [RTCOutboundRtpStreamStats] object for the same SSRC.
    ///
    /// [`localId`]: https://tinyurl.com/r8uhbo9
    /// [RTCOutBoundRtpStreamStats]: https://tinyurl.com/r6f5vqg
    pub local_id: Option<String>,

    /// Packet [jitter] measured in seconds for this SSRC.
    ///
    /// [jitter]: https://en.wikipedia.org/wiki/Jitter
    pub jitter: Option<Float>,

    /// Estimated round trip time for this SSRC based on the RTCP timestamps in
    /// the RTCP Receiver Report (RR) and measured in seconds. Calculated as
    /// defined in [Section 6.4.1 of RFC 3550][1]. If no RTCP Receiver Report
    /// is received with a DLSR value other than 0, the round trip time is
    /// left undefined.
    ///
    /// [1]: https://tools.ietf.org/html/rfc3550#section-6.4.1
    pub round_trip_time: Option<Float>,

    /// Fraction packet loss reported for this SSRC. Calculated as defined in
    /// [Section 6.4.1 of RFC 3550][1] and [Appendix A.3][2].
    ///
    /// [1]: https://tools.ietf.org/html/rfc3550#section-6.4.1
    /// [2]: https://tools.ietf.org/html/rfc3550#appendix-A.3
    pub fraction_lost: Option<Float>,

    /// Total number of RTCP RR blocks received for this SSRC.
    pub reports_received: Option<u64>,

    /// Total number of RTCP RR blocks received for this SSRC that contain a
    /// valid round trip time. This counter will increment if the
    /// [`roundTripTime`] is undefined.
    ///
    /// [`roundTripTime`]: https://tinyurl.com/ssg83hq
    pub round_trip_time_measurements: Option<Float>,
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// [RTCRtpTransceiverStats][1] object representing an [RTCRtpTransceiver] of an
/// [RTCPeerConnection].
///
/// It appears as soon as the monitored [RTCRtpTransceiver] object is created,
/// such as by invoking [addTransceiver][2], [addTrack][3] or
/// [setRemoteDescription][4]. [RTCRtpTransceiverStats][1] objects can only be
/// deleted if the corresponding [RTCRtpTransceiver] is removed (this can only
/// happen if a remote description is rolled back).
///
/// [`RtcStatsType::Transceiver`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
/// [RTCRtpTransceiver]: https://w3.org/TR/webrtc/#dom-rtcrtptransceiver
/// [1]: https://w3.org/TR/webrtc-stats/#transceiver-dict%2A
/// [2]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection-addtransceiver
/// [3]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection-addtrack
/// [4]: https://tinyurl.com/vejym8v
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcRtpTransceiverStats {
    /// ID of the stats object representing the
    /// [RTCRtpSender associated with the RTCRtpTransceiver][1] represented by
    /// this stats object.
    ///
    /// [1]: https://w3.org/TR/webrtc/#dom-rtcrtptransceiver-sender
    pub sender_id: Option<String>,

    /// ID of the stats object representing the
    /// [RTCRtpReceiver associated with the RTCRtpTransceiver][1] represented
    /// by this stats object.
    ///
    /// [1]: https://w3.org/TR/webrtc/#dom-rtcrtptransceiver-receiver
    pub receiver_id: Option<String>,

    /// If the [RTCRtpTransceiver] that this stats object represents has a
    /// [`mid` value][1] that is not null, this is that value, otherwise this
    /// value is undefined.
    ///
    /// [RTCRtpTransceiver]: https://w3.org/TR/webrtc/#dom-rtcrtptransceiver
    /// [1]: https://w3.org/TR/webrtc/#dom-rtptransceiver-mid
    pub mid: Option<String>,
}

/// Representation of the stats corresponding to an [RTCSctpTransport].
///
/// [`RtcStatsType::SctpTransport`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCSctpTransport]: https://w3.org/TR/webrtc/#dom-rtcsctptransport
/// [1]: https://w3.org/TR/webrtc-stats/#sctptransportstats-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcSctpTransportStats {
    /// Latest smoothed round-trip time value, corresponding to
    /// [`spinfo_srtt` defined in RFC 6458][1] but converted to seconds.
    ///
    /// If there has been no round-trip time measurements yet, this value is
    /// undefined.
    ///
    /// [1]: https://tools.ietf.org/html/rfc6458#page-83
    pub smoothed_round_trip_time: Option<HighResTimeStamp>,
}

/// Representation of the stats corresponding to an [RTCDtlsTransport] and its
/// underlying [RTCIceTransport].
///
/// When RTCP multiplexing is used, one transport is used for both RTP and RTCP.
/// Otherwise, RTP and RTCP will be sent on separate transports, and
/// `rtcpTransportStatsId` can be used to pair the resulting
/// [`RtcTransportStats`] objects. Additionally, when bundling is used, a single
/// transport will be used for all [MediaStreamTrack][2]s in the bundle group.
/// If bundling is not used, different [MediaStreamTrack][2]s will use different
/// transports. RTCP multiplexing and bundling are described in [WebRTC].
///
/// [`RtcStatsType::Transport`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCDtlsTransport]: https://w3.org/TR/webrtc/#dom-rtcdtlstransport
/// [RTCIceTransport]: https://w3.org/TR/webrtc/#dom-rtcicetransport
/// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
/// [WebRTC]: https://w3.org/TR/webrtc
/// [1]: https://w3.org/TR/webrtc-stats/#transportstats-dict%2A
/// [2]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
#[serde_with::skip_serializing_none]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcTransportStats {
    /// Total number of packets sent over this transport.
    pub packets_sent: Option<u64>,

    /// Total number of packets received on this transport.
    pub packets_received: Option<u64>,

    /// Total number of payload bytes sent on this [RTCPeerConnection], i.e.
    /// not including headers or padding.
    ///
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    pub bytes_sent: Option<u64>,

    /// Total number of bytes received on this [RTCPeerConnection], i.e. not
    /// including headers or padding.
    ///
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    pub bytes_received: Option<u64>,

    /// Set to the current value of the [`role` attribute][1] of the
    /// [underlying RTCDtlsTransport's `transport`][2].
    ///
    /// [1]: https://w3.org/TR/webrtc/#dom-icetransport-role
    /// [2]: https://w3.org/TR/webrtc/#dom-rtcdtlstransport-icetransport
    pub ice_role: Option<IceRole>,
}

/// Variants of [ICE roles][1].
///
/// More info in the [RFC 5245].
///
/// [RFC 5245]: https://tools.ietf.org/html/rfc5245
/// [1]: https://w3.org/TR/webrtc/#dom-icetransport-role
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum IceRole {
    /// Agent whose role as defined by [Section 3 in RFC 5245][1], has not yet
    /// been determined.
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-3
    Unknown,

    /// Controlling agent as defined by [Section 3 in RFC 5245][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-3
    Controlling,

    /// Controlled agent as defined by [Section 3 in RFC 5245][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-3
    Controlled,
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// Statistics related to a specific [RTCRtpSender] and the corresponding
/// media-level metrics.
///
/// [`RtcStatsType::Sender`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCRtpSender]: https://w3.org/TR/webrtc/#rtcrtpsender-interface
/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcstatstype-sender
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum SenderStatsKind {
    /// [RTCAudioSenderStats][1] object.
    ///
    /// [1]: https://tinyurl.com/w5ow5xs
    Audio { media_source_id: Option<String> },

    /// [RTCVideoSenderStats][1] object.
    ///
    /// [1]: https://tinyurl.com/ry39vnw
    Video { media_source_id: Option<String> },
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// Statistics related to a specific [RTCRtpReceiver] and the corresponding
/// media-level metrics.
///
/// [`RtcStatsType::Receiver`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCRtpReceiver]: https://w3.org/TR/webrtc/#dom-rtcrtpreceiver
/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcstatstype-receiver
#[serde_with::skip_serializing_none]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum ReceiverStatsKind {
    /// [RTCAudioReceiverStats] object.
    ///
    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcaudioreceiverstats
    Audio {},

    /// [RTCVideoReceiverStats] object.
    ///
    /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcvideoreceiverstats
    Video {},
}

/// ICE candidate pair statistics related to the [RTCIceTransport] objects.
///
/// A candidate pair that is not the current pair for a transport is
/// [deleted][1] when the [RTCIceTransport] does an ICE restart, at the time
/// the state changes to `new`.
///
/// The candidate pair that is the current pair for a transport is deleted after
/// an ICE restart when the [RTCIceTransport] switches to using a candidate pair
/// generated from the new candidates; this time doesn't correspond to any other
/// externally observable event.
///
/// [`RtcStatsType::CandidatePair`] variant.
///
/// [Full doc on W3C][2].
///
/// [RTCIceTransport]: https://w3.org/TR/webrtc/#dom-rtcicetransport
/// [1]: https://w3.org/TR/webrtc-stats/#dfn-deleted
/// [2]: https://w3.org/TR/webrtc-stats/#candidatepair-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcIceCandidatePairStats {
    /// State of the checklist for the local and remote candidates in a pair.
    pub state: IceCandidatePairState,

    /// Related to updating the nominated flag described in
    /// [Section 7.1.3.2.4 of RFC 5245][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-7.1.3.2.4
    pub nominated: bool,

    /// Total number of payload bytes sent on this candidate pair, i.e. not
    /// including headers or padding.
    pub bytes_sent: u64,

    /// Total number of payload bytes received on this candidate pair, i.e. not
    /// including headers or padding.
    pub bytes_received: u64,

    /// Sum of all round trip time measurements in seconds since the beginning
    /// of the session, based on STUN connectivity check [STUN-PATH-CHAR]
    /// responses (responsesReceived), including those that reply to requests
    /// that are sent in order to verify consent [RFC 7675].
    ///
    /// The average round trip time can be computed from
    /// [`totalRoundTripTime`][1] by dividing it by [`responsesReceived`][2].
    ///
    /// [STUN-PATH-CHAR]: https://w3.org/TR/webrtc-stats/#bib-stun-path-char
    /// [RFC 7675]: https://tools.ietf.org/html/rfc7675
    /// [1]: https://tinyurl.com/tgr543a
    /// [2]: https://tinyurl.com/r3zo2um
    pub total_round_trip_time: Option<HighResTimeStamp>,

    /// Latest round trip time measured in seconds, computed from both STUN
    /// connectivity checks [STUN-PATH-CHAR], including those that are sent for
    /// consent verification [RFC 7675].
    ///
    /// [STUN-PATH-CHAR]: https://w3.org/TR/webrtc-stats/#bib-stun-path-char
    /// [RFC 7675]: https://tools.ietf.org/html/rfc7675
    pub current_round_trip_time: Option<HighResTimeStamp>,

    /// Calculated by the underlying congestion control by combining the
    /// available bitrate for all the outgoing RTP streams using this candidate
    /// pair. The bitrate measurement does not count the size of the IP or
    /// other transport layers like TCP or UDP. It is similar to the TIAS
    /// defined in [RFC 3890], i.e. it is measured in bits per second and the
    /// bitrate is calculated over a 1 second window.
    ///
    /// Implementations that do not calculate a sender-side estimate MUST leave
    /// this undefined. Additionally, the value MUST be undefined for candidate
    /// pairs that were never used. For pairs in use, the estimate is normally
    /// no lower than the bitrate for the packets sent at
    /// [`lastPacketSentTimestamp`][1], but might be higher. For candidate
    /// pairs that are not currently in use but were used before,
    /// implementations MUST return undefined.
    ///
    /// [RFC 3890]: https://tools.ietf.org/html/rfc3890
    /// [1]: https://tinyurl.com/rfc72eh
    pub available_outgoing_bitrate: Option<u64>,
}

/// Each candidate pair in the check list has a foundation and a state.
/// The foundation is the combination of the foundations of the local and
/// remote candidates in the pair.  The state is assigned once the check
/// list for each media stream has been computed.  There are five
/// potential values that the state can have.
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum KnownIceCandidatePairState {
    /// Check has not been performed for this pair, and can be performed as
    /// soon as it is the highest-priority Waiting pair on the check list.
    Waiting,

    /// Check has been sent for this pair, but the transaction is in progress.
    InProgress,

    /// Check for this pair was already done and produced a successful result.
    Succeeded,

    /// Check for this pair was already done and failed, either never producing
    /// any response or producing an unrecoverable failure response.
    Failed,

    /// Check for this pair hasn't been performed, and it can't yet be
    /// performed until some other check succeeds, allowing this pair to
    /// unfreeze and move into the [`KnownIceCandidatePairState::Waiting`]
    /// state.
    Frozen,

    /// Other Candidate pair was nominated.
    ///
    /// This state is **obsolete and not spec compliant**, however, it still
    /// may be emitted by some implementations.
    Cancelled,
}

/// Non-exhaustive version of [`KnownIceCandidatePairState`].
pub type IceCandidatePairState = NonExhaustive<KnownIceCandidatePairState>;

/// Known protocols used in the WebRTC.
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum KnownProtocol {
    /// [User Datagram Protocol][1].
    ///
    /// [1]: https://en.wikipedia.org/wiki/User_Datagram_Protocol
    Udp,

    /// [Transmission Control Protocol][1].
    ///
    /// [1]: https://en.wikipedia.org/wiki/Transmission_Control_Protocol
    Tcp,
}

/// Non-exhaustive version of [`KnownProtocol`].
pub type Protocol = NonExhaustive<KnownProtocol>;

/// [RTCIceCandidateType] represents the type of the ICE candidate, as
/// defined in [Section 15.1 of RFC 5245][1].
///
/// [RTCIceCandidateType]: https://w3.org/TR/webrtc/#rtcicecandidatetype-enum
/// [1]: https://tools.ietf.org/html/rfc5245#section-15.1
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum KnownCandidateType {
    /// Host candidate, as defined in [Section 4.1.1.1 of RFC 5245][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-4.1.1.1
    Host,

    /// Server reflexive candidate, as defined in
    /// [Section 4.1.1.2 of RFC 5245][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-4.1.1.2
    Srlfx,

    /// Peer reflexive candidate, as defined in
    /// [Section 4.1.1.2 of RFC 5245][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-4.1.1.2
    Prflx,

    /// Relay candidate, as defined in [Section 7.1.3.2.1 of RFC 5245][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-7.1.3.2.1
    Relay,
}

/// Non-exhaustive version of [`KnownCandidateType`].
pub type CandidateType = NonExhaustive<KnownCandidateType>;

/// Fields of [`RtcStatsType::InboundRtp`] variant.
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(tag = "mediaType", rename_all = "camelCase")]
pub enum RtcInboundRtpStreamMediaType {
    /// Fields when `mediaType` is `audio`.
    Audio {
        /// Indicator whether the last RTP packet whose frame was delivered to
        /// the [RTCRtpReceiver]'s [MediaStreamTrack][1] for playout contained
        /// voice activity or not based on the presence of the V bit in the
        /// extension header, as defined in [RFC 6464].
        ///
        /// [RTCRtpReceiver]: https://w3.org/TR/webrtc/#rtcrtpreceiver-interface
        /// [RFC 6464]: https://tools.ietf.org/html/rfc6464#page-3
        /// [1]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
        voice_activity_flag: Option<bool>,

        /// Total number of samples that have been received on this RTP stream.
        /// This includes [`concealedSamples`].
        ///
        /// [`concealedSamples`]: https://tinyurl.com/s6c4qe4
        total_samples_received: Option<u64>,

        /// Total number of samples that are concealed samples.
        ///
        /// A concealed sample is a sample that was replaced with synthesized
        /// samples generated locally before being played out.
        /// Examples of samples that have to be concealed are samples from lost
        /// packets (reported in [`packetsLost`]) or samples from packets that
        /// arrive too late to be played out (reported in
        /// [`packetsDiscarded`]).
        ///
        /// [`packetsLost`]: https://tinyurl.com/u2gq965
        /// [`packetsDiscarded`]: https://tinyurl.com/yx7qyox3
        concealed_samples: Option<u64>,

        /// Total number of concealed samples inserted that are "silent".
        ///
        /// Playing out silent samples results in silence or comfort noise.
        /// This is a subset of [`concealedSamples`].
        ///
        /// [`concealedSamples`]: https://tinyurl.com/s6c4qe4
        silent_concealed_samples: Option<u64>,

        /// Audio level of the receiving track.
        audio_level: Option<Float>,

        /// Audio energy of the receiving track.
        total_audio_energy: Option<Float>,

        /// Audio duration of the receiving track.
        ///
        /// For audio durations of tracks attached locally, see
        /// [RTCAudioSourceStats][1] instead.
        ///
        /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcaudiosourcestats
        total_samples_duration: Option<HighResTimeStamp>,
    },

    /// Fields when `mediaType` is `video`.
    Video {
        /// Total number of frames correctly decoded for this RTP stream, i.e.
        /// frames that would be displayed if no frames are dropped.
        frames_decoded: Option<u64>,

        /// Total number of key frames, such as key frames in VP8 [RFC 6386] or
        /// IDR-frames in H.264 [RFC 6184], successfully decoded for this RTP
        /// media stream.
        ///
        /// This is a subset of [`framesDecoded`].
        /// [`framesDecoded`] - [`keyFramesDecoded`] gives you the number of
        /// delta frames decoded.
        ///
        /// [RFC 6386]: https://w3.org/TR/webrtc-stats/#bib-rfc6386
        /// [RFC 6184]: https://w3.org/TR/webrtc-stats/#bib-rfc6184
        /// [`framesDecoded`]: https://tinyurl.com/srfwrwt
        /// [`keyFramesDecoded`]: https://tinyurl.com/qtdmhtm
        key_frames_decoded: Option<u64>,

        /// Width of the last decoded frame.
        ///
        /// Before the first frame is decoded this attribute is missing.
        frame_width: Option<u64>,

        /// Height of the last decoded frame.
        ///
        /// Before the first frame is decoded this attribute is missing.
        frame_height: Option<u64>,

        /// Sum of the interframe delays in seconds between consecutively
        /// decoded frames, recorded just after a frame has been decoded.
        total_inter_frame_delay: Option<Float>,

        /// Number of decoded frames in the last second.
        frames_per_second: Option<u64>,

        /// Bit depth per pixel of the last decoded frame.
        ///
        /// Typical values are 24, 30, or 36 bits. Before the first frame is
        /// decoded this attribute is missing.
        frame_bit_depth: Option<u64>,

        /// Total number of Full Intra Request (FIR) packets sent by this
        /// receiver.
        fir_count: Option<u64>,

        /// Total number of Picture Loss Indication (PLI) packets sent by this
        /// receiver.
        pli_count: Option<u64>,

        /// Total number of Slice Loss Indication (SLI) packets sent by this
        /// receiver.
        sli_count: Option<u64>,

        /// Number of concealment events.
        ///
        /// This counter increases every time a concealed sample is synthesized
        /// after a non-concealed sample. That is, multiple consecutive
        /// concealed samples will increase the [`concealedSamples`] count
        /// multiple times but is a single concealment event.
        ///
        /// [`concealedSamples`]: https://tinyurl.com/s6c4qe4
        concealment_events: Option<u64>,

        /// Total number of complete frames received on this RTP stream.
        ///
        /// This metric is incremented when the complete frame is received.
        frames_received: Option<u64>,
    },
}

/// Representation of the measurement metrics for the incoming [RTP] media
/// stream. The timestamp reported in the statistics object is the time at which
/// the data was sampled.
///
/// [`RtcStatsType::InboundRtp`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcInboundRtpStreamStats {
    /// ID of the stats object representing the receiving track.
    pub track_id: Option<String>,

    /// Fields which should be in the [`RtcStat`] based on `mediaType`.
    #[serde(flatten)]
    pub media_specific_stats: RtcInboundRtpStreamMediaType,

    /// Total number of bytes received for this SSRC.
    pub bytes_received: u64,

    /// Total number of RTP data packets received for this SSRC.
    pub packets_received: u64,

    /// Total number of RTP data packets for this SSRC that have been lost
    /// since the beginning of reception.
    ///
    /// This number is defined to be the number of packets expected less the
    /// number of packets actually received, where the number of packets
    /// received includes any which are late or duplicates. Thus, packets that
    /// arrive late are not counted as lost, and the loss __may be negative__
    /// if there are duplicates.
    pub packets_lost: Option<i64>,

    /// Packet jitter measured in seconds for this SSRC.
    pub jitter: Option<Float>,

    /// Total number of seconds that have been spent decoding the
    /// [`framesDecoded`] frames of this stream.
    ///
    /// The average decode time can be calculated by dividing this value with
    /// [`framesDecoded`]. The time it takes to decode one frame is the time
    /// passed between feeding the decoder a frame and the decoder returning
    /// decoded data for that frame.
    ///
    /// [`framesDecoded`]: https://tinyurl.com/srfwrwt
    pub total_decode_time: Option<HighResTimeStamp>,

    /// Total number of audio samples or video frames that have come out of the
    /// jitter buffer (increasing [`jitterBufferDelay`]).
    ///
    /// [`jitterBufferDelay`]: https://tinyurl.com/qvoojt5
    pub jitter_buffer_emitted_count: Option<u64>,
}

/// Statistics related to a specific [MediaStreamTrack][1]'s attachment to an
/// [RTCRtpSender] and the corresponding media-level metrics.
///
/// [`RtcStatsType::Track`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCRtpSender]: https://w3.org/TR/webrtc/#rtcrtpsender-interface
/// [1]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
/// [2]: https://w3.org/TR/webrtc-stats/#dom-rtcstatstype-track
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TrackStats {
    /// [`id` property][1] of the track.
    ///
    /// [1]: https://w3.org/TR/mediacapture-streams/#dom-mediastreamtrack-id
    pub track_identifier: String,

    /// `true` if the source is remote, for instance if it is sourced from
    /// another host via an [RTCPeerConnection]. `false` otherwise.
    ///
    /// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
    pub remote_source: Option<bool>,

    /// Reflection of the "ended" state of the track.
    pub ended: Option<bool>,

    /// Either `audio` or `video`.
    ///
    /// This reflects the [`kind` attribute][2] of the [MediaStreamTrack][1].
    ///
    /// [1]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
    /// [2]: https://w3.org/TR/mediacapture-streams/#dom-mediastreamtrack-kind
    pub kind: Option<TrackStatsKind>,
}

/// [`kind` attribute] values of the [MediaStreamTrack][1].
///
/// [1]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
/// [2]: https://w3.org/TR/mediacapture-streams/#dom-mediastreamtrack-kind
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum TrackStatsKind {
    /// Track is used for the audio content.
    Audio,

    /// Track is used for the video content.
    Video,
}

/// [`RtcStat`] fields of [`RtcStatsType::OutboundRtp`] type based on
/// `mediaType`.
#[serde_with::skip_serializing_none]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(tag = "mediaType", rename_all = "camelCase")]
pub enum RtcOutboundRtpStreamMediaType {
    /// Fields when `mediaType` is `audio`.
    Audio {
        /// Total number of samples that have been sent over this RTP stream.
        total_samples_sent: Option<u64>,

        /// Whether the last RTP packet sent contained voice activity or not
        /// based on the presence of the V bit in the extension header.
        voice_activity_flag: Option<bool>,
    },

    /// Fields when `mediaType` is `video`.
    Video {
        /// Width of the last encoded frame.
        ///
        /// The resolution of the encoded frame may be lower than the media
        /// source (see [RTCVideoSourceStats.width][1]).
        ///
        /// Before the first frame is encoded this attribute is missing.
        ///
        /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcvideosourcestats-width
        frame_width: Option<u64>,

        /// Height of the last encoded frame.
        ///
        /// The resolution of the encoded frame may be lower than the media
        /// source (see [RTCVideoSourceStats.height][1]).
        ///
        /// Before the first frame is encoded this attribute is missing.
        ///
        /// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcvideosourcestats-height
        frame_height: Option<u64>,

        /// Number of encoded frames during the last second.
        ///
        /// This may be lower than the media source frame rate (see
        /// [RTCVideoSourceStats.framesPerSecond][1]).
        ///
        /// [1]: https://tinyurl.com/rrmkrfk
        frames_per_second: Option<u64>,
    },
}

/// Statistics for an outbound [RTP] stream that is currently sent with this
/// [RTCPeerConnection] object.
///
/// When there are multiple [RTP] streams connected to the same sender, such
/// as when using simulcast or RTX, there will be one
/// [`RtcOutboundRtpStreamStats`] per RTP stream, with distinct values of
/// the `ssrc` attribute, and all these senders will have a reference to
/// the same "sender" object (of type [RTCAudioSenderStats][1] or
/// [RTCVideoSenderStats][2]) and "track" object (of type
/// [RTCSenderAudioTrackAttachmentStats][3] or
/// [RTCSenderVideoTrackAttachmentStats][4]).
///
/// [`RtcStatsType::OutboundRtp`] variant.
///
/// [Full doc on W3C][5].
///
/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
/// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtcaudiosenderstats
/// [2]: https://w3.org/TR/webrtc-stats/#dom-rtcvideosenderstats
/// [3]: https://tinyurl.com/sefa5z4
/// [4]: https://tinyurl.com/rkuvpl4
/// [5]: https://w3.org/TR/webrtc-stats/#outboundrtpstats-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcOutboundRtpStreamStats {
    /// ID of the stats object representing the current track attachment to the
    /// sender of this stream.
    pub track_id: Option<String>,

    /// Fields which should be in the [`RtcStat`] based on `mediaType`.
    #[serde(flatten)]
    pub media_type: RtcOutboundRtpStreamMediaType,

    /// Total number of bytes sent for this SSRC.
    pub bytes_sent: u64,

    /// Total number of RTP packets sent for this SSRC.
    pub packets_sent: u64,

    /// ID of the stats object representing the track currently
    /// attached to the sender of this stream.
    pub media_source_id: Option<String>,
}

/// Properties of a `candidate` in [Section 15.1 of RFC 5245][1].
/// It corresponds to a [RTCIceTransport] object.
///
/// [`RtcStatsType::LocalCandidate`] or [`RtcStatsType::RemoteCandidate`]
/// variant.
///
/// [Full doc on W3C][2].
///
/// [RTCIceTransport]: https://w3.org/TR/webrtc/#dom-rtcicetransport
/// [1]: https://tools.ietf.org/html/rfc5245#section-15.1
/// [2]: https://w3.org/TR/webrtc-stats/#icecandidate-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcIceCandidateStats {
    /// Unique ID that is associated to the object that was inspected to
    /// produce the [RTCTransportStats][1] associated with this candidate.
    ///
    /// [1]: https://w3.org/TR/webrtc-stats/#transportstats-dict%2A
    pub transport_id: Option<String>,

    /// Address of the candidate, allowing for IPv4 addresses, IPv6 addresses,
    /// and fully qualified domain names (FQDNs).
    pub address: Option<String>,

    /// Port number of the candidate.
    pub port: u16,

    /// Valid values for transport is one of `udp` and `tcp`.
    pub protocol: Protocol,

    /// Type of the ICE candidate.
    pub candidate_type: CandidateType,

    /// Calculated as defined in [Section 15.1 of RFC 5245][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc5245#section-15.1
    pub priority: u32,

    /// For local candidates this is the URL of the ICE server from which the
    /// candidate was obtained. It is the same as the
    /// [url surfaced in the RTCPeerConnectionIceEvent][1].
    ///
    /// `None` for remote candidates.
    ///
    /// [1]: https://w3.org/TR/webrtc/#rtcpeerconnectioniceevent
    pub url: Option<String>,

    /// Protocol used by the endpoint to communicate with the TURN server.
    ///
    /// Only present for local candidates.
    pub relay_protocol: Option<Protocol>,
}

/// [`RtcStat`] fields of [`RtcStatsType::MediaSource`] type based on its
/// `kind`.
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum MediaKind {
    /// Fields when `kind` is `video`.
    Video {
        /// Width (in pixels) of the last frame originating from the source.
        /// Before a frame has been produced this attribute is missing.
        width: Option<u32>,

        /// Height (in pixels) of the last frame originating from the source.
        /// Before a frame has been produced this attribute is missing.
        height: Option<u32>,

        /// Number of frames originating from the source, measured during the
        /// last second. For the first second of this object's lifetime this
        /// attribute is missing.
        frames_per_second: Option<u32>,
    },

    /// Fields when `kind` is `audio`.
    Audio {
        /// Audio level of the media source.
        audio_level: Option<Float>,

        /// Audio energy of the media source.
        total_audio_energy: Option<Float>,

        /// Audio duration of the media source.
        total_samples_duration: Option<Float>,
    },
}

/// Statistics for the media produced by a [MediaStreamTrack][1] that is
/// currently attached to an [RTCRtpSender]. This reflects the media that is fed
/// to the encoder after [getUserMedia] constraints have been applied (i.e. not
/// the raw media produced by the camera).
///
/// [`RtcStatsType::MediaSource`] variant.
///
/// [Full doc on W3C][2].
///
/// [RTCRtpSender]: https://w3.org/TR/webrtc/#rtcrtpsender-interface
/// [getUserMedia]: https://tinyurl.com/sngpyr6
/// [1]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
/// [2]: https://w3.org/TR/webrtc-stats/#dom-rtcstatstype-media-source
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MediaSourceStats {
    /// Value of the [MediaStreamTrack][1]'s ID attribute.
    ///
    /// [1]: https://w3.org/TR/mediacapture-streams/#mediastreamtrack
    pub track_identifier: Option<String>,

    /// Fields which should be in the [`RtcStat`] based on `kind`.
    #[serde(flatten)]
    pub kind: MediaKind,
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// Statistics for a codec that is currently used by [RTP] streams being sent or
/// received by [RTCPeerConnection] object.
///
/// [`RtcStatsType::Codec`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
/// [RTCPeerConnection]: https://w3.org/TR/webrtc/#dom-rtcpeerconnection
/// [1]: https://w3.org/TR/webrtc-stats/#dom-rtccodecstats
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcCodecStats {
    /// [Payload type][1] as used in [RTP] encoding or decoding.
    ///
    /// [RTP]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
    /// [1]: https://tools.ietf.org/html/rfc3550#page-14
    pub payload_type: u32,

    /// The codec MIME media `type/subtype` (e.g. `video/vp8` or equivalent).
    pub mime_type: String,

    /// Media sampling rate.
    pub clock_rate: u32,
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// Information about a certificate used by [RTCIceTransport].
///
/// [`RtcStatsType::Certificate`] variant.
///
/// [Full doc on W3C][1].
///
/// [RTCIceTransport]: https://w3.org/TR/webrtc/#dom-rtcicetransport
/// [1]: https://w3.org/TR/webrtc-stats/#certificatestats-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcCertificateStats {
    /// Fingerprint of the certificate.
    ///
    /// Only use the fingerprint value as defined in [Section 5 of RFC
    /// 4572][1].
    ///
    /// [1]: https://tools.ietf.org/html/rfc4572#section-5
    pub fingerprint: String,

    /// Hash function used to compute the certificate fingerprint.
    /// For instance, `sha-256`.
    pub fingerprint_algorithm: String,

    /// The DER-encoded Base64 representation of the certificate.
    pub base64_certificate: String,
}

/// Representation of [DOMHighResTimeStamp][1].
///
/// Can be converted to the [`SystemTime`] with millisecond-wise accuracy.
///
/// [`HighResTimeStamp`] type is a [`f64`] and is used to store a time value
/// in milliseconds. This type can be used to describe a discrete point in time
/// or a time interval (the difference in time between two discrete points in
/// time).
///
/// The time, given in milliseconds, should be accurate to 5 µs (microseconds),
/// with the fractional part of the number indicating fractions of a
/// millisecond. However, if the browser is unable to provide a time value
/// accurate to 5 µs (due, for example, to hardware or software constraints),
/// the browser can represent the value as a time in milliseconds accurate to a
/// millisecond. Also note the section below on reduced time precision
/// controlled by browser preferences to avoid timing attacks and
/// fingerprinting.
///
/// Further, if the device or operating system the user agent is running on
/// doesn't have a clock accurate to the microsecond level, they may only be
/// accurate to the millisecond.
///
/// [1]: https://developer.mozilla.org/docs/Web/API/DOMHighResTimeStamp
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct HighResTimeStamp(pub f64);

impl From<HighResTimeStamp> for SystemTime {
    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
    #[inline]
    fn from(timestamp: HighResTimeStamp) -> Self {
        SystemTime::UNIX_EPOCH + Duration::from_millis(timestamp.0 as u64)
    }
}

impl From<SystemTime> for HighResTimeStamp {
    #[allow(clippy::cast_precision_loss)]
    #[inline]
    fn from(time: SystemTime) -> Self {
        HighResTimeStamp(
            time.duration_since(SystemTime::UNIX_EPOCH)
                .unwrap()
                .as_millis() as f64,
        )
    }
}

/// Hashing string representation.
///
/// Some people believe that such behavior is incorrect (but in some programming
/// languages this is a default behavior) due to `NaN`, `Inf` or `-Inf` (they
/// all will have the same hashes).
/// But in the case of [`RtcStat`] received from the client, there should be no
/// such situations, and the hash will always be correct.
impl Hash for HighResTimeStamp {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.to_string().hash(state);
    }
}

/// Comparison string representations.
///
/// Such implementation is required, so that the results of comparing values and
/// comparing hashes match.
impl PartialEq for HighResTimeStamp {
    fn eq(&self, other: &Self) -> bool {
        self.0.to_string().eq(&other.0.to_string())
    }
}

/// [`f64`] wrapper with [`Hash`] implementation.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct Float(pub f64);

/// Hashing string representation.
///
/// Some people believe that such behavior is incorrect (but in some programming
/// languages this is a default behavior) due to `NaN`, `Inf` or `-Inf` (they
/// all will have the same hashes).
/// But in the case of [`RtcStat`] received from the client, there should be no
/// such situations, and the hash will always be correct.
impl Hash for Float {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.to_string().hash(state);
    }
}

/// Comparison string representations.
///
/// Such implementation is required, so that the results of comparing values and
/// comparing hashes match.
impl PartialEq for Float {
    fn eq(&self, other: &Self) -> bool {
        self.0.to_string().eq(&other.0.to_string())
    }
}

#[cfg(feature = "extended-stats")]
#[cfg_attr(docsrs, doc(cfg(feature = "extended-stats")))]
/// Information about the connection to an ICE server (e.g. STUN or TURN).
///
/// [`RtcStatsType::IceServer`] variant.
///
/// [Full doc on W3C][1].
///
/// [1]: https://w3.org/TR/webrtc-stats/#ice-server-dict%2A
#[serde_with::skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RtcIceServerStats {
    /// URL of the ICE server (e.g. TURN or STUN server).
    pub url: String,

    /// Port number used by the client.
    pub port: u16,

    /// Protocol used by the client to connect to ICE server.
    pub protocol: Protocol,

    /// Total amount of requests that have been sent to this server.
    pub total_requests_sent: Option<u64>,

    /// Total amount of responses received from this server.
    pub total_responses_received: Option<u64>,

    /// Sum of RTTs for all requests that have been sent where a response has
    /// been received.
    pub total_round_trip_time: Option<HighResTimeStamp>,
}