Collect packet loss and RTT stats of STUN binding requests.
STUN candidates use STUN binding requests to keep NAT bindings open.
Related stats including packet loss and RTT can be now collected via the
legacy GetStats in PeerConnection.
Bug: None
Change-Id: I7b0eee1ccb07eb670a32ee303c9590047b25f31c
Reviewed-on: https://webrtc-review.googlesource.com/54100
Commit-Queue: Qingsi Wang <qingsi@google.com>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22113}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index a052c17..8371543 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -183,6 +183,8 @@
// TODO(hbos): |RTCStatsCollector| only collects candidates that are part of
// ice candidate pairs, but there could be candidates not paired with anything.
// crbug.com/632723
+// TODO(qingsi): Add the stats of STUN binding requests (keepalives) and collect
+// them in the new PeerConnection::GetStats.
class RTCIceCandidateStats : public RTCStats {
public:
WEBRTC_RTCSTATS_DECL();
diff --git a/api/statstypes.cc b/api/statstypes.cc
index d1637e3..8a87265 100644
--- a/api/statstypes.cc
+++ b/api/statstypes.cc
@@ -430,7 +430,9 @@
case kStatsValueNameBandwidthLimitedResolution:
return "googBandwidthLimitedResolution";
// STUN ping related attributes.
+ //
// TODO(zhihuang) Rename these stats to follow the standards.
+ // Connectivity checks.
case kStatsValueNameSentPingRequestsTotal:
return "requestsSent";
case kStatsValueNameSentPingRequestsBeforeFirstResponse:
@@ -441,6 +443,15 @@
return "requestsReceived";
case kStatsValueNameRecvPingResponses:
return "responsesReceived";
+ // STUN Keepalive pings.
+ case kStatsValueNameSentStunKeepaliveRequests:
+ return "stunKeepaliveRequestsSent";
+ case kStatsValueNameRecvStunKeepaliveResponses:
+ return "stunKeepaliveResponsesReceived";
+ case kStatsValueNameStunKeepaliveRttTotal:
+ return "stunKeepaliveRttTotal";
+ case kStatsValueNameStunKeepaliveRttSquaredTotal:
+ return "stunKeepaliveRttSquaredTotal";
// Candidate related attributes. Values are taken from
// http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*.
diff --git a/api/statstypes.h b/api/statstypes.h
index 2ba8ba5..9dc6154 100644
--- a/api/statstypes.h
+++ b/api/statstypes.h
@@ -129,6 +129,10 @@
kStatsValueNameSentPingResponses,
kStatsValueNameRecvPingRequests,
kStatsValueNameRecvPingResponses,
+ kStatsValueNameSentStunKeepaliveRequests,
+ kStatsValueNameRecvStunKeepaliveResponses,
+ kStatsValueNameStunKeepaliveRttTotal,
+ kStatsValueNameStunKeepaliveRttSquaredTotal,
// Internal StatsValue names.
kStatsValueNameAccelerateRate,
diff --git a/p2p/base/fakeicetransport.h b/p2p/base/fakeicetransport.h
index 556a1cd..427481e 100644
--- a/p2p/base/fakeicetransport.h
+++ b/p2p/base/fakeicetransport.h
@@ -146,10 +146,14 @@
}
void RemoveRemoteCandidate(const Candidate& candidate) override {}
- bool GetStats(ConnectionInfos* infos) override {
- ConnectionInfo info;
- infos->clear();
- infos->push_back(info);
+ bool GetStats(ConnectionInfos* candidate_pair_stats_list,
+ CandidateStatsList* candidate_stats_list) override {
+ CandidateStats candidate_stats;
+ ConnectionInfo candidate_pair_stats;
+ candidate_stats_list->clear();
+ candidate_stats_list->push_back(candidate_stats);
+ candidate_pair_stats_list->clear();
+ candidate_pair_stats_list->push_back(candidate_pair_stats);
return true;
}
diff --git a/p2p/base/icetransportinternal.h b/p2p/base/icetransportinternal.h
index 13ba331..192a9d0 100644
--- a/p2p/base/icetransportinternal.h
+++ b/p2p/base/icetransportinternal.h
@@ -201,7 +201,8 @@
virtual IceGatheringState gathering_state() const = 0;
// Returns the current stats for this connection.
- virtual bool GetStats(ConnectionInfos* infos) = 0;
+ virtual bool GetStats(ConnectionInfos* candidate_pair_stats_list,
+ CandidateStatsList* candidate_stats_list) = 0;
// Returns RTT estimate over the currently active connection, or an empty
// rtc::Optional if there is none.
diff --git a/p2p/base/mockicetransport.h b/p2p/base/mockicetransport.h
index 3e7aed7..c30d797 100644
--- a/p2p/base/mockicetransport.h
+++ b/p2p/base/mockicetransport.h
@@ -40,7 +40,9 @@
MOCK_METHOD2(SetOption, int(rtc::Socket::Option opt, int value));
MOCK_METHOD0(GetError, int());
MOCK_CONST_METHOD0(GetIceRole, cricket::IceRole());
- MOCK_METHOD1(GetStats, bool(cricket::ConnectionInfos* infos));
+ MOCK_METHOD2(GetStats,
+ bool(cricket::ConnectionInfos* candidate_pair_stats_list,
+ cricket::CandidateStatsList* candidate_stats_list));
IceTransportState GetState() const override {
return IceTransportState::STATE_INIT;
diff --git a/p2p/base/p2ptransportchannel.cc b/p2p/base/p2ptransportchannel.cc
index 2ad4114..414ff2b 100644
--- a/p2p/base/p2ptransportchannel.cc
+++ b/p2p/base/p2ptransportchannel.cc
@@ -1136,15 +1136,22 @@
return sent;
}
-bool P2PTransportChannel::GetStats(ConnectionInfos *infos) {
+bool P2PTransportChannel::GetStats(ConnectionInfos* candidate_pair_stats_list,
+ CandidateStatsList* candidate_stats_list) {
RTC_DCHECK(network_thread_ == rtc::Thread::Current());
- // Gather connection infos.
- infos->clear();
+ // Gather candidate and candidate pair stats.
+ candidate_stats_list->clear();
+ candidate_pair_stats_list->clear();
+ if (!allocator_sessions_.empty()) {
+ allocator_session()->GetCandidateStatsFromReadyPorts(candidate_stats_list);
+ }
+
+ // TODO(qingsi): Remove naming inconsistency for candidate pair/connection.
for (Connection* connection : connections_) {
- ConnectionInfo info = connection->stats();
- info.best_connection = (selected_connection_ == connection);
- infos->push_back(std::move(info));
+ ConnectionInfo candidate_pair_stats = connection->stats();
+ candidate_pair_stats.best_connection = (selected_connection_ == connection);
+ candidate_pair_stats_list->push_back(std::move(candidate_pair_stats));
connection->set_reported(true);
}
diff --git a/p2p/base/p2ptransportchannel.h b/p2p/base/p2ptransportchannel.h
index af5625a..e4db38c 100644
--- a/p2p/base/p2ptransportchannel.h
+++ b/p2p/base/p2ptransportchannel.h
@@ -118,7 +118,8 @@
int SetOption(rtc::Socket::Option opt, int value) override;
bool GetOption(rtc::Socket::Option opt, int* value) override;
int GetError() override;
- bool GetStats(std::vector<ConnectionInfo>* stats) override;
+ bool GetStats(std::vector<ConnectionInfo>* candidate_pair_stats_list,
+ std::vector<CandidateStats>* candidate_stats_list) override;
rtc::Optional<int> GetRttEstimate() override;
// TODO(honghaiz): Remove this method once the reference of it in
diff --git a/p2p/base/p2ptransportchannel_unittest.cc b/p2p/base/p2ptransportchannel_unittest.cc
index fc2b65c..71c648a 100644
--- a/p2p/base/p2ptransportchannel_unittest.cc
+++ b/p2p/base/p2ptransportchannel_unittest.cc
@@ -1176,8 +1176,10 @@
kMediumTimeout, clock);
TestSendRecv(&clock);
ConnectionInfos infos;
- ASSERT_TRUE(ep1_ch1()->GetStats(&infos));
+ CandidateStatsList candidate_stats_list;
+ ASSERT_TRUE(ep1_ch1()->GetStats(&infos, &candidate_stats_list));
ASSERT_GE(infos.size(), 1u);
+ ASSERT_GE(candidate_stats_list.size(), 1u);
ConnectionInfo* best_conn_info = nullptr;
for (ConnectionInfo& info : infos) {
if (info.best_connection) {
diff --git a/p2p/base/port.cc b/p2p/base/port.cc
index 5f5153f..b142865 100644
--- a/p2p/base/port.cc
+++ b/p2p/base/port.cc
@@ -193,6 +193,16 @@
return rtc::ToString<uint32_t>(rtc::ComputeCrc32(ost.str()));
}
+CandidateStats::CandidateStats() = default;
+
+CandidateStats::CandidateStats(const CandidateStats&) = default;
+
+CandidateStats::CandidateStats(Candidate candidate) {
+ this->candidate = candidate;
+}
+
+CandidateStats::~CandidateStats() = default;
+
ConnectionInfo::ConnectionInfo()
: best_connection(false),
writable(false),
@@ -1428,7 +1438,7 @@
set_write_state(STATE_WRITABLE);
set_state(IceCandidatePairState::SUCCEEDED);
if (rtt_samples_ > 0) {
- rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
+ rtt_ = rtc::GetNextMovingAverage(rtt_, rtt, RTT_RATIO);
} else {
rtt_ = rtt;
}
diff --git a/p2p/base/port.h b/p2p/base/port.h
index 8dbecce..16fedb8 100644
--- a/p2p/base/port.h
+++ b/p2p/base/port.h
@@ -106,6 +106,36 @@
// frozen because we have not implemented ICE freezing logic.
};
+// Stats that we can return about the port of a connection.
+class StunStats {
+ public:
+ StunStats() = default;
+ StunStats(const StunStats&) = default;
+ ~StunStats() = default;
+
+ StunStats& operator=(const StunStats& other) = default;
+
+ int stun_binding_requests_sent = 0;
+ int stun_binding_responses_received = 0;
+ double stun_binding_rtt_ms_total = 0;
+ double stun_binding_rtt_ms_squared_total = 0;
+};
+
+// Stats that we can return about a candidate.
+class CandidateStats {
+ public:
+ CandidateStats();
+ explicit CandidateStats(Candidate candidate);
+ CandidateStats(const CandidateStats&);
+ ~CandidateStats();
+
+ Candidate candidate;
+ // STUN port stats if this candidate is a STUN candidate.
+ rtc::Optional<StunStats> stun_stats;
+};
+
+typedef std::vector<CandidateStats> CandidateStatsList;
+
// Stats that we can return about the connections for a transport channel.
// TODO(hta): Rename to ConnectionStats
struct ConnectionInfo {
@@ -149,7 +179,7 @@
rtc::Optional<uint32_t> current_round_trip_time_ms;
};
-// Information about all the connections of a channel.
+// Information about all the candidate pairs of a channel.
typedef std::vector<ConnectionInfo> ConnectionInfos;
const char* ProtoToString(ProtocolType proto);
@@ -368,6 +398,8 @@
int16_t network_cost() const { return network_cost_; }
+ void GetStunStats(rtc::Optional<StunStats>* stats) override{};
+
protected:
enum { MSG_DESTROY_IF_DEAD = 0, MSG_FIRST_AVAILABLE };
diff --git a/p2p/base/portallocator.cc b/p2p/base/portallocator.cc
index 6ef084c..2b9b183 100644
--- a/p2p/base/portallocator.cc
+++ b/p2p/base/portallocator.cc
@@ -79,6 +79,19 @@
return false;
}
+void PortAllocatorSession::GetCandidateStatsFromReadyPorts(
+ CandidateStatsList* candidate_stats_list) const {
+ auto ports = ReadyPorts();
+ for (auto* port : ports) {
+ auto candidates = port->Candidates();
+ for (const auto& candidate : candidates) {
+ CandidateStats candidate_stats(candidate);
+ port->GetStunStats(&candidate_stats.stun_stats);
+ candidate_stats_list->push_back(std::move(candidate_stats));
+ }
+ }
+}
+
uint32_t PortAllocatorSession::generation() {
return generation_;
}
@@ -210,4 +223,11 @@
pooled_sessions_.clear();
}
+void PortAllocator::GetCandidateStatsFromPooledSessions(
+ CandidateStatsList* candidate_stats_list) {
+ for (const auto& session : pooled_sessions()) {
+ session->GetCandidateStatsFromReadyPorts(candidate_stats_list);
+ }
+}
+
} // namespace cricket
diff --git a/p2p/base/portallocator.h b/p2p/base/portallocator.h
index f32fa07..95052c2 100644
--- a/p2p/base/portallocator.h
+++ b/p2p/base/portallocator.h
@@ -244,6 +244,10 @@
virtual void RegatherOnFailedNetworks() {}
// Re-gathers candidates on all networks.
virtual void RegatherOnAllNetworks() {}
+ // Get candidate-level stats from all candidates on the ready ports and return
+ // the stats to the given list.
+ virtual void GetCandidateStatsFromReadyPorts(
+ CandidateStatsList* candidate_stats_list) const;
// Set the interval at which STUN candidates will resend STUN binding requests
// on the underlying ports to keep NAT bindings open.
// The default value of the interval in implementation is restored if a null
@@ -476,6 +480,14 @@
return turn_customizer_;
}
+ // Collect candidate stats from pooled allocator sessions. This can be used to
+ // collect candidate stats without creating an offer/answer or setting local
+ // description. After the local description is set, the ownership of the
+ // pooled session is taken by P2PTransportChannel, and the
+ // candidate stats can be collected from P2PTransportChannel::GetStats.
+ virtual void GetCandidateStatsFromPooledSessions(
+ CandidateStatsList* candidate_stats_list);
+
protected:
virtual PortAllocatorSession* CreateSessionInternal(
const std::string& content_name,
diff --git a/p2p/base/portinterface.h b/p2p/base/portinterface.h
index e34e39a..49a4164 100644
--- a/p2p/base/portinterface.h
+++ b/p2p/base/portinterface.h
@@ -15,6 +15,7 @@
#include <vector>
#include "api/candidate.h"
+#include "api/optional.h"
#include "p2p/base/transportdescription.h"
#include "rtc_base/asyncpacketsocket.h"
#include "rtc_base/socketaddress.h"
@@ -28,6 +29,7 @@
class Connection;
class IceMessage;
class StunMessage;
+class StunStats;
enum ProtocolType {
PROTO_UDP,
@@ -125,6 +127,8 @@
virtual std::string ToString() const = 0;
+ virtual void GetStunStats(rtc::Optional<StunStats>* stats) = 0;
+
protected:
PortInterface();
};
diff --git a/p2p/base/stunport.cc b/p2p/base/stunport.cc
index 2df14b7..3ea1f96 100644
--- a/p2p/base/stunport.cc
+++ b/p2p/base/stunport.cc
@@ -52,7 +52,7 @@
RTC_LOG(LS_ERROR) << "Binding address has bad family";
} else {
rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
- port_->OnStunBindingRequestSucceeded(server_addr_, addr);
+ port_->OnStunBindingRequestSucceeded(this->Elapsed(), server_addr_, addr);
}
// The keep-alive requests will be stopped after its lifetime has passed.
@@ -317,6 +317,10 @@
return PROTO_UDP;
}
+void UDPPort::GetStunStats(rtc::Optional<StunStats>* stats) {
+ *stats = stats_;
+}
+
void UDPPort::set_stun_keepalive_delay(const rtc::Optional<int>& delay) {
stun_keepalive_delay_ = (delay.has_value() ? delay.value() : KEEPALIVE_DELAY);
}
@@ -450,6 +454,7 @@
}
void UDPPort::OnStunBindingRequestSucceeded(
+ int rtt_ms,
const rtc::SocketAddress& stun_server_addr,
const rtc::SocketAddress& stun_reflected_addr) {
if (bind_request_succeeded_servers_.find(stun_server_addr) !=
@@ -458,6 +463,11 @@
}
bind_request_succeeded_servers_.insert(stun_server_addr);
+ RTC_DCHECK(stats_.stun_binding_responses_received <
+ stats_.stun_binding_requests_sent);
+ stats_.stun_binding_responses_received++;
+ stats_.stun_binding_rtt_ms_total += rtt_ms;
+ stats_.stun_binding_rtt_ms_squared_total += rtt_ms * rtt_ms;
// If socket is shared and |stun_reflected_addr| is equal to local socket
// address, or if the same address has been added by another STUN server,
// then discarding the stun address.
@@ -520,8 +530,10 @@
void UDPPort::OnSendPacket(const void* data, size_t size, StunRequest* req) {
StunBindingRequest* sreq = static_cast<StunBindingRequest*>(req);
rtc::PacketOptions options(DefaultDscpValue());
- if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0)
+ if (socket_->SendTo(data, size, sreq->server_addr(), options) < 0) {
RTC_LOG_ERR_EX(LERROR, socket_->GetError()) << "sendto";
+ }
+ stats_.stun_binding_requests_sent++;
}
bool UDPPort::HasCandidateWithAddress(const rtc::SocketAddress& addr) const {
diff --git a/p2p/base/stunport.h b/p2p/base/stunport.h
index eaeea3a..72afbd3 100644
--- a/p2p/base/stunport.h
+++ b/p2p/base/stunport.h
@@ -101,6 +101,8 @@
bool SupportsProtocol(const std::string& protocol) const override;
ProtocolType GetProtocol() const override;
+ void GetStunStats(rtc::Optional<StunStats>* stats) override;
+
void set_stun_keepalive_delay(const rtc::Optional<int>& delay);
int stun_keepalive_delay() const {
return stun_keepalive_delay_;
@@ -206,6 +208,7 @@
// Below methods handles binding request responses.
void OnStunBindingRequestSucceeded(
+ int rtt_ms,
const rtc::SocketAddress& stun_server_addr,
const rtc::SocketAddress& stun_reflected_addr);
void OnStunBindingOrResolveRequestFailed(
@@ -240,6 +243,8 @@
int stun_keepalive_delay_;
int stun_keepalive_lifetime_ = INFINITE_LIFETIME;
+ StunStats stats_;
+
// This is true by default and false when
// PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE is specified.
bool emit_local_for_anyaddress_;
diff --git a/pc/jseptransport.cc b/pc/jseptransport.cc
index 12aad7a..a6a6135 100644
--- a/pc/jseptransport.cc
+++ b/pc/jseptransport.cc
@@ -234,7 +234,7 @@
dtls_transport->GetSslCipherSuite(&substats.ssl_cipher_suite);
substats.dtls_state = dtls_transport->dtls_state();
if (!dtls_transport->ice_transport()->GetStats(
- &substats.connection_infos)) {
+ &substats.connection_infos, &substats.candidate_stats_list)) {
return false;
}
stats->channel_stats.push_back(substats);
diff --git a/pc/jseptransport.h b/pc/jseptransport.h
index 972f91b..719ff7a 100644
--- a/pc/jseptransport.h
+++ b/pc/jseptransport.h
@@ -39,6 +39,7 @@
~TransportChannelStats();
int component = 0;
+ CandidateStatsList candidate_stats_list;
ConnectionInfos connection_infos;
int srtp_crypto_suite = rtc::SRTP_INVALID_CRYPTO_SUITE;
int ssl_cipher_suite = rtc::TLS_NULL_WITH_NULL_NULL;
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 533e648..aa7146b 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -4937,6 +4937,12 @@
sctp_ready_to_send_data_;
}
+cricket::CandidateStatsList PeerConnection::GetPooledCandidateStats() const {
+ cricket::CandidateStatsList candidate_states_list;
+ port_allocator_->GetCandidateStatsFromPooledSessions(&candidate_states_list);
+ return candidate_states_list;
+}
+
std::map<std::string, std::string> PeerConnection::GetTransportNamesByMid()
const {
std::map<std::string, std::string> transport_names_by_mid;
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index f1dc299..e6ced41 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -233,6 +233,7 @@
return sctp_transport_name_;
}
+ cricket::CandidateStatsList GetPooledCandidateStats() const override;
std::map<std::string, std::string> GetTransportNamesByMid() const override;
std::map<std::string, cricket::TransportStats> GetTransportStatsByNames(
const std::set<std::string>& transport_names) override;
diff --git a/pc/peerconnectioninternal.h b/pc/peerconnectioninternal.h
index 4bca65e..8cf4989 100644
--- a/pc/peerconnectioninternal.h
+++ b/pc/peerconnectioninternal.h
@@ -56,6 +56,8 @@
virtual rtc::Optional<std::string> sctp_content_name() const = 0;
virtual rtc::Optional<std::string> sctp_transport_name() const = 0;
+ virtual cricket::CandidateStatsList GetPooledCandidateStats() const = 0;
+
// Returns a map from MID to transport name for all active media sections.
virtual std::map<std::string, std::string> GetTransportNamesByMid() const = 0;
diff --git a/pc/statscollector.cc b/pc/statscollector.cc
index 9a636b4..e7fb95b 100644
--- a/pc/statscollector.cc
+++ b/pc/statscollector.cc
@@ -670,10 +670,12 @@
report->AddBoolean(b.name, b.value);
report->AddId(StatsReport::kStatsValueNameChannelId, channel_report_id);
+ cricket::CandidateStats local_candidate_stats(info.local_candidate);
+ cricket::CandidateStats remote_candidate_stats(info.remote_candidate);
report->AddId(StatsReport::kStatsValueNameLocalCandidateId,
- AddCandidateReport(info.local_candidate, true)->id());
+ AddCandidateReport(local_candidate_stats, true)->id());
report->AddId(StatsReport::kStatsValueNameRemoteCandidateId,
- AddCandidateReport(info.remote_candidate, false)->id());
+ AddCandidateReport(remote_candidate_stats, false)->id());
const Int64ForAdd int64s[] = {
{StatsReport::kStatsValueNameBytesReceived, info.recv_total_bytes},
@@ -708,8 +710,9 @@
}
StatsReport* StatsCollector::AddCandidateReport(
- const cricket::Candidate& candidate,
+ const cricket::CandidateStats& candidate_stats,
bool local) {
+ const auto& candidate = candidate_stats.candidate;
StatsReport::Id id(StatsReport::NewCandidateId(local, candidate.id()));
StatsReport* report = reports_.Find(id);
if (!report) {
@@ -718,6 +721,18 @@
if (local) {
report->AddString(StatsReport::kStatsValueNameCandidateNetworkType,
AdapterTypeToStatsType(candidate.network_type()));
+ if (candidate_stats.stun_stats.has_value()) {
+ const auto& stun_stats = candidate_stats.stun_stats.value();
+ report->AddInt64(StatsReport::kStatsValueNameSentStunKeepaliveRequests,
+ stun_stats.stun_binding_requests_sent);
+ report->AddInt64(StatsReport::kStatsValueNameRecvStunKeepaliveResponses,
+ stun_stats.stun_binding_responses_received);
+ report->AddFloat(StatsReport::kStatsValueNameStunKeepaliveRttTotal,
+ stun_stats.stun_binding_rtt_ms_total);
+ report->AddFloat(
+ StatsReport::kStatsValueNameStunKeepaliveRttSquaredTotal,
+ stun_stats.stun_binding_rtt_ms_squared_total);
+ }
}
report->AddString(StatsReport::kStatsValueNameCandidateIPAddress,
candidate.address().ipaddr().ToString());
@@ -745,6 +760,13 @@
report->AddBoolean(StatsReport::kStatsValueNameInitiator,
pc_->initial_offerer());
+ cricket::CandidateStatsList pooled_candidate_stats_list =
+ pc_->GetPooledCandidateStats();
+
+ for (const cricket::CandidateStats& stats : pooled_candidate_stats_list) {
+ AddCandidateReport(stats, true);
+ }
+
std::set<std::string> transport_names;
for (const auto& entry : pc_->GetTransportNamesByMid()) {
transport_names.insert(entry.second);
@@ -808,6 +830,16 @@
rtc::SSLStreamAdapter::SslCipherSuiteToName(ssl_cipher_suite));
}
+ // Collect stats for non-pooled candidates. Note that the reports
+ // generated here supersedes the candidate reports generated in
+ // AddConnectionInfoReport below, and they may report candidates that are
+ // not paired. Also, the candidate report generated in
+ // AddConnectionInfoReport do not report port stats like StunStats.
+ for (const cricket::CandidateStats& stats :
+ channel_iter.candidate_stats_list) {
+ AddCandidateReport(stats, true);
+ }
+
int connection_id = 0;
for (const cricket::ConnectionInfo& info :
channel_iter.connection_infos) {
diff --git a/pc/statscollector.h b/pc/statscollector.h
index 681a8f0..abd65a9 100644
--- a/pc/statscollector.h
+++ b/pc/statscollector.h
@@ -96,8 +96,9 @@
// Helper method for creating IceCandidate report. |is_local| indicates
// whether this candidate is local or remote.
- StatsReport* AddCandidateReport(const cricket::Candidate& candidate,
- bool local);
+ StatsReport* AddCandidateReport(
+ const cricket::CandidateStats& candidate_stats,
+ bool local);
// Adds a report for this certificate and every certificate in its chain, and
// returns the leaf certificate's report (|cert|'s report).
diff --git a/pc/test/fakepeerconnectionforstats.h b/pc/test/fakepeerconnectionforstats.h
index c198d1d..c26d144 100644
--- a/pc/test/fakepeerconnectionforstats.h
+++ b/pc/test/fakepeerconnectionforstats.h
@@ -272,6 +272,10 @@
return sctp_data_channels_;
}
+ cricket::CandidateStatsList GetPooledCandidateStats() const override {
+ return {};
+ }
+
std::map<std::string, std::string> GetTransportNamesByMid() const override {
std::map<std::string, std::string> transport_names_by_mid;
if (voice_channel_) {
diff --git a/rtc_base/helpers.cc b/rtc_base/helpers.cc
index b0c8856..9cb9268 100644
--- a/rtc_base/helpers.cc
+++ b/rtc_base/helpers.cc
@@ -215,4 +215,8 @@
std::numeric_limits<double>::epsilon());
}
+double GetNextMovingAverage(double prev_average, double cur, double ratio) {
+ return (ratio * prev_average + cur) / (ratio + 1);
+}
+
} // namespace rtc
diff --git a/rtc_base/helpers.h b/rtc_base/helpers.h
index e1d2ebb..0100794 100644
--- a/rtc_base/helpers.h
+++ b/rtc_base/helpers.h
@@ -59,6 +59,10 @@
// Generates a random double between 0.0 (inclusive) and 1.0 (exclusive).
double CreateRandomDouble();
+// Compute moving average with the given ratio between the previous average
+// value and the current value.
+double GetNextMovingAverage(double prev_average, double cur, double ratio);
+
} // namespace rtc
#endif // RTC_BASE_HELPERS_H_