RTCIceCandidatePairStats[1] added.
Note: In this initial CL most stats members are missing. This needs to
be addressed before closing the RTCIceCandidatePairStats bug
(crbug.com/633550).
[1] https://w3c.github.io/webrtc-stats/#candidatepair-dict*
BUG=chromium:633550, chromium:627816
Review-Url: https://codereview.webrtc.org/2390693003
Cr-Commit-Position: refs/heads/master@{#14604}
diff --git a/webrtc/api/rtcstatscollector.cc b/webrtc/api/rtcstatscollector.cc
index 2d858c0..5f60ea1 100644
--- a/webrtc/api/rtcstatscollector.cc
+++ b/webrtc/api/rtcstatscollector.cc
@@ -180,16 +180,16 @@
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& transport_stats : session_stats.transport_stats) {
rtc::scoped_refptr<rtc::RTCCertificate> local_certificate;
if (pc_->session()->GetLocalCertificate(
- transport.second.transport_name, &local_certificate)) {
+ transport_stats.second.transport_name, &local_certificate)) {
ProduceCertificateStatsFromSSLCertificateAndChain_s(
timestamp_us, local_certificate->ssl_certificate(), report);
}
std::unique_ptr<rtc::SSLCertificate> remote_certificate =
pc_->session()->GetRemoteSSLCertificate(
- transport.second.transport_name);
+ transport_stats.second.transport_name);
if (remote_certificate) {
ProduceCertificateStatsFromSSLCertificateAndChain_s(
timestamp_us, *remote_certificate.get(), report);
@@ -222,19 +222,65 @@
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
+ for (const auto& transport_stats : session_stats.transport_stats) {
+ for (const auto& channel_stats : transport_stats.second.channel_stats) {
+ for (const cricket::ConnectionInfo& info :
+ channel_stats.connection_infos) {
+ const std::string& id = "RTCIceCandidatePair_" +
+ info.local_candidate.id() + "_" + info.remote_candidate.id();
+ std::unique_ptr<RTCIceCandidatePairStats> candidate_pair_stats(
+ new RTCIceCandidatePairStats(id, timestamp_us));
+
+ // TODO(hbos): Set all of the |RTCIceCandidatePairStats|'s members,
+ // crbug.com/633550.
+
+ // TODO(hbos): Set candidate_pair_stats->transport_id. Should be ID to
+ // RTCTransportStats which does not exist yet: crbug.com/653873.
+
// 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(
+ candidate_pair_stats->local_candidate_id = ProduceIceCandidateStats_s(
timestamp_us, info.local_candidate, true, report);
- ProduceIceCandidateStats_s(
+ candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats_s(
timestamp_us, info.remote_candidate, false, report);
+
+ // TODO(hbos): Set candidate_pair_stats->state.
+ // TODO(hbos): Set candidate_pair_stats->priority.
+ // TODO(hbos): Set candidate_pair_stats->nominated.
+ // TODO(hbos): This writable is different than the spec. It goes to
+ // false after a certain amount of time without a response passes.
+ // crbug.com/633550
+ candidate_pair_stats->writable = info.writable;
+ // TODO(hbos): Set candidate_pair_stats->readable.
+ candidate_pair_stats->bytes_sent =
+ static_cast<uint64_t>(info.sent_total_bytes);
+ candidate_pair_stats->bytes_received =
+ static_cast<uint64_t>(info.recv_total_bytes);
+ // TODO(hbos): Set candidate_pair_stats->total_rtt.
+ // TODO(hbos): The |info.rtt| measurement is smoothed. It shouldn't be
+ // smoothed according to the spec. crbug.com/633550. See
+ // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-currentrtt
+ candidate_pair_stats->current_rtt =
+ static_cast<double>(info.rtt) / 1000.0;
+ // TODO(hbos): Set candidate_pair_stats->available_outgoing_bitrate.
+ // TODO(hbos): Set candidate_pair_stats->available_incoming_bitrate.
+ // TODO(hbos): Set candidate_pair_stats->requests_received.
+ candidate_pair_stats->requests_sent =
+ static_cast<uint64_t>(info.sent_ping_requests_total);
+ candidate_pair_stats->responses_received =
+ static_cast<uint64_t>(info.recv_ping_responses);
+ candidate_pair_stats->responses_sent =
+ static_cast<uint64_t>(info.sent_ping_responses);
+ // TODO(hbos): Set candidate_pair_stats->retransmissions_received.
+ // TODO(hbos): Set candidate_pair_stats->retransmissions_sent.
+ // TODO(hbos): Set candidate_pair_stats->consent_requests_received.
+ // TODO(hbos): Set candidate_pair_stats->consent_requests_sent.
+ // TODO(hbos): Set candidate_pair_stats->consent_responses_received.
+ // TODO(hbos): Set candidate_pair_stats->consent_responses_sent.
+
+ report->AddStats(std::move(candidate_pair_stats));
}
}
}
@@ -248,13 +294,10 @@
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));
- }
+ 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();
diff --git a/webrtc/api/rtcstatscollector.h b/webrtc/api/rtcstatscollector.h
index 6443d13..712f9e2 100644
--- a/webrtc/api/rtcstatscollector.h
+++ b/webrtc/api/rtcstatscollector.h
@@ -85,8 +85,7 @@
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
+ // Produces |RTCIceCandidatePairStats| and |RTCIceCandidateStats|.
void ProduceIceCandidateAndPairStats_s(
int64_t timestamp_us, const SessionStats& session_stats,
RTCStatsReport* report) const;
diff --git a/webrtc/api/rtcstatscollector_unittest.cc b/webrtc/api/rtcstatscollector_unittest.cc
index 0da772f..c8eed9f 100644
--- a/webrtc/api/rtcstatscollector_unittest.cc
+++ b/webrtc/api/rtcstatscollector_unittest.cc
@@ -331,12 +331,11 @@
return callback->report();
}
- void ExpectReportContainsCandidate(
+ const RTCIceCandidateStats* ExpectReportContainsCandidate(
const rtc::scoped_refptr<const RTCStatsReport>& report,
const cricket::Candidate& candidate,
bool is_local) {
- const RTCStats* stats =
- report->Get("RTCIceCandidate_" + candidate.id());
+ const RTCStats* stats = report->Get("RTCIceCandidate_" + candidate.id());
EXPECT_TRUE(stats);
const RTCIceCandidateStats* candidate_stats;
if (is_local)
@@ -353,6 +352,69 @@
static_cast<int32_t>(candidate.priority()));
// TODO(hbos): Define candidate_stats->url. crbug.com/632723
EXPECT_FALSE(candidate_stats->url.is_defined());
+ return candidate_stats;
+ }
+
+ void ExpectReportContainsCandidatePair(
+ const rtc::scoped_refptr<const RTCStatsReport>& report,
+ const cricket::TransportStats& transport_stats) {
+ for (const auto& channel_stats : transport_stats.channel_stats) {
+ for (const cricket::ConnectionInfo& info :
+ channel_stats.connection_infos) {
+ const std::string& id = "RTCIceCandidatePair_" +
+ info.local_candidate.id() + "_" + info.remote_candidate.id();
+ const RTCStats* stats = report->Get(id);
+ EXPECT_TRUE(stats);
+ const RTCIceCandidatePairStats& candidate_pair_stats =
+ stats->cast_to<RTCIceCandidatePairStats>();
+
+ // TODO(hbos): Define all the undefined |candidate_pair_stats| stats.
+ // The EXPECT_FALSE are for the undefined stats, see also todos listed
+ // in rtcstatscollector.cc. crbug.com/633550
+ EXPECT_FALSE(candidate_pair_stats.transport_id.is_defined());
+ const RTCIceCandidateStats* local_candidate =
+ ExpectReportContainsCandidate(report, info.local_candidate, true);
+ EXPECT_EQ(*candidate_pair_stats.local_candidate_id,
+ local_candidate->id());
+ const RTCIceCandidateStats* remote_candidate =
+ ExpectReportContainsCandidate(report, info.remote_candidate, false);
+ EXPECT_EQ(*candidate_pair_stats.remote_candidate_id,
+ remote_candidate->id());
+
+ EXPECT_FALSE(candidate_pair_stats.state.is_defined());
+ EXPECT_FALSE(candidate_pair_stats.priority.is_defined());
+ EXPECT_FALSE(candidate_pair_stats.nominated.is_defined());
+ EXPECT_EQ(*candidate_pair_stats.writable, info.writable);
+ EXPECT_FALSE(candidate_pair_stats.readable.is_defined());
+ EXPECT_EQ(*candidate_pair_stats.bytes_sent,
+ static_cast<uint64_t>(info.sent_total_bytes));
+ EXPECT_EQ(*candidate_pair_stats.bytes_received,
+ static_cast<uint64_t>(info.recv_total_bytes));
+ EXPECT_FALSE(candidate_pair_stats.total_rtt.is_defined());
+ EXPECT_EQ(*candidate_pair_stats.current_rtt,
+ static_cast<double>(info.rtt) / 1000.0);
+ EXPECT_FALSE(
+ candidate_pair_stats.available_outgoing_bitrate.is_defined());
+ EXPECT_FALSE(
+ candidate_pair_stats.available_incoming_bitrate.is_defined());
+ EXPECT_FALSE(candidate_pair_stats.requests_received.is_defined());
+ EXPECT_EQ(*candidate_pair_stats.requests_sent,
+ static_cast<uint64_t>(info.sent_ping_requests_total));
+ EXPECT_EQ(*candidate_pair_stats.responses_received,
+ static_cast<uint64_t>(info.recv_ping_responses));
+ EXPECT_EQ(*candidate_pair_stats.responses_sent,
+ static_cast<uint64_t>(info.sent_ping_responses));
+ EXPECT_FALSE(
+ candidate_pair_stats.retransmissions_received.is_defined());
+ EXPECT_FALSE(candidate_pair_stats.retransmissions_sent.is_defined());
+ EXPECT_FALSE(
+ candidate_pair_stats.consent_requests_received.is_defined());
+ EXPECT_FALSE(candidate_pair_stats.consent_requests_sent.is_defined());
+ EXPECT_FALSE(
+ candidate_pair_stats.consent_responses_received.is_defined());
+ EXPECT_FALSE(candidate_pair_stats.consent_responses_sent.is_defined());
+ }
+ }
}
void ExpectReportContainsCertificateInfo(
@@ -659,6 +721,43 @@
ExpectReportContainsCandidate(report, *b_remote.get(), false);
}
+TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
+ std::unique_ptr<cricket::Candidate> local_candidate = CreateFakeCandidate(
+ "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
+ std::unique_ptr<cricket::Candidate> remote_candidate = CreateFakeCandidate(
+ "42.42.42.42", 42, "protocol", cricket::LOCAL_PORT_TYPE, 42);
+
+ SessionStats session_stats;
+
+ cricket::ConnectionInfo connection_info;
+ connection_info.local_candidate = *local_candidate.get();
+ connection_info.remote_candidate = *remote_candidate.get();
+ connection_info.writable = true;
+ connection_info.sent_total_bytes = 42;
+ connection_info.recv_total_bytes = 1234;
+ connection_info.rtt = 1337;
+ connection_info.sent_ping_requests_total = 1010;
+ connection_info.recv_ping_responses = 4321;
+ connection_info.sent_ping_responses = 1000;
+
+ cricket::TransportChannelStats transport_channel_stats;
+ transport_channel_stats.connection_infos.push_back(connection_info);
+ session_stats.transport_stats["transport"].transport_name = "transport";
+ session_stats.transport_stats["transport"].channel_stats.push_back(
+ 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();
+ ExpectReportContainsCandidatePair(
+ report, session_stats.transport_stats["transport"]);
+}
+
TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
int64_t before = rtc::TimeUTCMicros();
rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
diff --git a/webrtc/api/stats/rtcstats_objects.h b/webrtc/api/stats/rtcstats_objects.h
index e827d01..4738fe8 100644
--- a/webrtc/api/stats/rtcstats_objects.h
+++ b/webrtc/api/stats/rtcstats_objects.h
@@ -17,6 +17,16 @@
namespace webrtc {
+// https://w3c.github.io/webrtc-stats/#dom-rtcstatsicecandidatepairstate
+struct RTCStatsIceCandidatePairState {
+ static const char* kFrozen;
+ static const char* kWaiting;
+ static const char* kInProgress;
+ static const char* kFailed;
+ static const char* kSucceeded;
+ static const char* kCancelled;
+};
+
// https://www.w3.org/TR/webrtc/#rtcicecandidatetype-enum
struct RTCIceCandidateType {
static const char* kHost;
@@ -25,6 +35,43 @@
static const char* kRelay;
};
+class RTCIceCandidatePairStats : public RTCStats {
+ public:
+ WEBRTC_RTCSTATS_DECL();
+
+ RTCIceCandidatePairStats(const std::string& id, int64_t timestamp_us);
+ RTCIceCandidatePairStats(std::string&& id, int64_t timestamp_us);
+ RTCIceCandidatePairStats(const RTCIceCandidatePairStats& other);
+ ~RTCIceCandidatePairStats() override;
+
+ RTCStatsMember<std::string> transport_id;
+ RTCStatsMember<std::string> local_candidate_id;
+ RTCStatsMember<std::string> remote_candidate_id;
+ // TODO(hbos): Support enum types?
+ // "RTCStatsMember<RTCStatsIceCandidatePairState>"?
+ RTCStatsMember<std::string> state;
+ RTCStatsMember<uint64_t> priority;
+ RTCStatsMember<bool> nominated;
+ RTCStatsMember<bool> writable;
+ RTCStatsMember<bool> readable;
+ RTCStatsMember<uint64_t> bytes_sent;
+ RTCStatsMember<uint64_t> bytes_received;
+ RTCStatsMember<double> total_rtt;
+ RTCStatsMember<double> current_rtt;
+ RTCStatsMember<double> available_outgoing_bitrate;
+ RTCStatsMember<double> available_incoming_bitrate;
+ RTCStatsMember<uint64_t> requests_received;
+ RTCStatsMember<uint64_t> requests_sent;
+ RTCStatsMember<uint64_t> responses_received;
+ RTCStatsMember<uint64_t> responses_sent;
+ RTCStatsMember<uint64_t> retransmissions_received;
+ RTCStatsMember<uint64_t> retransmissions_sent;
+ RTCStatsMember<uint64_t> consent_requests_received;
+ RTCStatsMember<uint64_t> consent_requests_sent;
+ RTCStatsMember<uint64_t> consent_responses_received;
+ RTCStatsMember<uint64_t> consent_responses_sent;
+};
+
// https://w3c.github.io/webrtc-stats/#icecandidate-dict*
class RTCIceCandidateStats : public RTCStats {
public: