stats: add missing ice candidate stats

added in https://github.com/w3c/webrtc-stats/pull/611
* foundation
* relatedAddress
* relatedPort
* usernameFragment
* tcpType

BUG=webrtc:14480

Change-Id: I5f43373fbbc7c780b8dafb6e2ace2c27f5e22970
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/276780
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38292}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index b73648a..f1ead22 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -245,6 +245,12 @@
   RTCStatsMember<std::string> candidate_type;
   RTCStatsMember<int32_t> priority;
   RTCStatsMember<std::string> url;
+  RTCStatsMember<std::string> foundation;
+  RTCStatsMember<std::string> related_address;
+  RTCStatsMember<int32_t> related_port;
+  RTCStatsMember<std::string> username_fragment;
+  // Enum type RTCIceTcpCandidateType.
+  RTCStatsMember<std::string> tcp_type;
 
   RTCNonStandardStatsMember<bool> vpn;
   RTCNonStandardStatsMember<std::string> network_adapter_type;
diff --git a/g3doc/sitemap.md b/g3doc/sitemap.md
index 4255531..f3230e1 100644
--- a/g3doc/sitemap.md
+++ b/g3doc/sitemap.md
@@ -34,7 +34,7 @@
     *   DataChannel
     *   [PeerConnection](/pc/g3doc/peer_connection.md)
     *   Desktop capture
-    *   Stats
+    *   [Stats](/stats/g3doc/stats.md)
     *   [Logging](/logging/g3doc/rtc_event_log.md)
 *   Testing
     *   Media Quality and performance
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 3dd10e2..bdde9fa 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -921,6 +921,17 @@
     candidate_stats->candidate_type =
         CandidateTypeToRTCIceCandidateType(candidate.type());
     candidate_stats->priority = static_cast<int32_t>(candidate.priority());
+    candidate_stats->foundation = candidate.foundation();
+    auto related_address = candidate.related_address();
+    if (related_address.port() != 0) {
+      candidate_stats->related_address = related_address.ipaddr().ToString();
+      candidate_stats->related_port =
+          static_cast<int32_t>(related_address.port());
+    }
+    candidate_stats->username_fragment = candidate.username();
+    if (candidate.protocol() == "tcp") {
+      candidate_stats->tcp_type = candidate.tcptype();
+    }
 
     stats = candidate_stats.get();
     report->AddStats(std::move(candidate_stats));
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index 371f120..58ea56d 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -225,6 +225,9 @@
   candidate->set_underlying_type_for_vpn(underlying_type_for_vpn);
   candidate->set_type(candidate_type);
   candidate->set_priority(priority);
+  // Defaults for testing.
+  candidate->set_foundation("foundationIsAString");
+  candidate->set_username("iceusernamefragment");
   return candidate;
 }
 
@@ -1664,6 +1667,8 @@
   expected_a_local_host.priority = 0;
   expected_a_local_host.vpn = true;
   expected_a_local_host.network_adapter_type = RTCNetworkAdapterType::kEthernet;
+  expected_a_local_host.foundation = "foundationIsAString";
+  expected_a_local_host.username_fragment = "iceusernamefragment";
 
   std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
       "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
@@ -1677,6 +1682,8 @@
   expected_a_remote_srflx.protocol = "remote_srflx's protocol";
   expected_a_remote_srflx.candidate_type = "srflx";
   expected_a_remote_srflx.priority = 1;
+  expected_a_remote_srflx.foundation = "foundationIsAString";
+  expected_a_remote_srflx.username_fragment = "iceusernamefragment";
 
   std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
       "11.12.13.14", 15, "a_local_prflx's protocol",
@@ -1694,6 +1701,8 @@
   expected_a_local_prflx.vpn = false;
   expected_a_local_prflx.network_adapter_type =
       RTCNetworkAdapterType::kCellular2g;
