RTCDataChannelStats[1] added, supporting all stats members.
Also updates MockDataChannel to also mock id, messages_sent, bytes_sent,
messages_received and bytes_received.
[1] https://w3c.github.io/webrtc-stats/#dcstats-dict*
BUG=chromium:654927, chromium:627816
Review-Url: https://codereview.webrtc.org/2420473002
Cr-Commit-Position: refs/heads/master@{#14670}
diff --git a/webrtc/api/rtcstatscollector.cc b/webrtc/api/rtcstatscollector.cc
index 5f60ea1..71f4725 100644
--- a/webrtc/api/rtcstatscollector.cc
+++ b/webrtc/api/rtcstatscollector.cc
@@ -23,6 +23,8 @@
namespace webrtc {
+namespace {
+
const char* CandidateTypeToRTCIceCandidateType(const std::string& type) {
if (type == cricket::LOCAL_PORT_TYPE)
return RTCIceCandidateType::kHost;
@@ -36,6 +38,25 @@
return nullptr;
}
+const char* DataStateToRTCDataChannelState(
+ DataChannelInterface::DataState state) {
+ switch (state) {
+ case DataChannelInterface::kConnecting:
+ return RTCDataChannelState::kConnecting;
+ case DataChannelInterface::kOpen:
+ return RTCDataChannelState::kOpen;
+ case DataChannelInterface::kClosing:
+ return RTCDataChannelState::kClosing;
+ case DataChannelInterface::kClosed:
+ return RTCDataChannelState::kClosed;
+ default:
+ RTC_NOTREACHED();
+ return nullptr;
+ }
+}
+
+} // namespace
+
rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
PeerConnection* pc, int64_t cache_lifetime_us) {
return rtc::scoped_refptr<RTCStatsCollector>(
@@ -111,6 +132,7 @@
ProduceIceCandidateAndPairStats_s(timestamp_us, session_stats,
report.get());
}
+ ProduceDataChannelStats_s(timestamp_us, report.get());
ProducePeerConnectionStats_s(timestamp_us, report.get());
AddPartialResults(report);
@@ -218,6 +240,28 @@
}
}
+void RTCStatsCollector::ProduceDataChannelStats_s(
+ int64_t timestamp_us, RTCStatsReport* report) const {
+ RTC_DCHECK(signaling_thread_->IsCurrent());
+ for (const rtc::scoped_refptr<DataChannel>& data_channel :
+ pc_->sctp_data_channels()) {
+ std::unique_ptr<RTCDataChannelStats> data_channel_stats(
+ new RTCDataChannelStats(
+ "RTCDataChannel_" + rtc::ToString<>(data_channel->id()),
+ timestamp_us));
+ data_channel_stats->label = data_channel->label();
+ data_channel_stats->protocol = data_channel->protocol();
+ data_channel_stats->datachannelid = data_channel->id();
+ data_channel_stats->state =
+ DataStateToRTCDataChannelState(data_channel->state());
+ data_channel_stats->messages_sent = data_channel->messages_sent();
+ data_channel_stats->bytes_sent = data_channel->bytes_sent();
+ data_channel_stats->messages_received = data_channel->messages_received();
+ data_channel_stats->bytes_received = data_channel->bytes_received();
+ report->AddStats(std::move(data_channel_stats));
+ }
+}
+
void RTCStatsCollector::ProduceIceCandidateAndPairStats_s(
int64_t timestamp_us, const SessionStats& session_stats,
RTCStatsReport* report) const {
@@ -337,4 +381,14 @@
report->AddStats(std::move(stats));
}
+const char* CandidateTypeToRTCIceCandidateTypeForTesting(
+ const std::string& type) {
+ return CandidateTypeToRTCIceCandidateType(type);
+}
+
+const char* DataStateToRTCDataChannelStateForTesting(
+ DataChannelInterface::DataState state) {
+ return DataStateToRTCDataChannelState(state);
+}
+
} // namespace webrtc
diff --git a/webrtc/api/rtcstatscollector.h b/webrtc/api/rtcstatscollector.h
index 712f9e2..ae04e61 100644
--- a/webrtc/api/rtcstatscollector.h
+++ b/webrtc/api/rtcstatscollector.h
@@ -14,6 +14,7 @@
#include <memory>
#include <vector>
+#include "webrtc/api/datachannelinterface.h"
#include "webrtc/api/stats/rtcstats_objects.h"
#include "webrtc/api/stats/rtcstatsreport.h"
#include "webrtc/base/asyncinvoker.h"
@@ -85,6 +86,9 @@
void ProduceCertificateStatsFromSSLCertificateAndChain_s(
int64_t timestamp_us, const rtc::SSLCertificate& certificate,
RTCStatsReport* report) const;
+ // Produces |RTCDataChannelStats|.
+ void ProduceDataChannelStats_s(
+ int64_t timestamp_us, RTCStatsReport* report) const;
// Produces |RTCIceCandidatePairStats| and |RTCIceCandidateStats|.
void ProduceIceCandidateAndPairStats_s(
int64_t timestamp_us, const SessionStats& session_stats,
@@ -116,8 +120,10 @@
rtc::scoped_refptr<const RTCStatsReport> cached_report_;
};
-// Helper function, exposed for unittests.
-const char* CandidateTypeToRTCIceCandidateType(const std::string& type);
+const char* CandidateTypeToRTCIceCandidateTypeForTesting(
+ const std::string& type);
+const char* DataStateToRTCDataChannelStateForTesting(
+ DataChannelInterface::DataState state);
} // namespace webrtc
diff --git a/webrtc/api/rtcstatscollector_unittest.cc b/webrtc/api/rtcstatscollector_unittest.cc
index c8eed9f..fb07e0b 100644
--- a/webrtc/api/rtcstatscollector_unittest.cc
+++ b/webrtc/api/rtcstatscollector_unittest.cc
@@ -328,6 +328,10 @@
rtc::scoped_refptr<StatsCallback> callback = StatsCallback::Create();
collector_->GetStatsReport(callback);
EXPECT_TRUE_WAIT(callback->report(), kGetStatsReportTimeoutMs);
+ int64_t after = rtc::TimeUTCMicros();
+ for (const RTCStats& stats : *callback->report()) {
+ EXPECT_LE(stats.timestamp_us(), after);
+ }
return callback->report();
}
@@ -347,7 +351,7 @@
static_cast<int32_t>(candidate.address().port()));
EXPECT_EQ(*candidate_stats->protocol, candidate.protocol());
EXPECT_EQ(*candidate_stats->candidate_type,
- CandidateTypeToRTCIceCandidateType(candidate.type()));
+ CandidateTypeToRTCIceCandidateTypeForTesting(candidate.type()));
EXPECT_EQ(*candidate_stats->priority,
static_cast<int32_t>(candidate.priority()));
// TODO(hbos): Define candidate_stats->url. crbug.com/632723
@@ -438,6 +442,27 @@
}
}
+ void ExpectReportContainsDataChannel(
+ const rtc::scoped_refptr<const RTCStatsReport>& report,
+ const DataChannel& data_channel) {
+ const RTCStats* stats = report->Get("RTCDataChannel_" +
+ rtc::ToString<>(data_channel.id()));
+ EXPECT_TRUE(stats);
+ const RTCDataChannelStats& data_channel_stats =
+ stats->cast_to<const RTCDataChannelStats>();
+ EXPECT_EQ(*data_channel_stats.label, data_channel.label());
+ EXPECT_EQ(*data_channel_stats.protocol, data_channel.protocol());
+ EXPECT_EQ(*data_channel_stats.datachannelid, data_channel.id());
+ EXPECT_EQ(*data_channel_stats.state,
+ DataStateToRTCDataChannelStateForTesting(data_channel.state()));
+ EXPECT_EQ(*data_channel_stats.messages_sent, data_channel.messages_sent());
+ EXPECT_EQ(*data_channel_stats.bytes_sent, data_channel.bytes_sent());
+ EXPECT_EQ(*data_channel_stats.messages_received,
+ data_channel.messages_received());
+ EXPECT_EQ(*data_channel_stats.bytes_received,
+ data_channel.bytes_received());
+ }
+
protected:
rtc::scoped_refptr<RTCStatsCollectorTestHelper> test_;
rtc::scoped_refptr<RTCStatsCollector> collector_;
@@ -643,6 +668,44 @@
ExpectReportContainsCertificateInfo(report, *remote_certinfo.get());
}
+TEST_F(RTCStatsCollectorTest, CollectRTCDataChannelStats) {
+ test_->data_channels().push_back(
+ new MockDataChannel(0, DataChannelInterface::kConnecting));
+ test_->data_channels().push_back(
+ new MockDataChannel(1, DataChannelInterface::kOpen));
+ test_->data_channels().push_back(
+ new MockDataChannel(2, DataChannelInterface::kClosing));
+ test_->data_channels().push_back(
+ new MockDataChannel(3, DataChannelInterface::kClosed));
+
+ rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
+ ExpectReportContainsDataChannel(report, *test_->data_channels()[0]);
+ ExpectReportContainsDataChannel(report, *test_->data_channels()[1]);
+ ExpectReportContainsDataChannel(report, *test_->data_channels()[2]);
+ ExpectReportContainsDataChannel(report, *test_->data_channels()[3]);
+
+ test_->data_channels().clear();
+ test_->data_channels().push_back(
+ new MockDataChannel(0, DataChannelInterface::kConnecting,
+ 1, 2, 3, 4));
+ test_->data_channels().push_back(
+ new MockDataChannel(1, DataChannelInterface::kOpen,
+ 5, 6, 7, 8));
+ test_->data_channels().push_back(
+ new MockDataChannel(2, DataChannelInterface::kClosing,
+ 9, 10, 11, 12));
+ test_->data_channels().push_back(
+ new MockDataChannel(3, DataChannelInterface::kClosed,
+ 13, 14, 15, 16));
+
+ collector_->ClearCachedStatsReport();
+ report = GetStatsReport();
+ ExpectReportContainsDataChannel(report, *test_->data_channels()[0]);
+ ExpectReportContainsDataChannel(report, *test_->data_channels()[1]);
+ ExpectReportContainsDataChannel(report, *test_->data_channels()[2]);
+ ExpectReportContainsDataChannel(report, *test_->data_channels()[3]);
+}
+
TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidateStats) {
// Candidates in the first transport stats.
std::unique_ptr<cricket::Candidate> a_local_host = CreateFakeCandidate(
@@ -759,15 +822,11 @@
}
TEST_F(RTCStatsCollectorTest, CollectRTCPeerConnectionStats) {
- int64_t before = rtc::TimeUTCMicros();
rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
- int64_t after = rtc::TimeUTCMicros();
EXPECT_EQ(report->GetStatsOfType<RTCPeerConnectionStats>().size(),
static_cast<size_t>(1)) << "Expecting 1 RTCPeerConnectionStats.";
const RTCStats* stats = report->Get("RTCPeerConnection");
EXPECT_TRUE(stats);
- EXPECT_LE(before, stats->timestamp_us());
- EXPECT_LE(stats->timestamp_us(), after);
{
// Expected stats with no data channels
const RTCPeerConnectionStats& pcstats =
@@ -777,13 +836,13 @@
}
test_->data_channels().push_back(
- new MockDataChannel(DataChannelInterface::kConnecting));
+ new MockDataChannel(0, DataChannelInterface::kConnecting));
test_->data_channels().push_back(
- new MockDataChannel(DataChannelInterface::kOpen));
+ new MockDataChannel(1, DataChannelInterface::kOpen));
test_->data_channels().push_back(
- new MockDataChannel(DataChannelInterface::kClosing));
+ new MockDataChannel(2, DataChannelInterface::kClosing));
test_->data_channels().push_back(
- new MockDataChannel(DataChannelInterface::kClosed));
+ new MockDataChannel(3, DataChannelInterface::kClosed));
collector_->ClearCachedStatsReport();
report = GetStatsReport();
diff --git a/webrtc/api/stats/rtcstats_objects.h b/webrtc/api/stats/rtcstats_objects.h
index 4738fe8..ad6a39c 100644
--- a/webrtc/api/stats/rtcstats_objects.h
+++ b/webrtc/api/stats/rtcstats_objects.h
@@ -17,6 +17,14 @@
namespace webrtc {
+// https://w3c.github.io/webrtc-pc/#idl-def-rtcdatachannelstate
+struct RTCDataChannelState {
+ static const char* kConnecting;
+ static const char* kOpen;
+ static const char* kClosing;
+ static const char* kClosed;
+};
+
// https://w3c.github.io/webrtc-stats/#dom-rtcstatsicecandidatepairstate
struct RTCStatsIceCandidatePairState {
static const char* kFrozen;
@@ -27,7 +35,7 @@
static const char* kCancelled;
};
-// https://www.w3.org/TR/webrtc/#rtcicecandidatetype-enum
+// https://w3c.github.io/webrtc-pc/#rtcicecandidatetype-enum
struct RTCIceCandidateType {
static const char* kHost;
static const char* kSrflx;
@@ -129,6 +137,27 @@
RTCStatsMember<std::string> issuer_certificate_id;
};
+// https://w3c.github.io/webrtc-stats/#dcstats-dict*
+class RTCDataChannelStats final : public RTCStats {
+ public:
+ WEBRTC_RTCSTATS_DECL();
+
+ RTCDataChannelStats(const std::string& id, int64_t timestamp_us);
+ RTCDataChannelStats(std::string&& id, int64_t timestamp_us);
+ RTCDataChannelStats(const RTCDataChannelStats& other);
+ ~RTCDataChannelStats() override;
+
+ RTCStatsMember<std::string> label;
+ RTCStatsMember<std::string> protocol;
+ RTCStatsMember<int32_t> datachannelid;
+ // TODO(hbos): Support enum types? "RTCStatsMember<RTCDataChannelState>"?
+ RTCStatsMember<std::string> state;
+ RTCStatsMember<uint32_t> messages_sent;
+ RTCStatsMember<uint64_t> bytes_sent;
+ RTCStatsMember<uint32_t> messages_received;
+ RTCStatsMember<uint64_t> bytes_received;
+};
+
// https://w3c.github.io/webrtc-stats/#pcstats-dict*
// TODO(hbos): Tracking bug crbug.com/636818
class RTCPeerConnectionStats final : public RTCStats {
diff --git a/webrtc/api/test/mock_datachannel.h b/webrtc/api/test/mock_datachannel.h
index a09964e..1bb3984 100644
--- a/webrtc/api/test/mock_datachannel.h
+++ b/webrtc/api/test/mock_datachannel.h
@@ -18,12 +18,35 @@
class MockDataChannel : public rtc::RefCountedObject<DataChannel> {
public:
- explicit MockDataChannel(DataState state)
+ MockDataChannel(int id, DataState state)
+ : MockDataChannel(id, state, 0, 0, 0, 0) {
+ }
+ MockDataChannel(
+ int id,
+ DataState state,
+ uint32_t messages_sent,
+ uint64_t bytes_sent,
+ uint32_t messages_received,
+ uint64_t bytes_received)
: rtc::RefCountedObject<DataChannel>(
nullptr, cricket::DCT_NONE, "MockDataChannel") {
+ EXPECT_CALL(*this, id()).WillRepeatedly(testing::Return(id));
EXPECT_CALL(*this, state()).WillRepeatedly(testing::Return(state));
+ EXPECT_CALL(*this, messages_sent()).WillRepeatedly(
+ testing::Return(messages_sent));
+ EXPECT_CALL(*this, bytes_sent()).WillRepeatedly(
+ testing::Return(bytes_sent));
+ EXPECT_CALL(*this, messages_received()).WillRepeatedly(
+ testing::Return(messages_received));
+ EXPECT_CALL(*this, bytes_received()).WillRepeatedly(
+ testing::Return(bytes_received));
}
+ MOCK_CONST_METHOD0(id, int());
MOCK_CONST_METHOD0(state, DataState());
+ MOCK_CONST_METHOD0(messages_sent, uint32_t());
+ MOCK_CONST_METHOD0(bytes_sent, uint64_t());
+ MOCK_CONST_METHOD0(messages_received, uint32_t());
+ MOCK_CONST_METHOD0(bytes_received, uint64_t());
};
} // namespace webrtc