RTCIceCandidatePairStats.[state/priority] added, ConnectionInfo updated.

State and priority added to ConnectionInfo. The Connection::State enum
is replaced by IceCandidatePairState enum class.

At P2PTransportChannel::GetStats, Connection::stats is called, producing
ConnectionInfo for the connection that is then filled in with additional
values from the Connection. This is refactored so that all values are
set by Connection::stats.

RTCStatsCollector is updated to surface the ConnectionInfo stats.

BUG=webrtc:6755, chromium:633550, chromium:627816

Review-Url: https://codereview.webrtc.org/2597423003
Cr-Commit-Position: refs/heads/master@{#15870}
This commit is contained in:
hbos 2017-01-02 08:08:18 -08:00 committed by Commit bot
parent 7eb0e23bcf
commit 06495bcbb7
12 changed files with 95 additions and 60 deletions

View File

@ -359,8 +359,8 @@ class RTCStatsReportVerifier {
candidate_pair.local_candidate_id, RTCLocalIceCandidateStats::kType); candidate_pair.local_candidate_id, RTCLocalIceCandidateStats::kType);
verifier.TestMemberIsIDReference( verifier.TestMemberIsIDReference(
candidate_pair.remote_candidate_id, RTCRemoteIceCandidateStats::kType); candidate_pair.remote_candidate_id, RTCRemoteIceCandidateStats::kType);
verifier.TestMemberIsUndefined(candidate_pair.state); verifier.TestMemberIsDefined(candidate_pair.state);
verifier.TestMemberIsUndefined(candidate_pair.priority); verifier.TestMemberIsNonNegative<uint64_t>(candidate_pair.priority);
verifier.TestMemberIsUndefined(candidate_pair.nominated); verifier.TestMemberIsUndefined(candidate_pair.nominated);
verifier.TestMemberIsDefined(candidate_pair.writable); verifier.TestMemberIsDefined(candidate_pair.writable);
verifier.TestMemberIsUndefined(candidate_pair.readable); verifier.TestMemberIsUndefined(candidate_pair.readable);

View File