+  expected_a_local_prflx.foundation = "foundationIsAString";
+  expected_a_local_prflx.username_fragment = "iceusernamefragment";
 
   std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
       "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
@@ -1707,6 +1716,8 @@
   expected_a_remote_relay.protocol = "a_remote_relay's protocol";
   expected_a_remote_relay.candidate_type = "relay";
   expected_a_remote_relay.priority = 3;
+  expected_a_remote_relay.foundation = "foundationIsAString";
+  expected_a_remote_relay.username_fragment = "iceusernamefragment";
 
   std::unique_ptr<cricket::Candidate> a_local_relay = CreateFakeCandidate(
       "16.17.18.19", 21, "a_local_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
@@ -1728,6 +1739,8 @@
   expected_a_local_relay.url = "turn:url1";
   expected_a_local_relay.vpn = false;
   expected_a_local_relay.network_adapter_type = RTCNetworkAdapterType::kUnknown;
+  expected_a_local_relay.foundation = "foundationIsAString";
+  expected_a_local_relay.username_fragment = "iceusernamefragment";
 
   std::unique_ptr<cricket::Candidate> a_local_relay_prflx = CreateFakeCandidate(
       "11.12.13.20", 22, "a_local_relay_prflx's protocol",
@@ -1748,6 +1761,8 @@
   expected_a_local_relay_prflx.vpn = false;
   expected_a_local_relay_prflx.network_adapter_type =
       RTCNetworkAdapterType::kUnknown;
+  expected_a_local_relay_prflx.foundation = "foundationIsAString";
+  expected_a_local_relay_prflx.username_fragment = "iceusernamefragment";
 
   // A non-paired local candidate.
   std::unique_ptr<cricket::Candidate> a_local_host_not_paired =
@@ -1768,6 +1783,8 @@
   expected_a_local_host_not_paired.vpn = true;
   expected_a_local_host_not_paired.network_adapter_type =
       RTCNetworkAdapterType::kEthernet;
+  expected_a_local_host_not_paired.foundation = "foundationIsAString";
+  expected_a_local_host_not_paired.username_fragment = "iceusernamefragment";
 
   // Candidates in the second transport stats.
   std::unique_ptr<cricket::Candidate> b_local =
@@ -1784,6 +1801,8 @@
   expected_b_local.priority = 42;
   expected_b_local.vpn = false;
   expected_b_local.network_adapter_type = RTCNetworkAdapterType::kWifi;
+  expected_b_local.foundation = "foundationIsAString";
+  expected_b_local.username_fragment = "iceusernamefragment";
 
   std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
       "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
@@ -1796,6 +1815,8 @@
   expected_b_remote.protocol = "b_remote's protocol";
   expected_b_remote.candidate_type = "host";
   expected_b_remote.priority = 42;
+  expected_b_remote.foundation = "foundationIsAString";
+  expected_b_remote.username_fragment = "iceusernamefragment";
 
   // Add candidate pairs to connection.
   cricket::TransportChannelStats a_transport_channel_stats;
@@ -1886,9 +1907,13 @@
   std::unique_ptr<cricket::Candidate> local_candidate =
       CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
                           cricket::LOCAL_PORT_TYPE, 42);
+  local_candidate->set_username("local_iceusernamefragment");
+
   std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
       "42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_UNKNOWN,
-      cricket::LOCAL_PORT_TYPE, 42);
+      cricket::STUN_PORT_TYPE, 42);
+  remote_candidate->set_related_address(rtc::SocketAddress("192.168.2.1", 43));
+  remote_candidate->set_username("remote_iceusernamefragment");
 
   cricket::ConnectionInfo connection_info;
   connection_info.best_connection = false;
@@ -2022,6 +2047,8 @@
   expected_local_candidate.protocol = "protocol";
   expected_local_candidate.candidate_type = "host";
   expected_local_candidate.priority = 42;
