stats: implement iceRole

https://www.w3.org/TR/webrtc-stats/#dom-rtctransportstats-icerole

BUG=webrtc:14022

Change-Id: I88de2c843a2042ce99076d55ce41be22589e2d92
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/261201
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <philipp.hancke@googlemail.com>
Cr-Commit-Position: refs/heads/main@{#36766}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index b22de2b..3fb68ae 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -97,6 +97,13 @@
   static const char* const kServer;
 };
 
+// https://www.w3.org/TR/webrtc/#rtcicerole
+struct RTCIceRole {
+  static const char* const kUnknown;
+  static const char* const kControlled;
+  static const char* const kControlling;
+};
+
 // https://w3c.github.io/webrtc-stats/#certificatestats-dict*
 class RTC_EXPORT RTCCertificateStats final : public RTCStats {
  public:
@@ -701,6 +708,7 @@
   RTCStatsMember<std::string> dtls_role;
   RTCStatsMember<std::string> srtp_cipher;
   RTCStatsMember<uint32_t> selected_candidate_pair_changes;
+  RTCStatsMember<std::string> ice_role;
 };
 
 }  // namespace webrtc
diff --git a/p2p/base/ice_transport_internal.h b/p2p/base/ice_transport_internal.h
index e1171d4..3992de2 100644
--- a/p2p/base/ice_transport_internal.h
+++ b/p2p/base/ice_transport_internal.h
@@ -47,6 +47,8 @@
   uint64_t bytes_received = 0;
   uint64_t packets_sent = 0;
   uint64_t packets_received = 0;
+
+  IceRole ice_role = ICEROLE_UNKNOWN;
 };
 
 typedef std::vector<Candidate> Candidates;
diff --git a/p2p/base/p2p_transport_channel.cc b/p2p/base/p2p_transport_channel.cc
index 1daec12..bc68911 100644
--- a/p2p/base/p2p_transport_channel.cc
+++ b/p2p/base/p2p_transport_channel.cc
@@ -1663,6 +1663,9 @@
   ice_transport_stats->bytes_received = bytes_received_;
   ice_transport_stats->packets_sent = packets_sent_;
   ice_transport_stats->packets_received = packets_received_;
+
+  ice_transport_stats->ice_role = GetIceRole();
+
   return true;
 }
 
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 488b7a7..b3378ce 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -210,6 +210,20 @@
   }
 }
 
