Add network_type to local RTCIceCandidateStats

Details:
  * Add RTCNetworkType enum
  * Add network_type to local ice candidate stats

Bug: webrtc:8435
Change-Id: Idb872849c09ad49c8f759d02afdc825e397afa07
Reviewed-on: https://webrtc-review.googlesource.com/14680
Commit-Queue: Gary Liu <qinghualiu@google.com>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20822}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index 97a7d3c..b0cf3d0 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -60,6 +60,17 @@
   static const char* const kVideo;
 };
 
+// https://w3c.github.io/webrtc-stats/#dom-rtcnetworktype
+struct RTCNetworkType {
+  static const char* const kBluetooth;
+  static const char* const kCellular;
+  static const char* const kEthernet;
+  static const char* const kWifi;
+  static const char* const kWimax;
+  static const char* const kVpn;
+  static const char* const kUnknown;
+};
+
 // https://w3c.github.io/webrtc-stats/#certificatestats-dict*
 class RTCCertificateStats final : public RTCStats {
  public:
@@ -181,6 +192,7 @@
 
   RTCStatsMember<std::string> transport_id;
   RTCStatsMember<bool> is_remote;
+  RTCStatsMember<std::string> network_type;
   RTCStatsMember<std::string> ip;
   RTCStatsMember<int32_t> port;
   RTCStatsMember<std::string> protocol;
diff --git a/pc/rtcstats_integrationtest.cc b/pc/rtcstats_integrationtest.cc
index d0a5863..b6c92f3 100644
--- a/pc/rtcstats_integrationtest.cc
+++ b/pc/rtcstats_integrationtest.cc
@@ -463,6 +463,11 @@
     verifier.TestMemberIsIDReference(
         candidate.transport_id, RTCTransportStats::kType);
     verifier.TestMemberIsDefined(candidate.is_remote);
+    if (*candidate.is_remote) {
+      verifier.TestMemberIsUndefined(candidate.network_type);
+    } else {
+      verifier.TestMemberIsDefined(candidate.network_type);
+    }
     verifier.TestMemberIsDefined(candidate.ip);
     verifier.TestMemberIsNonNegative<int32_t>(candidate.port);
     verifier.TestMemberIsDefined(candidate.protocol);
diff --git a/pc/rtcstatscollector.cc b/pc/rtcstatscollector.cc
index 8353cd7..a23ab30 100644
--- a/pc/rtcstatscollector.cc
+++ b/pc/rtcstatscollector.cc
@@ -162,6 +162,24 @@
   }
 }
 
+const char* NetworkAdapterTypeToStatsType(rtc::AdapterType type) {
+  switch (type) {
+    case rtc::ADAPTER_TYPE_CELLULAR:
+      return RTCNetworkType::kCellular;
+    case rtc::ADAPTER_TYPE_ETHERNET:
+      return RTCNetworkType::kEthernet;
+    case rtc::ADAPTER_TYPE_WIFI:
+      return RTCNetworkType::kWifi;
+    case rtc::ADAPTER_TYPE_VPN:
+      return RTCNetworkType::kVpn;
+    case rtc::ADAPTER_TYPE_UNKNOWN:
+    case rtc::ADAPTER_TYPE_LOOPBACK:
+      return RTCNetworkType::kUnknown;
+  }
+  RTC_NOTREACHED();
+  return nullptr;
+}
+
 double DoubleAudioLevelFromIntAudioLevel(int audio_level) {
   RTC_DCHECK_GE(audio_level, 0);
   RTC_DCHECK_LE(audio_level, 32767);
@@ -341,6 +359,13 @@
     else
       candidate_stats.reset(new RTCRemoteIceCandidateStats(id, timestamp_us));
     candidate_stats->transport_id = transport_id;
+    if (is_local) {
+      candidate_stats->network_type =
+          NetworkAdapterTypeToStatsType(candidate.network_type());
+    } else {
+      // We don't expect to know the adapter type of remote candidates.
+      RTC_DCHECK_EQ(rtc::ADAPTER_TYPE_UNKNOWN, candidate.network_type());
+    }
     candidate_stats->ip = candidate.address().ipaddr().ToString();
     candidate_stats->port = static_cast<int32_t>(candidate.address().port());
     candidate_stats->protocol = candidate.protocol();
diff --git a/pc/rtcstatscollector_unittest.cc b/pc/rtcstatscollector_unittest.cc
index d088221..d6c21ce 100644
--- a/pc/rtcstatscollector_unittest.cc
+++ b/pc/rtcstatscollector_unittest.cc
@@ -159,11 +159,13 @@
     const std::string& hostname,
     int port,
     const std::string& protocol,
+    const rtc::AdapterType adapter_type,
     const std::string& candidate_type,
     uint32_t priority) {
   std::unique_ptr<cricket::Candidate> candidate(new cricket::Candidate());
   candidate->set_address(rtc::SocketAddress(hostname, port));
   candidate->set_protocol(protocol);
+  candidate->set_network_type(adapter_type);
   candidate->set_type(candidate_type);
   candidate->set_priority(priority);
   return candidate;
@@ -1051,14 +1053,13 @@
 
 TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
   // Candidates in the first transport stats.
-  std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
-      "1.2.3.4", 5,
-      "a_local_host's protocol",
-      cricket::LOCAL_PORT_TYPE,
-      0);
+  std::unique_ptr<cricket::Candidate> a_local_host =
+      CreateFakeCandidate("1.2.3.4", 5, "a_local_host's protocol",
+                          rtc::ADAPTER_TYPE_VPN, cricket::LOCAL_PORT_TYPE, 0);
   RTCLocalIceCandidateStats expected_a_local_host(
       "RTCIceCandidate_" + a_local_host->id(), 0);
   expected_a_local_host.transport_id = "RTCTransport_a_0";
