Add UMA metrics for ICE regathering reasons.

BUG=webrtc:6462
R=deadbeef@webrtc.org

Review URL: https://codereview.webrtc.org/2386783002 .

Cr-Commit-Position: refs/heads/master@{#14531}
This commit is contained in:
Honghai Zhang
2016-10-05 11:47:22 -07:00
parent 425a6ccac3
commit d93f50cd57
17 changed files with 316 additions and 16 deletions

View File

@ -337,6 +337,7 @@ if (rtc_include_tests) {
rtc_test("rtc_unittests") { rtc_test("rtc_unittests") {
testonly = true testonly = true
sources = [ sources = [
"api/fakemetricsobserver.cc",
"base/array_view_unittest.cc", "base/array_view_unittest.cc",
"base/atomicops_unittest.cc", "base/atomicops_unittest.cc",
"base/autodetectproxy_unittest.cc", "base/autodetectproxy_unittest.cc",

View File

@ -45,7 +45,9 @@ void FakeMetricsObserver::AddHistogramSample(PeerConnectionMetricsName type,
int FakeMetricsObserver::GetEnumCounter(PeerConnectionEnumCounterType type, int FakeMetricsObserver::GetEnumCounter(PeerConnectionEnumCounterType type,
int counter) const { int counter) const {
RTC_DCHECK(thread_checker_.CalledOnValidThread()); RTC_DCHECK(thread_checker_.CalledOnValidThread());
RTC_CHECK(counters_.size() > static_cast<size_t>(type)); if (counters_.size() <= static_cast<size_t>(type)) {
return 0;
}
const auto& it = counters_[type].find(counter); const auto& it = counters_[type].find(counter);
if (it == counters_[type].end()) { if (it == counters_[type].end()) {
return 0; return 0;

View File

@ -1300,6 +1300,7 @@ void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
// Send information about IPv4/IPv6 status. // Send information about IPv4/IPv6 status.
if (uma_observer_ && port_allocator_) { if (uma_observer_ && port_allocator_) {
port_allocator_->SetMetricsObserver(uma_observer_);
if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) { if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
uma_observer_->IncrementEnumCounter( uma_observer_->IncrementEnumCounter(
kEnumCounterAddressFamily, kPeerConnection_IPv6, kEnumCounterAddressFamily, kPeerConnection_IPv6,

View File

@ -33,6 +33,8 @@ enum PeerConnectionEnumCounterType {
kEnumCounterDataSrtpCipher, kEnumCounterDataSrtpCipher,
kEnumCounterDataSslCipher, kEnumCounterDataSslCipher,
kEnumCounterDtlsHandshakeError, kEnumCounterDtlsHandshakeError,
kEnumCounterIceRegathering,
kEnumCounterIceRestart,
kPeerConnectionEnumCounterMax kPeerConnectionEnumCounterMax
}; };

View File

@ -293,6 +293,7 @@ class WebRtcSession :
void set_metrics_observer( void set_metrics_observer(
webrtc::MetricsObserverInterface* metrics_observer) { webrtc::MetricsObserverInterface* metrics_observer) {
metrics_observer_ = metrics_observer; metrics_observer_ = metrics_observer;
transport_controller_->SetMetricsObserver(metrics_observer);
} }
// Called when voice_channel_, video_channel_ and data_channel_ are created // Called when voice_channel_, video_channel_ and data_channel_ are created

View File

@ -186,6 +186,10 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl {
channel_->RemoveRemoteCandidate(candidate); channel_->RemoveRemoteCandidate(candidate);
} }
void SetMetricsObserver(webrtc::MetricsObserverInterface* observer) override {
channel_->SetMetricsObserver(observer);
}
void SetIceConfig(const IceConfig& config) override { void SetIceConfig(const IceConfig& config) override {
channel_->SetIceConfig(config); channel_->SetIceConfig(config);
} }

View File

@ -299,6 +299,9 @@ class FakeTransportChannel : public TransportChannelImpl,
return ssl_max_version_; return ssl_max_version_;
} }
void SetMetricsObserver(webrtc::MetricsObserverInterface* observer) override {
}
private: private:
void NegotiateSrtpCiphers() { void NegotiateSrtpCiphers() {
for (std::vector<int>::const_iterator it1 = srtp_ciphers_.begin(); for (std::vector<int>::const_iterator it1 = srtp_ciphers_.begin();

View File

@ -13,6 +13,7 @@
#include <algorithm> #include <algorithm>
#include <set> #include <set>
#include "webrtc/api/peerconnectioninterface.h"
#include "webrtc/base/common.h" #include "webrtc/base/common.h"
#include "webrtc/base/crc32.h" #include "webrtc/base/crc32.h"
#include "webrtc/base/logging.h" #include "webrtc/base/logging.h"
@ -435,6 +436,11 @@ const IceConfig& P2PTransportChannel::config() const {
return config_; return config_;
} }
void P2PTransportChannel::SetMetricsObserver(
webrtc::MetricsObserverInterface* observer) {
metrics_observer_ = observer;
}
void P2PTransportChannel::MaybeStartGathering() { void P2PTransportChannel::MaybeStartGathering() {
if (ice_parameters_.ufrag.empty() || ice_parameters_.pwd.empty()) { if (ice_parameters_.ufrag.empty() || ice_parameters_.pwd.empty()) {
LOG(LS_ERROR) << "Cannot gather candidates because ICE parameters are empty" LOG(LS_ERROR) << "Cannot gather candidates because ICE parameters are empty"
@ -451,6 +457,21 @@ void P2PTransportChannel::MaybeStartGathering() {
gathering_state_ = kIceGatheringGathering; gathering_state_ = kIceGatheringGathering;
SignalGatheringState(this); SignalGatheringState(this);
} }
if (metrics_observer_ && !allocator_sessions_.empty()) {
IceRestartState state;
if (writable()) {
state = IceRestartState::CONNECTED;
} else if (IsGettingPorts()) {
state = IceRestartState::CONNECTING;
} else {
state = IceRestartState::DISCONNECTED;
}
metrics_observer_->IncrementEnumCounter(
webrtc::kEnumCounterIceRestart, static_cast<int>(state),
static_cast<int>(IceRestartState::MAX_VALUE));
}
// Time for a new allocator. // Time for a new allocator.
std::unique_ptr<PortAllocatorSession> pooled_session = std::unique_ptr<PortAllocatorSession> pooled_session =
allocator_->TakePooledSession(transport_name(), component(), allocator_->TakePooledSession(transport_name(), component(),
@ -473,7 +494,6 @@ void P2PTransportChannel::MaybeStartGathering() {
AddAllocatorSession(allocator_->CreateSession( AddAllocatorSession(allocator_->CreateSession(
transport_name(), component(), ice_parameters_.ufrag, transport_name(), component(), ice_parameters_.ufrag,
ice_parameters_.pwd)); ice_parameters_.pwd));
LOG(LS_INFO) << "Start getting ports";
allocator_sessions_.back()->StartGettingPorts(); allocator_sessions_.back()->StartGettingPorts();
} }
} }

View File

@ -38,6 +38,10 @@
namespace cricket { namespace cricket {
// Enum for UMA metrics, used to record whether the channel is
// connected/connecting/disconnected when ICE restart happens.
enum class IceRestartState { CONNECTING, CONNECTED, DISCONNECTED, MAX_VALUE };
extern const int WEAK_PING_INTERVAL; extern const int WEAK_PING_INTERVAL;
extern const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL; extern const int STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL;
extern const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL; extern const int STABLE_WRITABLE_CONNECTION_PING_INTERVAL;
@ -95,6 +99,7 @@ class P2PTransportChannel : public TransportChannelImpl,
// TODO(deadbeef): Use rtc::Optional instead of negative values. // TODO(deadbeef): Use rtc::Optional instead of negative values.
void SetIceConfig(const IceConfig& config) override; void SetIceConfig(const IceConfig& config) override;
const IceConfig& config() const; const IceConfig& config() const;
void SetMetricsObserver(webrtc::MetricsObserverInterface* observer) override;
// From TransportChannel: // From TransportChannel:
int SendPacket(const char* data, int SendPacket(const char* data,
@ -394,6 +399,8 @@ class P2PTransportChannel : public TransportChannelImpl,
// connection. A zero-value indicates the connection will not be nominated. // connection. A zero-value indicates the connection will not be nominated.
uint32_t nomination_ = 0; uint32_t nomination_ = 0;
webrtc::MetricsObserverInterface* metrics_observer_ = nullptr;
RTC_DISALLOW_COPY_AND_ASSIGN(P2PTransportChannel); RTC_DISALLOW_COPY_AND_ASSIGN(P2PTransportChannel);
}; };

View File

@ -11,6 +11,7 @@
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
#include "webrtc/api/fakemetricsobserver.h"
#include "webrtc/p2p/base/fakeportallocator.h" #include "webrtc/p2p/base/fakeportallocator.h"
#include "webrtc/p2p/base/p2ptransportchannel.h" #include "webrtc/p2p/base/p2ptransportchannel.h"
#include "webrtc/p2p/base/testrelayserver.h" #include "webrtc/p2p/base/testrelayserver.h"
@ -198,9 +199,15 @@ class P2PTransportChannelTestBase : public testing::Test,
ep1_.allocator_.reset( ep1_.allocator_.reset(
CreateBasicPortAllocator(&ep1_.network_manager_, stun_servers, CreateBasicPortAllocator(&ep1_.network_manager_, stun_servers,
kTurnUdpIntAddr, rtc::SocketAddress())); kTurnUdpIntAddr, rtc::SocketAddress()));
ep1_.metrics_observer_ =
new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
ep1_.allocator_->SetMetricsObserver(ep1_.metrics_observer_);
ep2_.allocator_.reset( ep2_.allocator_.reset(
CreateBasicPortAllocator(&ep2_.network_manager_, stun_servers, CreateBasicPortAllocator(&ep2_.network_manager_, stun_servers,
kTurnUdpIntAddr, rtc::SocketAddress())); kTurnUdpIntAddr, rtc::SocketAddress()));
ep2_.metrics_observer_ =
new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
ep2_.allocator_->SetMetricsObserver(ep2_.metrics_observer_);
} }
protected: protected:
@ -298,6 +305,9 @@ class P2PTransportChannelTestBase : public testing::Test,
} }
rtc::FakeNetworkManager network_manager_; rtc::FakeNetworkManager network_manager_;
// |metrics_observer_| should outlive |allocator_| as the former may be
// used by the latter.
rtc::scoped_refptr<webrtc::FakeMetricsObserver> metrics_observer_;
std::unique_ptr<BasicPortAllocator> allocator_; std::unique_ptr<BasicPortAllocator> allocator_;
ChannelData cd1_; ChannelData cd1_;
ChannelData cd2_; ChannelData cd2_;
@ -334,6 +344,8 @@ class P2PTransportChannelTestBase : public testing::Test,
ice_ep1_cd1_ch, ice_ep2_cd1_ch)); ice_ep1_cd1_ch, ice_ep2_cd1_ch));
ep2_.cd1_.ch_.reset(CreateChannel(1, ICE_CANDIDATE_COMPONENT_DEFAULT, ep2_.cd1_.ch_.reset(CreateChannel(1, ICE_CANDIDATE_COMPONENT_DEFAULT,
ice_ep2_cd1_ch, ice_ep1_cd1_ch)); ice_ep2_cd1_ch, ice_ep1_cd1_ch));
ep1_.cd1_.ch_->SetMetricsObserver(ep1_.metrics_observer_);
ep2_.cd1_.ch_->SetMetricsObserver(ep2_.metrics_observer_);
ep1_.cd1_.ch_->SetIceConfig(ep1_config); ep1_.cd1_.ch_->SetIceConfig(ep1_config);
ep2_.cd1_.ch_->SetIceConfig(ep2_config); ep2_.cd1_.ch_->SetIceConfig(ep2_config);
ep1_.cd1_.ch_->MaybeStartGathering(); ep1_.cd1_.ch_->MaybeStartGathering();
@ -416,6 +428,9 @@ class P2PTransportChannelTestBase : public testing::Test,
PortAllocator* GetAllocator(int endpoint) { PortAllocator* GetAllocator(int endpoint) {
return GetEndpoint(endpoint)->allocator_.get(); return GetEndpoint(endpoint)->allocator_.get();
} }
webrtc::FakeMetricsObserver* GetMetricsObserver(int endpoint) {
return GetEndpoint(endpoint)->metrics_observer_;
}
void AddAddress(int endpoint, const SocketAddress& addr) { void AddAddress(int endpoint, const SocketAddress& addr) {
GetEndpoint(endpoint)->network_manager_.AddInterface(addr); GetEndpoint(endpoint)->network_manager_.AddInterface(addr);
} }
@ -958,13 +973,12 @@ class P2PTransportChannelTest : public P2PTransportChannelTestBase {
Config config2, Config config2,
int allocator_flags1, int allocator_flags1,
int allocator_flags2) { int allocator_flags2) {
int delay = kMinimumStepDelay;
ConfigureEndpoint(0, config1); ConfigureEndpoint(0, config1);
SetAllocatorFlags(0, allocator_flags1); SetAllocatorFlags(0, allocator_flags1);
SetAllocationStepDelay(0, delay); SetAllocationStepDelay(0, kMinimumStepDelay);
ConfigureEndpoint(1, config2); ConfigureEndpoint(1, config2);
SetAllocatorFlags(1, allocator_flags2); SetAllocatorFlags(1, allocator_flags2);
SetAllocationStepDelay(1, delay); SetAllocationStepDelay(1, kMinimumStepDelay);
set_remote_ice_parameter_source(FROM_SETICEPARAMETERS); set_remote_ice_parameter_source(FROM_SETICEPARAMETERS);
} }
@ -1172,6 +1186,169 @@ TEST_F(P2PTransportChannelTest, GetStats) {
DestroyChannels(); DestroyChannels();
} }
// Tests that UMAs are recorded when ICE restarts while the channel
// is disconnected.
TEST_F(P2PTransportChannelTest, TestUMAIceRestartWhileDisconnected) {
rtc::ScopedFakeClock clock;
ConfigureEndpoints(OPEN, OPEN, kOnlyLocalPorts, kOnlyLocalPorts);
CreateChannels();
EXPECT_TRUE_SIMULATED_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
ep2_ch1()->receiving() &&
ep2_ch1()->writable(),
kDefaultTimeout, clock);
// Drop all packets so that both channels become not writable.
fw()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, kPublicAddrs[0]);
const int kWriteTimeoutDelay = 6000;
EXPECT_TRUE_SIMULATED_WAIT(!ep1_ch1()->writable() && !ep2_ch1()->writable(),
kWriteTimeoutDelay, clock);
ep1_ch1()->SetIceParameters(kIceParams[2]);
ep1_ch1()->SetRemoteIceParameters(kIceParams[3]);
ep1_ch1()->MaybeStartGathering();
EXPECT_EQ(1, GetMetricsObserver(0)->GetEnumCounter(
webrtc::kEnumCounterIceRestart,
static_cast<int>(IceRestartState::DISCONNECTED)));
ep2_ch1()->SetIceParameters(kIceParams[3]);
ep2_ch1()->SetRemoteIceParameters(kIceParams[2]);
ep2_ch1()->MaybeStartGathering();
EXPECT_EQ(1, GetMetricsObserver(1)->GetEnumCounter(
webrtc::kEnumCounterIceRestart,
static_cast<int>(IceRestartState::DISCONNECTED)));
DestroyChannels();
}
// Tests that UMAs are recorded when ICE restarts while the channel
// is connected.
TEST_F(P2PTransportChannelTest, TestUMAIceRestartWhileConnected) {
rtc::ScopedFakeClock clock;
ConfigureEndpoints(OPEN, OPEN, kOnlyLocalPorts, kOnlyLocalPorts);
CreateChannels();
EXPECT_TRUE_SIMULATED_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
ep2_ch1()->receiving() &&
ep2_ch1()->writable(),
kDefaultTimeout, clock);
ep1_ch1()->SetIceParameters(kIceParams[2]);
ep1_ch1()->SetRemoteIceParameters(kIceParams[3]);
ep1_ch1()->MaybeStartGathering();
EXPECT_EQ(1, GetMetricsObserver(0)->GetEnumCounter(
webrtc::kEnumCounterIceRestart,
static_cast<int>(IceRestartState::CONNECTED)));
ep2_ch1()->SetIceParameters(kIceParams[3]);
ep2_ch1()->SetRemoteIceParameters(kIceParams[2]);
ep2_ch1()->MaybeStartGathering();
EXPECT_EQ(1, GetMetricsObserver(1)->GetEnumCounter(
webrtc::kEnumCounterIceRestart,
static_cast<int>(IceRestartState::CONNECTED)));
DestroyChannels();
}
// Tests that UMAs are recorded when ICE restarts while the channel
// is connecting.
TEST_F(P2PTransportChannelTest, TestUMAIceRestartWhileConnecting) {
rtc::ScopedFakeClock clock;
ConfigureEndpoints(OPEN, OPEN, kOnlyLocalPorts, kOnlyLocalPorts);
// Create the channels without waiting for them to become connected.
CreateChannels();
ep1_ch1()->SetIceParameters(kIceParams[2]);
ep1_ch1()->SetRemoteIceParameters(kIceParams[3]);
ep1_ch1()->MaybeStartGathering();
EXPECT_EQ(1, GetMetricsObserver(0)->GetEnumCounter(
webrtc::kEnumCounterIceRestart,
static_cast<int>(IceRestartState::CONNECTING)));
ep2_ch1()->SetIceParameters(kIceParams[3]);
ep2_ch1()->SetRemoteIceParameters(kIceParams[2]);
ep2_ch1()->MaybeStartGathering();
EXPECT_EQ(1, GetMetricsObserver(1)->GetEnumCounter(
webrtc::kEnumCounterIceRestart,
static_cast<int>(IceRestartState::CONNECTING)));
DestroyChannels();
}
// Tests that a UMA on ICE regathering is recorded when there is a network
// change if and only if continual gathering is enabled.
TEST_F(P2PTransportChannelTest,
TestIceRegatheringReasonContinualGatheringByNetworkChange) {
rtc::ScopedFakeClock clock;
ConfigureEndpoints(OPEN, OPEN, kOnlyLocalPorts, kOnlyLocalPorts);
// ep1 gathers continually but ep2 does not.
IceConfig continual_gathering_config =
CreateIceConfig(1000, GATHER_CONTINUALLY);
IceConfig default_config;
CreateChannels(continual_gathering_config, default_config);
EXPECT_TRUE_SIMULATED_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
ep2_ch1()->receiving() &&
ep2_ch1()->writable(),
kDefaultTimeout, clock);
// Adding address in ep1 will trigger continual gathering.
AddAddress(0, kAlternateAddrs[0]);
EXPECT_EQ_SIMULATED_WAIT(
1, GetMetricsObserver(0)->GetEnumCounter(
webrtc::kEnumCounterIceRegathering,
static_cast<int>(IceRegatheringReason::NETWORK_CHANGE)),
kDefaultTimeout, clock);
ep2_ch1()->SetIceParameters(kIceParams[3]);
ep2_ch1()->SetRemoteIceParameters(kIceParams[2]);
ep2_ch1()->MaybeStartGathering();
AddAddress(1, kAlternateAddrs[1]);
SIMULATED_WAIT(false, kDefaultTimeout, clock);
// ep2 has not enabled continual gathering.
EXPECT_EQ(0, GetMetricsObserver(1)->GetEnumCounter(
webrtc::kEnumCounterIceRegathering,
static_cast<int>(IceRegatheringReason::NETWORK_CHANGE)));
DestroyChannels();
}
// Tests that a UMA on ICE regathering is recorded when there is a network
// failure if and only if continual gathering is enabled.
TEST_F(P2PTransportChannelTest,
TestIceRegatheringReasonContinualGatheringByNetworkFailure) {
rtc::ScopedFakeClock clock;
ConfigureEndpoints(OPEN, OPEN, kOnlyLocalPorts, kOnlyLocalPorts);
// ep1 gathers continually but ep2 does not.
IceConfig config1 = CreateIceConfig(1000, GATHER_CONTINUALLY);
config1.regather_on_failed_networks_interval = rtc::Optional<int>(2000);
IceConfig config2;
config2.regather_on_failed_networks_interval = rtc::Optional<int>(2000);
CreateChannels(config1, config2);
EXPECT_TRUE_SIMULATED_WAIT(ep1_ch1()->receiving() && ep1_ch1()->writable() &&
ep2_ch1()->receiving() &&
ep2_ch1()->writable(),
kDefaultTimeout, clock);
fw()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, kPublicAddrs[0]);
// Timeout value such that all connections are deleted.
const int kNetworkFailureTimeout = 35000;
SIMULATED_WAIT(false, kNetworkFailureTimeout, clock);
EXPECT_LE(1, GetMetricsObserver(0)->GetEnumCounter(
webrtc::kEnumCounterIceRegathering,
static_cast<int>(IceRegatheringReason::NETWORK_FAILURE)));
EXPECT_EQ(0, GetMetricsObserver(1)->GetEnumCounter(
webrtc::kEnumCounterIceRegathering,
static_cast<int>(IceRegatheringReason::NETWORK_FAILURE)));
DestroyChannels();
}
// Test that we properly create a connection on a STUN ping from unknown address // Test that we properly create a connection on a STUN ping from unknown address
// when the signaling is slow. // when the signaling is slow.
TEST_F(P2PTransportChannelTest, PeerReflexiveCandidateBeforeSignaling) { TEST_F(P2PTransportChannelTest, PeerReflexiveCandidateBeforeSignaling) {

View File

@ -23,6 +23,10 @@
#include "webrtc/base/sigslot.h" #include "webrtc/base/sigslot.h"
#include "webrtc/base/thread.h" #include "webrtc/base/thread.h"
namespace webrtc {
class MetricsObserverInterface;
}
namespace cricket { namespace cricket {
// PortAllocator is responsible for allocating Port types for a given // PortAllocator is responsible for allocating Port types for a given
@ -72,6 +76,9 @@ enum {
PORTALLOCATOR_DISABLE_COSTLY_NETWORKS = 0x2000, PORTALLOCATOR_DISABLE_COSTLY_NETWORKS = 0x2000,
}; };
// Defines various reasons that have caused ICE regathering.
enum class IceRegatheringReason { NETWORK_CHANGE, NETWORK_FAILURE, MAX_VALUE };
const uint32_t kDefaultPortAllocatorFlags = 0; const uint32_t kDefaultPortAllocatorFlags = 0;
const uint32_t kDefaultStepDelay = 1000; // 1 sec step delay. const uint32_t kDefaultStepDelay = 1000; // 1 sec step delay.
@ -216,6 +223,9 @@ class PortAllocatorSession : public sigslot::has_slots<> {
SignalCandidatesRemoved; SignalCandidatesRemoved;
sigslot::signal1<PortAllocatorSession*> SignalCandidatesAllocationDone; sigslot::signal1<PortAllocatorSession*> SignalCandidatesAllocationDone;
sigslot::signal2<PortAllocatorSession*, IceRegatheringReason>
SignalIceRegathering;
virtual uint32_t generation() { return generation_; } virtual uint32_t generation() { return generation_; }
virtual void set_generation(uint32_t generation) { generation_ = generation; } virtual void set_generation(uint32_t generation) { generation_ = generation; }
sigslot::signal1<PortAllocatorSession*> SignalDestroyed; sigslot::signal1<PortAllocatorSession*> SignalDestroyed;
@ -370,6 +380,10 @@ class PortAllocator : public sigslot::has_slots<> {
const std::string& origin() const { return origin_; } const std::string& origin() const { return origin_; }
void set_origin(const std::string& origin) { origin_ = origin; } void set_origin(const std::string& origin) { origin_ = origin; }
void SetMetricsObserver(webrtc::MetricsObserverInterface* observer) {
metrics_observer_ = observer;
}
protected: protected:
virtual PortAllocatorSession* CreateSessionInternal( virtual PortAllocatorSession* CreateSessionInternal(
const std::string& content_name, const std::string& content_name,
@ -377,6 +391,14 @@ class PortAllocator : public sigslot::has_slots<> {
const std::string& ice_ufrag, const std::string& ice_ufrag,
const std::string& ice_pwd) = 0; const std::string& ice_pwd) = 0;
webrtc::MetricsObserverInterface* metrics_observer() {
return metrics_observer_;
}
const std::deque<std::unique_ptr<PortAllocatorSession>>& pooled_sessions() {
return pooled_sessions_;
}
uint32_t flags_; uint32_t flags_;
std::string agent_; std::string agent_;
rtc::ProxyInfo proxy_; rtc::ProxyInfo proxy_;
@ -397,6 +419,8 @@ class PortAllocator : public sigslot::has_slots<> {
int allocated_pooled_session_count_ = 0; int allocated_pooled_session_count_ = 0;
std::deque<std::unique_ptr<PortAllocatorSession>> pooled_sessions_; std::deque<std::unique_ptr<PortAllocatorSession>> pooled_sessions_;
bool prune_turn_ports_ = false; bool prune_turn_ports_ = false;
webrtc::MetricsObserverInterface* metrics_observer_ = nullptr;
}; };
} // namespace cricket } // namespace cricket

View File

@ -18,6 +18,10 @@
namespace buzz { class XmlElement; } namespace buzz { class XmlElement; }
namespace webrtc {
class MetricsObserverInterface;
}
namespace cricket { namespace cricket {
class Candidate; class Candidate;
@ -74,6 +78,9 @@ class TransportChannelImpl : public TransportChannel {
// occurred. // occurred.
virtual void MaybeStartGathering() = 0; virtual void MaybeStartGathering() = 0;
virtual void SetMetricsObserver(
webrtc::MetricsObserverInterface* observer) = 0;
sigslot::signal1<TransportChannelImpl*> SignalGatheringState; sigslot::signal1<TransportChannelImpl*> SignalGatheringState;
// Handles sending and receiving of candidates. The Transport // Handles sending and receiving of candidates. The Transport

View File

@ -187,6 +187,7 @@ TransportChannel* TransportController::CreateTransportChannel_n(
// Need to create a new channel. // Need to create a new channel.
Transport* transport = GetOrCreateTransport_n(transport_name); Transport* transport = GetOrCreateTransport_n(transport_name);
TransportChannelImpl* channel = transport->CreateChannel(component); TransportChannelImpl* channel = transport->CreateChannel(component);
channel->SetMetricsObserver(metrics_observer_);
channel->SignalWritableState.connect( channel->SignalWritableState.connect(
this, &TransportController::OnChannelWritableState_n); this, &TransportController::OnChannelWritableState_n);
channel->SignalReceivingState.connect( channel->SignalReceivingState.connect(
@ -704,4 +705,12 @@ void TransportController::OnDtlsHandshakeError(rtc::SSLHandshakeError error) {
SignalDtlsHandshakeError(error); SignalDtlsHandshakeError(error);
} }
void TransportController::SetMetricsObserver(
webrtc::MetricsObserverInterface* metrics_observer) {
metrics_observer_ = metrics_observer;
for (auto channel : channels_) {
channel->SetMetricsObserver(metrics_observer);
}
}
} // namespace cricket } // namespace cricket

View File

@ -25,6 +25,9 @@
namespace rtc { namespace rtc {
class Thread; class Thread;
} }
namespace webrtc {
class MetricsObserverInterface;
}
namespace cricket { namespace cricket {
@ -129,6 +132,8 @@ class TransportController : public sigslot::has_slots<>,
sigslot::signal1<rtc::SSLHandshakeError> SignalDtlsHandshakeError; sigslot::signal1<rtc::SSLHandshakeError> SignalDtlsHandshakeError;
void SetMetricsObserver(webrtc::MetricsObserverInterface* metrics_observer);
protected: protected:
// Protected and virtual so we can override it in unit tests. // Protected and virtual so we can override it in unit tests.
virtual Transport* CreateTransport_n(const std::string& transport_name); virtual Transport* CreateTransport_n(const std::string& transport_name);
@ -238,6 +243,8 @@ class TransportController : public sigslot::has_slots<>,
rtc::AsyncInvoker invoker_; rtc::AsyncInvoker invoker_;
// True if QUIC is used instead of DTLS. // True if QUIC is used instead of DTLS.
bool quic_ = false; bool quic_ = false;
webrtc::MetricsObserverInterface* metrics_observer_ = nullptr;
}; };
} // namespace cricket } // namespace cricket

View File

@ -14,6 +14,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "webrtc/api/peerconnectioninterface.h"
#include "webrtc/p2p/base/basicpacketsocketfactory.h" #include "webrtc/p2p/base/basicpacketsocketfactory.h"
#include "webrtc/p2p/base/common.h" #include "webrtc/p2p/base/common.h"
#include "webrtc/p2p/base/port.h" #include "webrtc/p2p/base/port.h"
@ -150,14 +151,35 @@ void BasicPortAllocator::Construct() {
allow_tcp_listen_ = true; allow_tcp_listen_ = true;
} }
void BasicPortAllocator::OnIceRegathering(PortAllocatorSession* session,
IceRegatheringReason reason) {
if (!metrics_observer()) {
return;
}
// If the session has not been taken by an active channel, do not report the
// metric.
for (auto& allocator_session : pooled_sessions()) {
if (allocator_session.get() == session) {
return;
}
}
metrics_observer()->IncrementEnumCounter(
webrtc::kEnumCounterIceRegathering, static_cast<int>(reason),
static_cast<int>(IceRegatheringReason::MAX_VALUE));
}
BasicPortAllocator::~BasicPortAllocator() { BasicPortAllocator::~BasicPortAllocator() {
} }
PortAllocatorSession* BasicPortAllocator::CreateSessionInternal( PortAllocatorSession* BasicPortAllocator::CreateSessionInternal(
const std::string& content_name, int component, const std::string& content_name, int component,
const std::string& ice_ufrag, const std::string& ice_pwd) { const std::string& ice_ufrag, const std::string& ice_pwd) {
return new BasicPortAllocatorSession( PortAllocatorSession* session = new BasicPortAllocatorSession(
this, content_name, component, ice_ufrag, ice_pwd); this, content_name, component, ice_ufrag, ice_pwd);
session->SignalIceRegathering.connect(this,
&BasicPortAllocator::OnIceRegathering);
return session;
} }
void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) { void BasicPortAllocator::AddTurnServer(const RelayServerConfig& turn_server) {
@ -247,7 +269,7 @@ void BasicPortAllocatorSession::StartGettingPorts() {
network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_START); network_thread_->Post(RTC_FROM_HERE, this, MSG_CONFIG_START);
LOG(LS_INFO) << "Pruning turn ports " LOG(LS_INFO) << "Start getting ports with prune_turn_ports "
<< (prune_turn_ports_ ? "enabled" : "disabled"); << (prune_turn_ports_ ? "enabled" : "disabled");
} }
@ -302,6 +324,8 @@ void BasicPortAllocatorSession::RegatherOnFailedNetworks() {
return; return;
} }
LOG(LS_INFO) << "Regather candidates on failed networks";
// Mark a sequence as "network failed" if its network is in the list of failed // Mark a sequence as "network failed" if its network is in the list of failed
// networks, so that it won't be considered as equivalent when the session // networks, so that it won't be considered as equivalent when the session
// regathers ports and candidates. // regathers ports and candidates.
@ -321,7 +345,9 @@ void BasicPortAllocatorSession::RegatherOnFailedNetworks() {
PrunePortsAndRemoveCandidates(ports_to_prune); PrunePortsAndRemoveCandidates(ports_to_prune);
} }
if (allocation_started_ && network_manager_started_) { if (allocation_started_ && network_manager_started_ && !IsStopped()) {
SignalIceRegathering(this, IceRegatheringReason::NETWORK_FAILURE);
DoAllocate(); DoAllocate();
} }
} }
@ -501,7 +527,7 @@ void BasicPortAllocatorSession::AllocatePorts() {
} }
void BasicPortAllocatorSession::OnAllocate() { void BasicPortAllocatorSession::OnAllocate() {
if (network_manager_started_) if (network_manager_started_ && !IsStopped())
DoAllocate(); DoAllocate();
allocation_started_ = true; allocation_started_ = true;
@ -553,10 +579,6 @@ std::vector<rtc::Network*> BasicPortAllocatorSession::GetNetworks() {
void BasicPortAllocatorSession::DoAllocate() { void BasicPortAllocatorSession::DoAllocate() {
bool done_signal_needed = false; bool done_signal_needed = false;
std::vector<rtc::Network*> networks = GetNetworks(); std::vector<rtc::Network*> networks = GetNetworks();
if (IsStopped()) {
return;
}
if (networks.empty()) { if (networks.empty()) {
LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated"; LOG(LS_WARNING) << "Machine has no networks; no ports will be allocated";
done_signal_needed = true; done_signal_needed = true;
@ -627,12 +649,18 @@ void BasicPortAllocatorSession::OnNetworksChanged() {
PrunePortsAndRemoveCandidates(ports_to_prune); PrunePortsAndRemoveCandidates(ports_to_prune);
} }
if (allocation_started_ && !IsStopped()) {
if (network_manager_started_) {
// If the network manager has started, it must be regathering.
SignalIceRegathering(this, IceRegatheringReason::NETWORK_CHANGE);
}
DoAllocate();
}
if (!network_manager_started_) { if (!network_manager_started_) {
LOG(LS_INFO) << "Network manager is started"; LOG(LS_INFO) << "Network manager has started";
network_manager_started_ = true; network_manager_started_ = true;
} }
if (allocation_started_)
DoAllocate();
} }
void BasicPortAllocatorSession::DisableEquivalentPhases( void BasicPortAllocatorSession::DisableEquivalentPhases(

View File

@ -65,6 +65,9 @@ class BasicPortAllocator : public PortAllocator {
private: private:
void Construct(); void Construct();
void OnIceRegathering(PortAllocatorSession* session,
IceRegatheringReason reason);
rtc::NetworkManager* network_manager_; rtc::NetworkManager* network_manager_;
rtc::PacketSocketFactory* socket_factory_; rtc::PacketSocketFactory* socket_factory_;
bool allow_tcp_listen_; bool allow_tcp_listen_;

View File

@ -199,6 +199,10 @@ class QuicTransportChannel : public TransportChannelImpl,
void OnProofVerifyDetailsAvailable( void OnProofVerifyDetailsAvailable(
const net::ProofVerifyDetails& verify_details) override; const net::ProofVerifyDetails& verify_details) override;
void SetMetricsObserver(webrtc::MetricsObserverInterface* observer) override {
channel_->SetMetricsObserver(observer);
}
// Returns true if |quic_| has queued data which wasn't written due // Returns true if |quic_| has queued data which wasn't written due
// to |channel_| being write blocked. // to |channel_| being write blocked.
bool HasDataToWrite() const; bool HasDataToWrite() const;