+  expected_local_candidate.foundation = "foundationIsAString";
+  expected_local_candidate.username_fragment = "local_iceusernamefragment";
   expected_local_candidate.vpn = false;
   expected_local_candidate.network_adapter_type = RTCNetworkAdapterType::kWifi;
   ASSERT_TRUE(report->Get(expected_local_candidate.id()));
@@ -2036,8 +2063,12 @@
   expected_remote_candidate.address = "42.42.42.42";
   expected_remote_candidate.port = 42;
   expected_remote_candidate.protocol = "protocol";
-  expected_remote_candidate.candidate_type = "host";
+  expected_remote_candidate.candidate_type = "srflx";
   expected_remote_candidate.priority = 42;
+  expected_remote_candidate.foundation = "foundationIsAString";
+  expected_remote_candidate.username_fragment = "remote_iceusernamefragment";
+  expected_remote_candidate.related_address = "192.168.2.1";
+  expected_remote_candidate.related_port = 43;
   ASSERT_TRUE(report->Get(expected_remote_candidate.id()));
   EXPECT_EQ(expected_remote_candidate,
             report->Get(expected_remote_candidate.id())
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index e49f173..b1f95bc 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -542,6 +542,11 @@
     verifier.TestMemberIsNonNegative<int32_t>(candidate.priority);
     verifier.TestMemberIsUndefined(candidate.url);
     verifier.TestMemberIsUndefined(candidate.relay_protocol);
+    verifier.TestMemberIsDefined(candidate.foundation);
+    verifier.TestMemberIsUndefined(candidate.related_address);
+    verifier.TestMemberIsUndefined(candidate.related_port);
+    verifier.TestMemberIsDefined(candidate.username_fragment);
+    verifier.TestMemberIsUndefined(candidate.tcp_type);
     return verifier.ExpectAllMembersSuccessfullyTested();
   }
 
diff --git a/stats/g3doc/stats.md b/stats/g3doc/stats.md
new file mode 100644
index 0000000..790e101
--- /dev/null
+++ b/stats/g3doc/stats.md
@@ -0,0 +1,18 @@
+<?% config.freshness.reviewed = '2022-10-01' %?>

+<?% config.freshness.owner = 'hta' %?>

+

+# getStats in WebRTC

+

+The WebRTC getStats API is specified in

+  https://w3c.github.io/webrtc-stats/

+and allows querying information about the current state of a RTCPeerConnection

+API and some of its member objects.

+

+## Adding new statistics to Chrome

+

+When adding a new standardized `RTCStatsMember` it is necessary to add

+it to the Chrome allowlist

+  chrome/test/data/webrtc/peerconnection_getstats.js

+before landing the WebRTC change. This mechanism prevents the accidential

+addition and exposure of non-standard attributes and is not required for

+`RTCNonStandardStatsMember` which is not exposed to the web API.
\ No newline at end of file
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index b1b081f..22fd9fb 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -279,6 +279,11 @@
     &candidate_type,
     &priority,
     &url,
+    &foundation,
+    &related_address,
+    &related_port,
+    &username_fragment,
+    &tcp_type,
     &vpn,
     &network_adapter_type)
 // clang-format on
@@ -303,6 +308,11 @@
       candidate_type("candidateType"),
       priority("priority"),
       url("url"),
+      foundation("foundation"),
+      related_address("relatedAddress"),
+      related_port("relatedPort"),
+      username_fragment("usernameFragment"),
+      tcp_type("tcpType"),
       vpn("vpn"),
       network_adapter_type("networkAdapterType") {}
 
@@ -319,6 +329,11 @@
       candidate_type(other.candidate_type),
       priority(other.priority),
       url(other.url),
+      foundation(other.foundation),
+      related_address(other.related_address),
+      related_port(other.related_port),
+      username_fragment(other.username_fragment),
+      tcp_type(other.tcp_type),
       vpn(other.vpn),
       network_adapter_type(other.network_adapter_type) {}