@ -114,6 +114,23 @@ const char* DataStateToRTCDataChannelState(
} }
} }
const char* IceCandidatePairStateToRTCStatsIceCandidatePairState(
cricket::IceCandidatePairState state) {
switch (state) {
case cricket::IceCandidatePairState::WAITING:
return RTCStatsIceCandidatePairState::kWaiting;
case cricket::IceCandidatePairState::IN_PROGRESS:
return RTCStatsIceCandidatePairState::kInProgress;
case cricket::IceCandidatePairState::SUCCEEDED:
return RTCStatsIceCandidatePairState::kSucceeded;
case cricket::IceCandidatePairState::FAILED:
return RTCStatsIceCandidatePairState::kFailed;
default:
RTC_NOTREACHED();
return nullptr;
}
}
std::unique_ptr<RTCCodecStats> CodecStatsFromRtpCodecParameters( std::unique_ptr<RTCCodecStats> CodecStatsFromRtpCodecParameters(
uint64_t timestamp_us, bool inbound, bool audio, uint64_t timestamp_us, bool inbound, bool audio,
const RtpCodecParameters& codec_params) { const RtpCodecParameters& codec_params) {
@ -646,6 +663,9 @@ void RTCStatsCollector::ProduceIceCandidateAndPairStats_n(
timestamp_us, info.local_candidate, true, report); timestamp_us, info.local_candidate, true, report);
candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats( candidate_pair_stats->remote_candidate_id = ProduceIceCandidateStats(
timestamp_us, info.remote_candidate, false, report); timestamp_us, info.remote_candidate, false, report);
candidate_pair_stats->state =
IceCandidatePairStateToRTCStatsIceCandidatePairState(info.state);
candidate_pair_stats->priority = info.priority;
// TODO(hbos): This writable is different than the spec. It goes to // TODO(hbos): This writable is different than the spec. It goes to
// false after a certain amount of time without a response passes. // false after a certain amount of time without a response passes.
// crbug.com/633550 // crbug.com/633550

View File

@ -1066,6 +1066,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
connection_info.sent_ping_requests_before_first_response = 2000; connection_info.sent_ping_requests_before_first_response = 2000;
connection_info.recv_ping_responses = 4321; connection_info.recv_ping_responses = 4321;
connection_info.sent_ping_responses = 1000; connection_info.sent_ping_responses = 1000;
connection_info.state = cricket::IceCandidatePairState::IN_PROGRESS;
connection_info.priority = 5555;
cricket::TransportChannelStats transport_channel_stats; cricket::TransportChannelStats transport_channel_stats;
transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP; transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
@ -1092,6 +1094,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCIceCandidatePairStats) {
expected_pair.local_candidate_id = "RTCIceCandidate_" + local_candidate->id(); expected_pair.local_candidate_id = "RTCIceCandidate_" + local_candidate->id();
expected_pair.remote_candidate_id = expected_pair.remote_candidate_id =
"RTCIceCandidate_" + remote_candidate->id(); "RTCIceCandidate_" + remote_candidate->id();
expected_pair.state = RTCStatsIceCandidatePairState::kInProgress;
expected_pair.priority = 5555;
expected_pair.writable = true; expected_pair.writable = true;
expected_pair.bytes_sent = 42; expected_pair.bytes_sent = 42;
expected_pair.bytes_received = 1234; expected_pair.bytes_received = 1234;

View File

@ -32,7 +32,6 @@ struct RTCStatsIceCandidatePairState {
static const char* kInProgress; static const char* kInProgress;
static const char* kFailed; static const char* kFailed;
static const char* kSucceeded; static const char* kSucceeded;
static const char* kCancelled;
}; };
// https://w3c.github.io/webrtc-pc/#rtcicecandidatetype-enum // https://w3c.github.io/webrtc-pc/#rtcicecandidatetype-enum
@ -120,9 +119,7 @@ class RTCIceCandidatePairStats final : public RTCStats {
RTCStatsMember<std::string> remote_candidate_id; RTCStatsMember<std::string> remote_candidate_id;
// TODO(hbos): Support enum types? // TODO(hbos): Support enum types?
// "RTCStatsMember<RTCStatsIceCandidatePairState>"? // "RTCStatsMember<RTCStatsIceCandidatePairState>"?
// TODO(hbos): Not collected by |RTCStatsCollector|. crbug.com/633550
RTCStatsMember<std::string> state; RTCStatsMember<std::string> state;
// TODO(hbos): Not collected by |RTCStatsCollector|. crbug.com/633550
RTCStatsMember<uint64_t> priority; RTCStatsMember<uint64_t> priority;
// TODO(hbos): Not collected by |RTCStatsCollector|. crbug.com/633550 // TODO(hbos): Not collected by |RTCStatsCollector|. crbug.com/633550
RTCStatsMember<bool> nominated; RTCStatsMember<bool> nominated;

View File

@ -41,6 +41,28 @@ static bool VerifyIceParams(const TransportDescription& desc) {
return true; return true;
} }
ConnectionInfo::ConnectionInfo()
: best_connection(false),
writable(false),
receiving(false),
timeout(false),
new_connection(false),
rtt(0),
sent_total_bytes(0),
sent_bytes_second(0),
sent_discarded_packets(0),
sent_total_packets(0),
sent_ping_requests_total(0),
sent_ping_requests_before_first_response(0),
sent_ping_responses(0),
recv_total_bytes(0),
recv_bytes_second(0),
recv_ping_requests(0),
recv_ping_responses(0),
key(nullptr),
state(IceCandidatePairState::WAITING),
priority(0) {}
bool BadTransportDescription(const std::string& desc, std::string* err_desc) { bool BadTransportDescription(const std::string& desc, std::string* err_desc) {
if (err_desc) { if (err_desc) {
*err_desc = desc; *err_desc = desc;

View File

@ -31,6 +31,7 @@ namespace cricket {
class TransportChannelImpl; class TransportChannelImpl;
class TransportChannelImpl; class TransportChannelImpl;
enum class IceCandidatePairState;
typedef std::vector<Candidate> Candidates; typedef std::vector<Candidate> Candidates;
@ -83,25 +84,7 @@ enum ContinualGatheringPolicy {
// Stats that we can return about the connections for a transport channel. // Stats that we can return about the connections for a transport channel.
// TODO(hta): Rename to ConnectionStats // TODO(hta): Rename to ConnectionStats
struct ConnectionInfo { struct ConnectionInfo {
ConnectionInfo() ConnectionInfo();
: best_connection(false),
writable(false),
receiving(false),
timeout(false),
new_connection(false),
rtt(0),
sent_total_bytes(0),
sent_bytes_second(0),
sent_discarded_packets(0),
sent_total_packets(0),
sent_ping_requests_total(0),
sent_ping_requests_before_first_response(0),
sent_ping_responses(0),
recv_total_bytes(0),
recv_bytes_second(0),
recv_ping_requests(0),
recv_ping_responses(0),
key(NULL) {}
bool best_connection; // Is this the best connection we have? bool best_connection; // Is this the best connection we have?
bool writable; // Has this connection received a STUN response? bool writable; // Has this connection received a STUN response?
@ -127,6 +110,10 @@ struct ConnectionInfo {
Candidate local_candidate; // The local candidate for this connection. Candidate local_candidate; // The local candidate for this connection.
Candidate remote_candidate; // The remote candidate for this connection. Candidate remote_candidate; // The remote candidate for this connection.
void* key; // A static value that identifies this conn. void* key; // A static value that identifies this conn.
// https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-state
IceCandidatePairState state;
// https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-priority
uint64_t priority;
}; };
// Information about all the connections of a channel. // Information about all the connections of a channel.

View File

@ -1012,17 +1012,8 @@ bool P2PTransportChannel::GetStats(ConnectionInfos *infos) {
for (Connection* connection : connections_) { for (Connection* connection : connections_) {
ConnectionInfo info = connection->stats(); ConnectionInfo info = connection->stats();
info.best_connection = (selected_connection_ == connection); info.best_connection = (selected_connection_ == connection);
info.receiving = connection->receiving(); infos->push_back(std::move(info));
info.writable = (connection->write_state() == Connection::STATE_WRITABLE);
info.timeout =
(connection->write_state() == Connection::STATE_WRITE_TIMEOUT);
info.new_connection = !connection->reported();
connection->set_reported(true); connection->set_reported(true);
info.rtt = connection->rtt();
info.local_candidate = connection->local_candidate();
info.remote_candidate = connection->remote_candidate();
info.key = connection;
infos->push_back(info);
} }
return true; return true;
@ -1559,7 +1550,7 @@ bool P2PTransportChannel::IsPingable(const Connection* conn,
} }
// A failed connection will not be pinged. // A failed connection will not be pinged.
if (conn->state() == Connection::STATE_FAILED) { if (conn->state() == IceCandidatePairState::FAILED) {
return false; return false;
} }

View File

@ -4017,14 +4017,14 @@ TEST_F(P2PTransportChannelPingTest, TestConnectionPrunedAgain) {
ASSERT_TRUE(conn2 != nullptr); ASSERT_TRUE(conn2 != nullptr);
EXPECT_TRUE_SIMULATED_WAIT(!conn2->active(), kDefaultTimeout, clock); EXPECT_TRUE_SIMULATED_WAIT(!conn2->active(), kDefaultTimeout, clock);
// |conn2| should not send a ping yet. // |conn2| should not send a ping yet.
EXPECT_EQ(Connection::STATE_WAITING, conn2->state()); EXPECT_EQ(IceCandidatePairState::WAITING, conn2->state());
EXPECT_EQ(TransportChannelState::STATE_COMPLETED, ch.GetState()); EXPECT_EQ(TransportChannelState::STATE_COMPLETED, ch.GetState());
// Wait for |conn1| becoming not receiving. // Wait for |conn1| becoming not receiving.
EXPECT_TRUE_SIMULATED_WAIT(!conn1->receiving(), kMediumTimeout, clock); EXPECT_TRUE_SIMULATED_WAIT(!conn1->receiving(), kMediumTimeout, clock);
// Make sure conn2 is not deleted. // Make sure conn2 is not deleted.
conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2, &clock); conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2, &clock);
ASSERT_TRUE(conn2 != nullptr); ASSERT_TRUE(conn2 != nullptr);
EXPECT_EQ_SIMULATED_WAIT(Connection::STATE_INPROGRESS, conn2->state(), EXPECT_EQ_SIMULATED_WAIT(IceCandidatePairState::IN_PROGRESS, conn2->state(),
kDefaultTimeout, clock); kDefaultTimeout, clock);
conn2->ReceivedPingResponse(LOW_RTT, "id"); conn2->ReceivedPingResponse(LOW_RTT, "id");
EXPECT_EQ_SIMULATED_WAIT(conn2, ch.selected_connection(), kDefaultTimeout, EXPECT_EQ_SIMULATED_WAIT(conn2, ch.selected_connection(), kDefaultTimeout,

View File

@ -868,7 +868,7 @@ Connection::Connection(Port* port,
last_data_received_(0), last_data_received_(0),
last_ping_response_received_(0), last_ping_response_received_(0),
reported_(false), reported_(false),
state_(STATE_WAITING), state_(IceCandidatePairState::WAITING),
receiving_timeout_(WEAK_CONNECTION_RECEIVE_TIMEOUT), receiving_timeout_(WEAK_CONNECTION_RECEIVE_TIMEOUT),
time_created_ms_(rtc::TimeMillis()) { time_created_ms_(rtc::TimeMillis()) {
// All of our connections start in WAITING state. // All of our connections start in WAITING state.
@ -937,8 +937,8 @@ void Connection::UpdateReceiving(int64_t now) {
SignalStateChange(this); SignalStateChange(this);
} }
void Connection::set_state(State state) { void Connection::set_state(IceCandidatePairState state) {
State old_state = state_; IceCandidatePairState old_state = state_;
state_ = state; state_ = state;
if (state != old_state) { if (state != old_state) {
LOG_J(LS_VERBOSE, this) << "set_state"; LOG_J(LS_VERBOSE, this) << "set_state";
@ -1126,12 +1126,12 @@ void Connection::Destroy() {
} }
void Connection::FailAndDestroy() { void Connection::FailAndDestroy() {
set_state(Connection::STATE_FAILED); set_state(IceCandidatePairState::FAILED);
Destroy(); Destroy();
} }
void Connection::FailAndPrune() { void Connection::FailAndPrune() {
set_state(Connection::STATE_FAILED); set_state(IceCandidatePairState::FAILED);
Prune(); Prune();
} }
@ -1223,7 +1223,7 @@ void Connection::Ping(int64_t now) {
<< ", id=" << rtc::hex_encode(req->id()) << ", id=" << rtc::hex_encode(req->id())
<< ", nomination=" << nomination_; << ", nomination=" << nomination_;
requests_.Send(req); requests_.Send(req);
state_ = STATE_INPROGRESS; state_ = IceCandidatePairState::IN_PROGRESS;
num_pings_sent_++; num_pings_sent_++;
} }
@ -1250,7 +1250,7 @@ void Connection::ReceivedPingResponse(int rtt, const std::string& request_id) {
last_ping_response_received_ = rtc::TimeMillis(); last_ping_response_received_ = rtc::TimeMillis();
UpdateReceiving(last_ping_response_received_); UpdateReceiving(last_ping_response_received_);
set_write_state(STATE_WRITABLE); set_write_state(STATE_WRITABLE);
set_state(STATE_SUCCEEDED); set_state(IceCandidatePairState::SUCCEEDED);
rtt_samples_++; rtt_samples_++;
rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1); rtt_ = (RTT_RATIO * rtt_ + rtt) / (RTT_RATIO + 1);
} }
@ -1331,8 +1331,8 @@ std::string Connection::ToString() const {
<< ":" << remote.protocol() << ":" << remote.address().ToSensitiveString() << ":" << remote.protocol() << ":" << remote.address().ToSensitiveString()
<< "|" << CONNECT_STATE_ABBREV[connected()] << "|" << CONNECT_STATE_ABBREV[connected()]
<< RECEIVE_STATE_ABBREV[receiving()] << WRITE_STATE_ABBREV[write_state()] << RECEIVE_STATE_ABBREV[receiving()] << WRITE_STATE_ABBREV[write_state()]
<< ICESTATE[state()] << "|" << remote_nomination() << "|" << nomination() << ICESTATE[static_cast<int>(state())] << "|" << remote_nomination() << "|"
<< "|" << priority() << "|"; << nomination() << "|" << priority() << "|";
if (rtt_ < DEFAULT_RTT) { if (rtt_ < DEFAULT_RTT) {
ss << rtt_ << "]"; ss << rtt_ << "]";
} else { } else {
@ -1471,6 +1471,16 @@ ConnectionInfo Connection::stats() {
stats_.recv_total_bytes = recv_rate_tracker_.TotalSampleCount(); stats_.recv_total_bytes = recv_rate_tracker_.TotalSampleCount();
stats_.sent_bytes_second = round(send_rate_tracker_.ComputeRate()); stats_.sent_bytes_second = round(send_rate_tracker_.ComputeRate());
stats_.sent_total_bytes = send_rate_tracker_.TotalSampleCount(); stats_.sent_total_bytes = send_rate_tracker_.TotalSampleCount();
stats_.receiving = receiving_;
stats_.writable = write_state_ == STATE_WRITABLE;
stats_.timeout = write_state_ == STATE_WRITE_TIMEOUT;
stats_.new_connection = !reported_;
stats_.rtt = rtt_;
stats_.local_candidate = local_candidate();
stats_.remote_candidate = remote_candidate();
stats_.key = this;
stats_.state = state_;
stats_.priority = priority();
return stats_; return stats_;
} }

View File

@ -92,6 +92,16 @@ enum IcePriorityValue {
ICE_TYPE_PREFERENCE_HOST = 126 ICE_TYPE_PREFERENCE_HOST = 126
}; };
// States are from RFC 5245. http://tools.ietf.org/html/rfc5245#section-5.7.4
enum class IceCandidatePairState {
WAITING = 0, // Check has not been performed, Waiting pair on CL.
IN_PROGRESS, // Check has been sent, transaction is in progress.
SUCCEEDED, // Check already done, produced a successful result.
FAILED, // Check for this connection failed.
// According to spec there should also be a frozen state, but nothing is ever
// frozen because we have not implemented ICE freezing logic.
};
const char* ProtoToString(ProtocolType proto); const char* ProtoToString(ProtocolType proto);
bool StringToProto(const char* value, ProtocolType* proto); bool StringToProto(const char* value, ProtocolType* proto);
@ -419,14 +429,6 @@ class Connection : public CandidatePairInterface,
uint32_t nomination; uint32_t nomination;
}; };
// States are from RFC 5245. http://tools.ietf.org/html/rfc5245#section-5.7.4
enum State {
STATE_WAITING = 0, // Check has not been performed, Waiting pair on CL.
STATE_INPROGRESS, // Check has been sent, transaction is in progress.
STATE_SUCCEEDED, // Check already done, produced a successful result.
STATE_FAILED // Check for this connection failed.
};
virtual ~Connection(); virtual ~Connection();
// The local port where this connection sends and receives packets. // The local port where this connection sends and receives packets.
@ -467,6 +469,8 @@ class Connection : public CandidatePairInterface,
// Estimate of the round-trip time over this connection. // Estimate of the round-trip time over this connection.
int rtt() const { return rtt_; } int rtt() const { return rtt_; }
// Gets the |ConnectionInfo| stats, where |best_connection| has not been
// populated (default value false).
ConnectionInfo stats(); ConnectionInfo stats();
sigslot::signal1<Connection*> SignalStateChange; sigslot::signal1<Connection*> SignalStateChange;
@ -575,7 +579,7 @@ class Connection : public CandidatePairInterface,
// Invoked when Connection receives STUN error response with 487 code. // Invoked when Connection receives STUN error response with 487 code.
void HandleRoleConflictFromPeer(); void HandleRoleConflictFromPeer();
State state() const { return state_; } IceCandidatePairState state() const { return state_; }
int num_pings_sent() const { return num_pings_sent_; } int num_pings_sent() const { return num_pings_sent_; }
@ -630,7 +634,7 @@ class Connection : public CandidatePairInterface,
// Changes the state and signals if necessary. // Changes the state and signals if necessary.
void set_write_state(WriteState value); void set_write_state(WriteState value);
void UpdateReceiving(int64_t now); void UpdateReceiving(int64_t now);
void set_state(State state); void set_state(IceCandidatePairState state);
void set_connected(bool value); void set_connected(bool value);
uint32_t nomination() const { return nomination_; } uint32_t nomination() const { return nomination_; }
@ -686,7 +690,7 @@ class Connection : public CandidatePairInterface,
std::vector<SentPing> pings_since_last_response_; std::vector<SentPing> pings_since_last_response_;
bool reported_; bool reported_;
State state_; IceCandidatePairState state_;
// Time duration to switch from receiving to not receiving. // Time duration to switch from receiving to not receiving.
int receiving_timeout_; int receiving_timeout_;
int64_t time_created_ms_; int64_t time_created_ms_;

View File

@ -334,7 +334,8 @@ class TurnPortTest : public testing::Test,
} }
bool CheckConnectionFailedAndPruned(Connection* conn) { bool CheckConnectionFailedAndPruned(Connection* conn) {
return conn && !conn->active() && conn->state() == Connection::STATE_FAILED; return conn && !conn->active() &&
conn->state() == IceCandidatePairState::FAILED;
} }
// Checks that |turn_port_| has a nonempty set of connections and they are all // Checks that |turn_port_| has a nonempty set of connections and they are all

View File

@ -19,10 +19,9 @@ const char* RTCDataChannelState::kClosed = "closed";
const char* RTCStatsIceCandidatePairState::kFrozen = "frozen"; const char* RTCStatsIceCandidatePairState::kFrozen = "frozen";
const char* RTCStatsIceCandidatePairState::kWaiting = "waiting"; const char* RTCStatsIceCandidatePairState::kWaiting = "waiting";
const char* RTCStatsIceCandidatePairState::kInProgress = "inprogress"; const char* RTCStatsIceCandidatePairState::kInProgress = "in-progress";
const char* RTCStatsIceCandidatePairState::kFailed = "failed"; const char* RTCStatsIceCandidatePairState::kFailed = "failed";
const char* RTCStatsIceCandidatePairState::kSucceeded = "succeeded"; const char* RTCStatsIceCandidatePairState::kSucceeded = "succeeded";
const char* RTCStatsIceCandidatePairState::kCancelled = "cancelled";
// Strings defined in https://tools.ietf.org/html/rfc5245. // Strings defined in https://tools.ietf.org/html/rfc5245.
const char* RTCIceCandidateType::kHost = "host"; const char* RTCIceCandidateType::kHost = "host";