+const char* IceRoleToRTCIceRole(cricket::IceRole role) {
+  switch (role) {
+    case cricket::IceRole::ICEROLE_UNKNOWN:
+      return RTCIceRole::kUnknown;
+    case cricket::IceRole::ICEROLE_CONTROLLED:
+      return RTCIceRole::kControlled;
+    case cricket::IceRole::ICEROLE_CONTROLLING:
+      return RTCIceRole::kControlling;
+    default:
+      RTC_DCHECK_NOTREACHED();
+      return nullptr;
+  }
+}
+
 const char* DtlsTransportStateToRTCDtlsTransportState(
     DtlsTransportState state) {
   switch (state) {
@@ -2100,6 +2114,8 @@
           DtlsTransportStateToRTCDtlsTransportState(channel_stats.dtls_state);
       transport_stats->selected_candidate_pair_changes =
           channel_stats.ice_transport_stats.selected_candidate_pair_changes;
+      transport_stats->ice_role =
+          IceRoleToRTCIceRole(channel_stats.ice_transport_stats.ice_role);
       for (const cricket::ConnectionInfo& info :
            channel_stats.ice_transport_stats.connection_infos) {
         if (info.best_connection) {
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index b5a5704..b070852 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -2465,6 +2465,7 @@
   expected_rtp_transport.dtls_state = RTCDtlsTransportState::kNew;
   expected_rtp_transport.dtls_role = RTCDtlsRole::kUnknown;
   expected_rtp_transport.selected_candidate_pair_changes = 1;
+  expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
 
   ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
   EXPECT_EQ(
@@ -2507,6 +2508,7 @@
   expected_rtcp_transport.dtls_state = RTCDtlsTransportState::kConnecting;
   expected_rtcp_transport.dtls_role = RTCDtlsRole::kUnknown;
   expected_rtcp_transport.selected_candidate_pair_changes = 0;
+  expected_rtcp_transport.ice_role = RTCIceRole::kUnknown;
 
   expected_rtp_transport.rtcp_transport_stats_id = expected_rtcp_transport.id();
   ASSERT_TRUE(report->Get(expected_rtp_transport.id()));
@@ -2606,6 +2608,8 @@
       .selected_candidate_pair_changes = 1;
   rtp_transport_channel_stats.ssl_version_bytes = 0x0203;
   rtp_transport_channel_stats.dtls_role = rtc::SSL_CLIENT;
+  rtp_transport_channel_stats.ice_transport_stats.ice_role =
+      cricket::ICEROLE_CONTROLLING;
   // 0x2F is TLS_RSA_WITH_AES_128_CBC_SHA according to IANA
   rtp_transport_channel_stats.ssl_cipher_suite = 0x2F;
   rtp_transport_channel_stats.srtp_crypto_suite = rtc::kSrtpAes128CmSha1_80;
@@ -2620,6 +2624,7 @@
       report->timestamp_us());
   expected_rtp_transport.dtls_state = RTCDtlsTransportState::kConnected;
   expected_rtp_transport.selected_candidate_pair_changes = 1;
+  expected_rtp_transport.ice_role = RTCIceRole::kUnknown;
   expected_rtp_transport.bytes_sent = 0;
   expected_rtp_transport.bytes_received = 0;
   expected_rtp_transport.packets_sent = 0;
@@ -2627,6 +2632,7 @@
   // Crypto parameters
   expected_rtp_transport.tls_version = "0203";
   expected_rtp_transport.dtls_role = RTCDtlsRole::kClient;
+  expected_rtp_transport.ice_role = RTCIceRole::kControlling;
   expected_rtp_transport.dtls_cipher = "TLS_RSA_WITH_AES_128_CBC_SHA";
   expected_rtp_transport.srtp_cipher = "AES_CM_128_HMAC_SHA1_80";
 
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index d94e4b6..c140404 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -1143,6 +1143,7 @@
     verifier.TestMemberIsDefined(transport.srtp_cipher);
     verifier.TestMemberIsPositive<uint32_t>(
         transport.selected_candidate_pair_changes);
+    verifier.TestMemberIsDefined(transport.ice_role);
     return verifier.ExpectAllMembersSuccessfullyTested();
   }
 
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index f45ea35..0362f6b 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -67,6 +67,11 @@
 const char* const RTCDtlsRole::kClient = "client";
 const char* const RTCDtlsRole::kServer = "server";
 
+// https://www.w3.org/TR/webrtc/#rtcicerole
+const char* const RTCIceRole::kUnknown = "unknown";
+const char* const RTCIceRole::kControlled = "controlled";
+const char* const RTCIceRole::kControlling = "controlling";
+
 // clang-format off
 WEBRTC_RTCSTATS_IMPL(RTCCertificateStats, RTCStats, "certificate",
     &fingerprint,
@@ -1092,7 +1097,8 @@
     &dtls_cipher,
     &dtls_role,
     &srtp_cipher,
-    &selected_candidate_pair_changes)
+    &selected_candidate_pair_changes,
+    &ice_role)
 // clang-format on
 
 RTCTransportStats::RTCTransportStats(const std::string& id,
@@ -1114,7 +1120,8 @@
       dtls_cipher("dtlsCipher"),
       dtls_role("dtlsRole"),
       srtp_cipher("srtpCipher"),
-      selected_candidate_pair_changes("selectedCandidatePairChanges") {}
+      selected_candidate_pair_changes("selectedCandidatePairChanges"),
+      ice_role("iceRole") {}
 
 RTCTransportStats::RTCTransportStats(const RTCTransportStats& other)
     : RTCStats(other.id(), other.timestamp_us()),
@@ -1131,7 +1138,8 @@
       dtls_cipher(other.dtls_cipher),
       dtls_role(other.dtls_role),
       srtp_cipher(other.srtp_cipher),
-      selected_candidate_pair_changes(other.selected_candidate_pair_changes) {}
+      selected_candidate_pair_changes(other.selected_candidate_pair_changes),
+      ice_role(other.ice_role) {}
 
 RTCTransportStats::~RTCTransportStats() {}