+  expected_a_local_host.network_type = "vpn";
   expected_a_local_host.ip = "1.2.3.4";
   expected_a_local_host.port = 5;
   expected_a_local_host.protocol = "a_local_host's protocol";
@@ -1067,10 +1068,8 @@
   EXPECT_FALSE(*expected_a_local_host.is_remote);
 
   std::unique_ptr<cricket::Candidate> a_remote_srflx = CreateFakeCandidate(
-      "6.7.8.9", 10,
-      "remote_srflx's protocol",
-      cricket::STUN_PORT_TYPE,
-      1);
+      "6.7.8.9", 10, "remote_srflx's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
+      cricket::STUN_PORT_TYPE, 1);
   RTCRemoteIceCandidateStats expected_a_remote_srflx(
       "RTCIceCandidate_" + a_remote_srflx->id(), 0);
   expected_a_remote_srflx.transport_id = "RTCTransport_a_0";
@@ -1083,13 +1082,12 @@
   EXPECT_TRUE(*expected_a_remote_srflx.is_remote);
 
   std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
-      "11.12.13.14", 15,
-      "a_local_prflx's protocol",
-      cricket::PRFLX_PORT_TYPE,
-      2);
+      "11.12.13.14", 15, "a_local_prflx's protocol", rtc::ADAPTER_TYPE_CELLULAR,
+      cricket::PRFLX_PORT_TYPE, 2);
   RTCLocalIceCandidateStats expected_a_local_prflx(
       "RTCIceCandidate_" + a_local_prflx->id(), 0);
   expected_a_local_prflx.transport_id = "RTCTransport_a_0";
+  expected_a_local_prflx.network_type = "cellular";
   expected_a_local_prflx.ip = "11.12.13.14";
   expected_a_local_prflx.port = 15;
   expected_a_local_prflx.protocol = "a_local_prflx's protocol";
@@ -1099,10 +1097,8 @@
   EXPECT_FALSE(*expected_a_local_prflx.is_remote);
 
   std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
-      "16.17.18.19", 20,
-      "a_remote_relay's protocol",
-      cricket::RELAY_PORT_TYPE,
-      3);
+      "16.17.18.19", 20, "a_remote_relay's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
+      cricket::RELAY_PORT_TYPE, 3);
   RTCRemoteIceCandidateStats expected_a_remote_relay(
       "RTCIceCandidate_" + a_remote_relay->id(), 0);
   expected_a_remote_relay.transport_id = "RTCTransport_a_0";
@@ -1115,14 +1111,13 @@
   EXPECT_TRUE(*expected_a_remote_relay.is_remote);
 
   // Candidates in the second transport stats.
-  std::unique_ptr<cricket::Candidate> b_local = CreateFakeCandidate(
-      "42.42.42.42", 42,
-      "b_local's protocol",
-      cricket::LOCAL_PORT_TYPE,
-      42);
+  std::unique_ptr<cricket::Candidate> b_local =
+      CreateFakeCandidate("42.42.42.42", 42, "b_local's protocol",
+                          rtc::ADAPTER_TYPE_WIFI, cricket::LOCAL_PORT_TYPE, 42);
   RTCLocalIceCandidateStats expected_b_local(
       "RTCIceCandidate_" + b_local->id(), 0);
   expected_b_local.transport_id = "RTCTransport_b_0";
+  expected_b_local.network_type = "wifi";
   expected_b_local.ip = "42.42.42.42";
   expected_b_local.port = 42;
   expected_b_local.protocol = "b_local's protocol";
@@ -1132,10 +1127,8 @@
   EXPECT_FALSE(*expected_b_local.is_remote);
 
   std::unique_ptr<cricket::Candidate> b_remote = CreateFakeCandidate(
-      "42.42.42.42", 42,
-      "b_remote's protocol",
-      cricket::LOCAL_PORT_TYPE,
-      42);
+      "42.42.42.42", 42, "b_remote's protocol", rtc::ADAPTER_TYPE_UNKNOWN,
+      cricket::LOCAL_PORT_TYPE, 42);
   RTCRemoteIceCandidateStats expected_b_remote(
       "RTCIceCandidate_" + b_remote->id(), 0);
   expected_b_remote.transport_id = "RTCTransport_b_0";
