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:
hbos
2016-10-07 02:18:47 -07:00
committed by Commit bot
parent 3dcfd64c26
commit ab9f6e4dea
5 changed files with 334 additions and 4 deletions

View File

@ -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());

View File

@ -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_

View File

@ -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();

View File

@ -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();

View File

@ -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,