diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h index 97a7d3cdb6..b0cf3d0f65 100644 --- a/api/stats/rtcstats_objects.h +++ b/api/stats/rtcstats_objects.h @@ -60,6 +60,17 @@ struct RTCMediaStreamTrackKind { 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 @@ class RTCIceCandidateStats : public RTCStats { RTCStatsMember transport_id; RTCStatsMember is_remote; + RTCStatsMember network_type; RTCStatsMember ip; RTCStatsMember port; RTCStatsMember protocol; diff --git a/pc/rtcstats_integrationtest.cc b/pc/rtcstats_integrationtest.cc index d0a5863f65..b6c92f368f 100644 --- a/pc/rtcstats_integrationtest.cc +++ b/pc/rtcstats_integrationtest.cc @@ -463,6 +463,11 @@ class RTCStatsReportVerifier { 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(candidate.port); verifier.TestMemberIsDefined(candidate.protocol); diff --git a/pc/rtcstatscollector.cc b/pc/rtcstatscollector.cc index 8353cd77db..a23ab30185 100644 --- a/pc/rtcstatscollector.cc +++ b/pc/rtcstatscollector.cc @@ -162,6 +162,24 @@ const char* DtlsTransportStateToRTCDtlsTransportState( } } +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 @@ const std::string& ProduceIceCandidateStats( 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(candidate.address().port()); candidate_stats->protocol = candidate.protocol(); diff --git a/pc/rtcstatscollector_unittest.cc b/pc/rtcstatscollector_unittest.cc index d088221051..d6c21cebfa 100644 --- a/pc/rtcstatscollector_unittest.cc +++ b/pc/rtcstatscollector_unittest.cc @@ -159,11 +159,13 @@ std::unique_ptr CreateFakeCandidate( 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 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, CollectRTCDataChannelStats) { TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { // Candidates in the first transport stats. - std::unique_ptr a_local_host = CreateFakeCandidate( - "1.2.3.4", 5, - "a_local_host's protocol", - cricket::LOCAL_PORT_TYPE, - 0); + std::unique_ptr 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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { EXPECT_FALSE(*expected_a_local_host.is_remote); std::unique_ptr 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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { EXPECT_TRUE(*expected_a_remote_srflx.is_remote); std::unique_ptr 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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { EXPECT_FALSE(*expected_a_local_prflx.is_remote); std::unique_ptr 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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { EXPECT_TRUE(*expected_a_remote_relay.is_remote); // Candidates in the second transport stats. - std::unique_ptr b_local = CreateFakeCandidate( - "42.42.42.42", 42, - "b_local's protocol", - cricket::LOCAL_PORT_TYPE, - 42); + std::unique_ptr 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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) { EXPECT_FALSE(*expected_b_local.is_remote); std::unique_ptr 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_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) { test_->signaling_thread(), rtc::WrapUnique(video_media_channel), "VideoContentName", kDefaultRtcpMuxRequired, kDefaultSrtpRequired); - std::unique_ptr local_candidate = CreateFakeCandidate( - "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42); + std::unique_ptr local_candidate = + CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI, + cricket::LOCAL_PORT_TYPE, 42); std::unique_ptr 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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) { 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, CollectRTCOutboundRTPStreamStats_Video) { } TEST_F(RTCStatsCollectorTest, CollectRTCTransportStats) { - std::unique_ptr rtp_local_candidate = CreateFakeCandidate( - "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42); + std::unique_ptr rtp_local_candidate = + CreateFakeCandidate("42.42.42.42", 42, "protocol", rtc::ADAPTER_TYPE_WIFI, + cricket::LOCAL_PORT_TYPE, 42); std::unique_ptr 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 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 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 b1698cfe71..b6bc4c0f9e 100644 --- a/stats/rtcstats_objects.cc +++ b/stats/rtcstats_objects.cc @@ -38,6 +38,15 @@ const char* const RTCDtlsTransportState::kFailed = "failed"; 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 @@ RTCIceCandidatePairStats::~RTCIceCandidatePairStats() { WEBRTC_RTCSTATS_IMPL(RTCIceCandidateStats, RTCStats, "ice-candidate", &transport_id, &is_remote, + &network_type, &ip, &port, &protocol, @@ -270,32 +280,33 @@ RTCIceCandidateStats::RTCIceCandidateStats( : 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() { }