@@ -1220,10 +1213,12 @@
       test_->signaling_thread(), rtc::WrapUnique(video_media_channel),
       "VideoContentName", kDefaultRtcpMuxRequired, kDefaultSrtpRequired);
 
-  std::unique_ptr<cricket::Candidate> local_candidate = CreateFakeCandidate(
-      "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
+  std::unique_ptr<cricket::Candidate> local_candidate =
+      CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
+                          cricket::LOCAL_PORT_TYPE, 42);
   std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
-      "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
+      "42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_UNKNOWN,
+      cricket::LOCAL_PORT_TYPE, 42);
 
   SessionStats session_stats;
 
@@ -1374,6 +1369,7 @@
   RTCLocalIceCandidateStats expected_local_candidate(
       *expected_pair.local_candidate_id, report->timestamp_us());
   expected_local_candidate.transport_id = *expected_pair.transport_id;
+  expected_local_candidate.network_type = "wifi";
   expected_local_candidate.ip = "42.42.42.42";
   expected_local_candidate.port = 42;
   expected_local_candidate.protocol = "protocol";
@@ -2162,17 +2158,20 @@
 }
 
 TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) {
-  std::unique_ptr<cricket::Candidate> rtp_local_candidate = CreateFakeCandidate(
-      "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
+  std::unique_ptr<cricket::Candidate> rtp_local_candidate =
+      CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
+                          cricket::LOCAL_PORT_TYPE, 42);
   std::unique_ptr<cricket::Candidate> rtp_remote_candidate =
       CreateFakeCandidate("42.42.42.42", 42, "protocol",
-                          cricket::LOCAL_PORT_TYPE, 42);
+                          rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
+                          42);
   std::unique_ptr<cricket::Candidate> rtcp_local_candidate =
-      CreateFakeCandidate("42.42.42.42", 42, "protocol",
+      CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI,
                           cricket::LOCAL_PORT_TYPE, 42);
   std::unique_ptr<cricket::Candidate> rtcp_remote_candidate =
       CreateFakeCandidate("42.42.42.42", 42, "protocol",
-                          cricket::LOCAL_PORT_TYPE, 42);
+                          rtc::ADAPTER_TYPE_UNKNOWN, cricket::LOCAL_PORT_TYPE,
+                          42);
 
   SessionStats session_stats;
   session_stats.transport_stats["transport"].transport_name = "transport";
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index b1698cf..b6bc4c0 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -38,6 +38,15 @@
 const char* const RTCMediaStreamTrackKind::kAudio = "audio";
 const char* const RTCMediaStreamTrackKind::kVideo = "video";
 
+// https://w3c.github.io/webrtc-stats/#dom-rtcnetworktype
+const char* const RTCNetworkType::kBluetooth = "bluetooth";
+const char* const RTCNetworkType::kCellular = "cellular";
+const char* const RTCNetworkType::kEthernet = "ethernet";
+const char* const RTCNetworkType::kWifi = "wifi";
+const char* const RTCNetworkType::kWimax = "wimax";
+const char* const RTCNetworkType::kVpn = "vpn";
+const char* const RTCNetworkType::kUnknown = "unknown";
+
 // clang-format off
 WEBRTC_RTCSTATS_IMPL(RTCCertificateStats, RTCStats, "certificate",
     &fingerprint,
@@ -256,6 +265,7 @@
 WEBRTC_RTCSTATS_IMPL(RTCIceCandidateStats, RTCStats, "ice-candidate",
     &transport_id,
     &is_remote,
+    &network_type,
     &ip,
     &port,
     &protocol,
@@ -270,32 +280,33 @@
     : RTCIceCandidateStats(std::string(id), timestamp_us, is_remote) {
 }
 
-RTCIceCandidateStats::RTCIceCandidateStats(
-    std::string&& id, int64_t timestamp_us, bool is_remote)
+RTCIceCandidateStats::RTCIceCandidateStats(std::string&& id,
+                                           int64_t timestamp_us,
+                                           bool is_remote)
     : RTCStats(std::move(id), timestamp_us),
       transport_id("transportId"),
       is_remote("isRemote", is_remote),
+      network_type("networkType"),
       ip("ip"),
       port("port"),
       protocol("protocol"),
       candidate_type("candidateType"),
       priority("priority"),
       url("url"),
-      deleted("deleted", false) {
-}
+      deleted("deleted", false) {}
 
 RTCIceCandidateStats::RTCIceCandidateStats(const RTCIceCandidateStats& other)
     : RTCStats(other.id(), other.timestamp_us()),
       transport_id(other.transport_id),
       is_remote(other.is_remote),
+      network_type(other.network_type),
       ip(other.ip),
       port(other.port),
       protocol(other.protocol),
       candidate_type(other.candidate_type),
       priority(other.priority),
       url(other.url),
-      deleted(other.deleted) {
-}
+      deleted(other.deleted) {}
 
 RTCIceCandidateStats::~RTCIceCandidateStats() {
 }