RTCIceCandidateStats[1] added.
The RTCStatsCollector collects candidates from candidate pairs. Note that there may be other candidates that are not paired with anything, stats for these should also be produced before closing crbug.com/632723. [1] https://w3c.github.io/webrtc-stats/#icecandidate-dict* BUG=chromium:627816, chromium:632723 Review-Url: https://codereview.webrtc.org/2384143002 Cr-Commit-Position: refs/heads/master@{#14565}
This commit is contained in:
@ -18,9 +18,24 @@
|
||||
#include "webrtc/api/webrtcsession.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/sslidentity.h"
|
||||
#include "webrtc/p2p/base/candidate.h"
|
||||
#include "webrtc/p2p/base/port.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const char* CandidateTypeToRTCIceCandidateType(const std::string& type) {
|
||||
if (type == cricket::LOCAL_PORT_TYPE)
|
||||
return RTCIceCandidateType::kHost;
|
||||
if (type == cricket::STUN_PORT_TYPE)
|
||||
return RTCIceCandidateType::kSrflx;
|
||||
if (type == cricket::PRFLX_PORT_TYPE)
|
||||
return RTCIceCandidateType::kPrflx;
|
||||
if (type == cricket::RELAY_PORT_TYPE)
|
||||
return RTCIceCandidateType::kRelay;
|
||||
RTC_NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
|
||||
PeerConnection* pc, int64_t cache_lifetime_us) {
|
||||
return rtc::scoped_refptr<RTCStatsCollector>(
|
||||
@ -93,6 +108,8 @@ void RTCStatsCollector::ProducePartialResultsOnSignalingThread(
|
||||
SessionStats session_stats;
|
||||
if (pc_->session()->GetTransportStats(&session_stats)) {
|
||||
ProduceCertificateStats_s(timestamp_us, session_stats, report.get());
|
||||
ProduceIceCandidateAndPairStats_s(timestamp_us, session_stats,
|
||||
report.get());
|
||||
}
|
||||
ProducePeerConnectionStats_s(timestamp_us, report.get());
|
||||
|
||||
@ -201,6 +218,59 @@ void RTCStatsCollector::ProduceCertificateStatsFromSSLCertificateAndChain_s(
|
||||
}
|
||||
}
|
||||
|
||||
void RTCStatsCollector::ProduceIceCandidateAndPairStats_s(
|
||||
int64_t timestamp_us, const SessionStats& session_stats,
|
||||
RTCStatsReport* report) const {
|
||||
RTC_DCHECK(signaling_thread_->IsCurrent());
|
||||
for (const auto& transport : session_stats.transport_stats) {
|
||||
for (const auto& channel : transport.second.channel_stats) {
|
||||
for (const cricket::ConnectionInfo& info : channel.connection_infos) {
|
||||
// TODO(hbos): Produce |RTCIceCandidatePairStats| referencing the
|
||||
// resulting |RTCIceCandidateStats| pair. crbug.com/633550
|
||||
// TODO(hbos): There could be other candidates that are not paired with
|
||||
// anything. We don't have a complete list. Local candidates come from
|
||||
// Port objects, and prflx candidates (both local and remote) are only
|
||||
// stored in candidate pairs. crbug.com/632723
|
||||
ProduceIceCandidateStats_s(
|
||||
timestamp_us, info.local_candidate, true, report);
|
||||
ProduceIceCandidateStats_s(
|
||||
timestamp_us, info.remote_candidate, false, report);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& RTCStatsCollector::ProduceIceCandidateStats_s(
|
||||
int64_t timestamp_us, const cricket::Candidate& candidate, bool is_local,
|
||||
RTCStatsReport* report) const {
|
||||
RTC_DCHECK(signaling_thread_->IsCurrent());
|
||||
const std::string& id = "RTCIceCandidate_" + candidate.id();
|
||||
const RTCStats* stats = report->Get(id);
|
||||
if (!stats) {
|
||||
std::unique_ptr<RTCIceCandidateStats> candidate_stats;
|
||||
if (is_local) {
|
||||
candidate_stats.reset(
|
||||
new RTCLocalIceCandidateStats(id, timestamp_us));
|
||||
} else {
|
||||
candidate_stats.reset(
|
||||
new RTCRemoteIceCandidateStats(id, timestamp_us));
|
||||
}
|
||||
candidate_stats->ip = candidate.address().ipaddr().ToString();
|
||||
candidate_stats->port = static_cast<int32_t>(candidate.address().port());
|
||||
candidate_stats->protocol = candidate.protocol();
|
||||
candidate_stats->candidate_type = CandidateTypeToRTCIceCandidateType(
|
||||
candidate.type());
|
||||
candidate_stats->priority = static_cast<int32_t>(candidate.priority());
|
||||
// TODO(hbos): Define candidate_stats->url. crbug.com/632723
|
||||
|
||||
stats = candidate_stats.get();
|
||||
report->AddStats(std::move(candidate_stats));
|
||||
}
|
||||
RTC_DCHECK_EQ(stats->type(), is_local ? RTCLocalIceCandidateStats::kType
|
||||
: RTCRemoteIceCandidateStats::kType);
|
||||
return stats->id();
|
||||
}
|
||||
|
||||
void RTCStatsCollector::ProducePeerConnectionStats_s(
|
||||
int64_t timestamp_us, RTCStatsReport* report) const {
|
||||
RTC_DCHECK(signaling_thread_->IsCurrent());
|
||||
|
||||
@ -21,10 +21,12 @@
|
||||
#include "webrtc/base/scoped_ref_ptr.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
|
||||
namespace cricket {
|
||||
class Candidate;
|
||||
} // namespace cricket
|
||||
|
||||
namespace rtc {
|
||||
|
||||
class SSLCertificate;
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
namespace webrtc {
|
||||
@ -76,12 +78,22 @@ class RTCStatsCollector : public virtual rtc::RefCountInterface {
|
||||
void AddPartialResults_s(rtc::scoped_refptr<RTCStatsReport> partial_report);
|
||||
void DeliverCachedReport();
|
||||
|
||||
// Produces |RTCCertificateStats|.
|
||||
void ProduceCertificateStats_s(
|
||||
int64_t timestamp_us, const SessionStats& session_stats,
|
||||
RTCStatsReport* report) const;
|
||||
void ProduceCertificateStatsFromSSLCertificateAndChain_s(
|
||||
int64_t timestamp_us, const rtc::SSLCertificate& certificate,
|
||||
RTCStatsReport* report) const;
|
||||
// Produces |RTCIceCandidateStats|. TODO(hbos): Should also produce
|
||||
// |RTCIceCandidatePairStats|. crbug.com/633550
|
||||
void ProduceIceCandidateAndPairStats_s(
|
||||
int64_t timestamp_us, const SessionStats& session_stats,
|
||||
RTCStatsReport* report) const;
|
||||
const std::string& ProduceIceCandidateStats_s(
|
||||
int64_t timestamp_us, const cricket::Candidate& candidate, bool is_local,
|
||||
RTCStatsReport* report) const;
|
||||
// Produces |RTCPeerConnectionStats|.
|
||||
void ProducePeerConnectionStats_s(
|
||||
int64_t timestamp_us, RTCStatsReport* report) const;
|
||||
|
||||
@ -105,6 +117,9 @@ class RTCStatsCollector : public virtual rtc::RefCountInterface {
|
||||
rtc::scoped_refptr<const RTCStatsReport> cached_report_;
|
||||
};
|
||||
|
||||
// Helper function, exposed for unittests.
|
||||
const char* CandidateTypeToRTCIceCandidateType(const std::string& type);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_API_RTCSTATSCOLLECTOR_H_
|
||||
|
||||
@ -25,10 +25,12 @@
|
||||
#include "webrtc/base/fakesslidentity.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/socketaddress.h"
|
||||
#include "webrtc/base/thread_checker.h"
|
||||
#include "webrtc/base/timedelta.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
#include "webrtc/media/base/fakemediaengine.h"
|
||||
#include "webrtc/p2p/base/port.h"
|
||||
|
||||
using testing::_;
|
||||
using testing::Invoke;
|
||||
@ -91,6 +93,20 @@ std::unique_ptr<CertificateInfo> CreateFakeCertificateAndInfoFromDers(
|
||||
return info;
|
||||
}
|
||||
|
||||
std::unique_ptr<cricket::Candidate> CreateFakeCandidate(
|
||||
const std::string& hostname,
|
||||
int port,
|
||||
const std::string& protocol,
|
||||
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_type(candidate_type);
|
||||
candidate->set_priority(priority);
|
||||
return candidate;
|
||||
}
|
||||
|
||||
class RTCStatsCollectorTestHelper : public SetSessionDescriptionObserver {
|
||||
public:
|
||||
RTCStatsCollectorTestHelper()
|
||||
@ -111,6 +127,10 @@ class RTCStatsCollectorTestHelper : public SetSessionDescriptionObserver {
|
||||
EXPECT_CALL(pc_, sctp_data_channels()).WillRepeatedly(
|
||||
ReturnRef(data_channels_));
|
||||
EXPECT_CALL(session_, GetTransportStats(_)).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(session_, GetLocalCertificate(_, _)).WillRepeatedly(
|
||||
Return(false));
|
||||
EXPECT_CALL(session_, GetRemoteSSLCertificate_ReturnsRawPointer(_))
|
||||
.WillRepeatedly(Return(nullptr));
|
||||
}
|
||||
|
||||
rtc::ScopedFakeClock& fake_clock() { return fake_clock_; }
|
||||
@ -308,6 +328,30 @@ class RTCStatsCollectorTest : public testing::Test {
|
||||
return callback->report();
|
||||
}
|
||||
|
||||
void ExpectReportContainsCandidate(
|
||||
const rtc::scoped_refptr<const RTCStatsReport>& report,
|
||||
const cricket::Candidate& candidate,
|
||||
bool is_local) {
|
||||
const RTCStats* stats =
|
||||
report->Get("RTCIceCandidate_" + candidate.id());
|
||||
EXPECT_TRUE(stats);
|
||||
const RTCIceCandidateStats* candidate_stats;
|
||||
if (is_local)
|
||||
candidate_stats = &stats->cast_to<RTCLocalIceCandidateStats>();
|
||||
else
|
||||
candidate_stats = &stats->cast_to<RTCRemoteIceCandidateStats>();
|
||||
EXPECT_EQ(*candidate_stats->ip, candidate.address().ipaddr().ToString());
|
||||
EXPECT_EQ(*candidate_stats->port,
|
||||
static_cast<int32_t>(candidate.address().port()));
|
||||
EXPECT_EQ(*candidate_stats->protocol, candidate.protocol());
|
||||
EXPECT_EQ(*candidate_stats->candidate_type,
|
||||
CandidateTypeToRTCIceCandidateType(candidate.type()));
|
||||
EXPECT_EQ(*candidate_stats->priority,
|
||||
static_cast<int32_t>(candidate.priority()));
|
||||
// TODO(hbos): Define candidate_stats->url. crbug.com/632723
|
||||
EXPECT_FALSE(candidate_stats->url.is_defined());
|
||||
}
|
||||
|
||||
void ExpectReportContainsCertificateInfo(
|
||||
const rtc::scoped_refptr<const RTCStatsReport>& report,
|
||||
const CertificateInfo& cert_info) {
|
||||
@ -534,6 +578,84 @@ TEST_F(RTCStatsCollectorTest, CollectRTCCertificateStatsChain) {
|
||||
ExpectReportContainsCertificateInfo(report, *remote_certinfo.get());
|
||||
}
|
||||
|
||||
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_remote_srflx = CreateFakeCandidate(
|
||||
"6.7.8.9", 10,
|
||||
"remote_srflx's protocol",
|
||||
cricket::STUN_PORT_TYPE,
|
||||
1);
|
||||
std::unique_ptr<cricket::Candidate> a_local_prflx = CreateFakeCandidate(
|
||||
"11.12.13.14", 15,
|
||||
"a_local_prflx's protocol",
|
||||
cricket::PRFLX_PORT_TYPE,
|
||||
2);
|
||||
std::unique_ptr<cricket::Candidate> a_remote_relay = CreateFakeCandidate(
|
||||
"16.17.18.19", 20,
|
||||
"a_remote_relay's protocol",
|
||||
cricket::RELAY_PORT_TYPE,
|
||||
3);
|
||||
// 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_remote = CreateFakeCandidate(
|
||||
"42.42.42.42", 42,
|
||||
"b_remote's protocol",
|
||||
cricket::LOCAL_PORT_TYPE,
|
||||
42);
|
||||
|
||||
SessionStats session_stats;
|
||||
|
||||
cricket::TransportChannelStats a_transport_channel_stats;
|
||||
a_transport_channel_stats.connection_infos.push_back(
|
||||
cricket::ConnectionInfo());
|
||||
a_transport_channel_stats.connection_infos[0].local_candidate =
|
||||
*a_local_host.get();
|
||||
a_transport_channel_stats.connection_infos[0].remote_candidate =
|
||||
*a_remote_srflx.get();
|
||||
a_transport_channel_stats.connection_infos.push_back(
|
||||
cricket::ConnectionInfo());
|
||||
a_transport_channel_stats.connection_infos[1].local_candidate =
|
||||
*a_local_prflx.get();
|
||||
a_transport_channel_stats.connection_infos[1].remote_candidate =
|
||||
*a_remote_relay.get();
|
||||
session_stats.transport_stats["a"].channel_stats.push_back(
|
||||
a_transport_channel_stats);
|
||||
|
||||
cricket::TransportChannelStats b_transport_channel_stats;
|
||||
b_transport_channel_stats.connection_infos.push_back(
|
||||
cricket::ConnectionInfo());
|
||||
b_transport_channel_stats.connection_infos[0].local_candidate =
|
||||
*b_local.get();
|
||||
b_transport_channel_stats.connection_infos[0].remote_candidate =
|
||||
*b_remote.get();
|
||||
session_stats.transport_stats["b"].channel_stats.push_back(
|
||||
b_transport_channel_stats);
|
||||
|
||||
// Mock the session to return the desired candidates.
|
||||
EXPECT_CALL(test_->session(), GetTransportStats(_)).WillRepeatedly(Invoke(
|
||||
[this, &session_stats](SessionStats* stats) {
|
||||
*stats = session_stats;
|
||||
return true;
|
||||
}));
|
||||
|
||||
rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
|
||||
ExpectReportContainsCandidate(report, *a_local_host.get(), true);
|
||||
ExpectReportContainsCandidate(report, *a_remote_srflx.get(), false);
|
||||
ExpectReportContainsCandidate(report, *a_local_prflx.get(), true);
|
||||
ExpectReportContainsCandidate(report, *a_remote_relay.get(), false);
|
||||
ExpectReportContainsCandidate(report, *b_local.get(), true);
|
||||
ExpectReportContainsCandidate(report, *b_remote.get(), false);
|
||||
}
|
||||
|
||||
TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
|
||||
int64_t before = rtc::TimeUTCMicros();
|
||||
rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
|
||||
|
||||
@ -17,8 +17,57 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// https://www.w3.org/TR/webrtc/#rtcicecandidatetype-enum
|
||||
struct RTCIceCandidateType {
|
||||
static const char* kHost;
|
||||
static const char* kSrflx;
|
||||
static const char* kPrflx;
|
||||
static const char* kRelay;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webrtc-stats/#icecandidate-dict*
|
||||
class RTCIceCandidateStats : public RTCStats {
|
||||
public:
|
||||
WEBRTC_RTCSTATS_DECL();
|
||||
|
||||
RTCIceCandidateStats(const RTCIceCandidateStats& other);
|
||||
~RTCIceCandidateStats() override;
|
||||
|
||||
RTCStatsMember<std::string> ip;
|
||||
RTCStatsMember<int32_t> port;
|
||||
RTCStatsMember<std::string> protocol;
|
||||
// TODO(hbos): Support enum types? "RTCStatsMember<RTCIceCandidateType>"?
|
||||
RTCStatsMember<std::string> candidate_type;
|
||||
RTCStatsMember<int32_t> priority;
|
||||
RTCStatsMember<std::string> url;
|
||||
|
||||
protected:
|
||||
RTCIceCandidateStats(const std::string& id, int64_t timestamp_us);
|
||||
RTCIceCandidateStats(std::string&& id, int64_t timestamp_us);
|
||||
};
|
||||
|
||||
// In the spec both local and remote varieties are of type RTCIceCandidateStats.
|
||||
// But here we define them as subclasses of |RTCIceCandidateStats| because the
|
||||
// |kType| need to be different ("RTCStatsType type") in the local/remote case.
|
||||
// https://w3c.github.io/webrtc-stats/#rtcstatstype-str*
|
||||
class RTCLocalIceCandidateStats final : public RTCIceCandidateStats {
|
||||
public:
|
||||
static const char kType[];
|
||||
RTCLocalIceCandidateStats(const std::string& id, int64_t timestamp_us);
|
||||
RTCLocalIceCandidateStats(std::string&& id, int64_t timestamp_us);
|
||||
const char* type() const override;
|
||||
};
|
||||
|
||||
class RTCRemoteIceCandidateStats final : public RTCIceCandidateStats {
|
||||
public:
|
||||
static const char kType[];
|
||||
RTCRemoteIceCandidateStats(const std::string& id, int64_t timestamp_us);
|
||||
RTCRemoteIceCandidateStats(std::string&& id, int64_t timestamp_us);
|
||||
const char* type() const override;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webrtc-stats/#certificatestats-dict*
|
||||
class RTCCertificateStats : public RTCStats {
|
||||
class RTCCertificateStats final : public RTCStats {
|
||||
public:
|
||||
WEBRTC_RTCSTATS_DECL();
|
||||
|
||||
@ -35,7 +84,7 @@ class RTCCertificateStats : public RTCStats {
|
||||
|
||||
// https://w3c.github.io/webrtc-stats/#pcstats-dict*
|
||||
// TODO(hbos): Tracking bug crbug.com/636818
|
||||
class RTCPeerConnectionStats : public RTCStats {
|
||||
class RTCPeerConnectionStats final : public RTCStats {
|
||||
public:
|
||||
WEBRTC_RTCSTATS_DECL();
|
||||
|
||||
|
||||
@ -12,6 +12,80 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const char* RTCIceCandidateType::kHost = "host";
|
||||
const char* RTCIceCandidateType::kSrflx = "srflx";
|
||||
const char* RTCIceCandidateType::kPrflx = "prflx";
|
||||
const char* RTCIceCandidateType::kRelay = "relay";
|
||||
|
||||
WEBRTC_RTCSTATS_IMPL(RTCIceCandidateStats, RTCStats, "ice-candidate",
|
||||
&ip,
|
||||
&port,
|
||||
&protocol,
|
||||
&candidate_type,
|
||||
&priority,
|
||||
&url);
|
||||
|
||||
RTCIceCandidateStats::RTCIceCandidateStats(
|
||||
const std::string& id, int64_t timestamp_us)
|
||||
: RTCIceCandidateStats(std::string(id), timestamp_us) {
|
||||
}
|
||||
|
||||
RTCIceCandidateStats::RTCIceCandidateStats(
|
||||
std::string&& id, int64_t timestamp_us)
|
||||
: RTCStats(std::move(id), timestamp_us),
|
||||
ip("ip"),
|
||||
port("port"),
|
||||
protocol("protocol"),
|
||||
candidate_type("candidateType"),
|
||||
priority("priority"),
|
||||
url("url") {
|
||||
}
|
||||
|
||||
RTCIceCandidateStats::RTCIceCandidateStats(const RTCIceCandidateStats& other)
|
||||
: RTCStats(other.id(), other.timestamp_us()),
|
||||
ip(other.ip),
|
||||
port(other.port),
|
||||
protocol(other.protocol),
|
||||
candidate_type(other.candidate_type),
|
||||
priority(other.priority),
|
||||
url(other.url) {
|
||||
}
|
||||
|
||||
RTCIceCandidateStats::~RTCIceCandidateStats() {
|
||||
}
|
||||
|
||||
const char RTCLocalIceCandidateStats::kType[] = "local-candidate";
|
||||
|
||||
RTCLocalIceCandidateStats::RTCLocalIceCandidateStats(
|
||||
const std::string& id, int64_t timestamp_us)
|
||||
: RTCIceCandidateStats(id, timestamp_us) {
|
||||
}
|
||||
|
||||
RTCLocalIceCandidateStats::RTCLocalIceCandidateStats(
|
||||
std::string&& id, int64_t timestamp_us)
|
||||
: RTCIceCandidateStats(std::move(id), timestamp_us) {
|
||||
}
|
||||
|
||||
const char* RTCLocalIceCandidateStats::type() const {
|
||||
return kType;
|
||||
}
|
||||
|
||||
const char RTCRemoteIceCandidateStats::kType[] = "remote-candidate";
|
||||
|
||||
RTCRemoteIceCandidateStats::RTCRemoteIceCandidateStats(
|
||||
const std::string& id, int64_t timestamp_us)
|
||||
: RTCIceCandidateStats(id, timestamp_us) {
|
||||
}
|
||||
|
||||
RTCRemoteIceCandidateStats::RTCRemoteIceCandidateStats(
|
||||
std::string&& id, int64_t timestamp_us)
|
||||
: RTCIceCandidateStats(std::move(id), timestamp_us) {
|
||||
}
|
||||
|
||||
const char* RTCRemoteIceCandidateStats::type() const {
|
||||
return kType;
|
||||
}
|
||||
|
||||
WEBRTC_RTCSTATS_IMPL(RTCCertificateStats, RTCStats, "certificate",
|
||||
&fingerprint,
|
||||
&fingerprint_algorithm,
|
||||
|
||||
Reference in New Issue
Block a user