Implement (mostly) standards-compliant RTCIceTransportState.
In order to correctly implement RTCPeerConnectionState and RTCIceConnectionState the ice transports need to support RTCIceTransportState.
This CL adds an implementation parallel to the current non-standard IceTransportState. It's not currently used anywhere. The old implementation will remain in place until we're ready to switch RTCIceConnectionState over.
Bug: webrtc:9308
Change-Id: I30e2bbb5b4fafa410261bcd9d5e3b76c03435feb
Reviewed-on: https://webrtc-review.googlesource.com/c/103220
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25078}
diff --git a/api/transport/BUILD.gn b/api/transport/BUILD.gn
index 5466061..9341da9 100644
--- a/api/transport/BUILD.gn
+++ b/api/transport/BUILD.gn
@@ -19,6 +19,13 @@
]
}
+rtc_source_set("enums") {
+ visibility = [ "*" ]
+ sources = [
+ "enums.h",
+ ]
+}
+
rtc_static_library("network_control") {
sources = [
"network_control.h",
diff --git a/api/transport/enums.h b/api/transport/enums.h
new file mode 100644
index 0000000..b1d5770
--- /dev/null
+++ b/api/transport/enums.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef API_TRANSPORT_ENUMS_H_
+#define API_TRANSPORT_ENUMS_H_
+
+namespace webrtc {
+
+// See https://w3c.github.io/webrtc-pc/#rtcicetransportstate
+// Note that kFailed is currently not a terminal state, and a transport might
+// incorrectly be marked as failed while gathering candidates, see
+// bugs.webrtc.org/8833
+enum class IceTransportState {
+ kNew,
+ kChecking,
+ kConnected,
+ kCompleted,
+ kFailed,
+ kDisconnected,
+ kClosed,
+};
+
+} // namespace webrtc
+
+#endif // API_TRANSPORT_ENUMS_H_
diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn
index 2d351bb..5d4e706 100644
--- a/p2p/BUILD.gn
+++ b/p2p/BUILD.gn
@@ -86,6 +86,7 @@
deps = [
"../api:libjingle_peerconnection_api",
"../api:ortc_api",
+ "../api/transport:enums",
"../logging:ice_log",
"../rtc_base:checks",
"../rtc_base:rtc_base",
diff --git a/p2p/base/fakeicetransport.h b/p2p/base/fakeicetransport.h
index 4815745..4ba0a2d 100644
--- a/p2p/base/fakeicetransport.h
+++ b/p2p/base/fakeicetransport.h
@@ -114,6 +114,10 @@
return IceTransportState::STATE_CONNECTING;
}
+ webrtc::IceTransportState GetIceTransportState() const override {
+ return webrtc::IceTransportState::kConnected;
+ }
+
void SetIceRole(IceRole role) override { role_ = role; }
IceRole GetIceRole() const override { return role_; }
void SetIceTiebreaker(uint64_t tiebreaker) override {
diff --git a/p2p/base/icetransportinternal.h b/p2p/base/icetransportinternal.h
index 7483c3b..31e7078 100644
--- a/p2p/base/icetransportinternal.h
+++ b/p2p/base/icetransportinternal.h
@@ -15,6 +15,7 @@
#include <vector>
#include "api/candidate.h"
+#include "api/transport/enums.h"
#include "p2p/base/candidatepairinterface.h"
#include "p2p/base/packettransportinternal.h"
#include "p2p/base/port.h"
@@ -188,7 +189,10 @@
IceTransportInternal();
~IceTransportInternal() override;
+ // TODO(bugs.webrtc.org/9308): Remove GetState once all uses have been
+ // migrated to GetIceTransportState.
virtual IceTransportState GetState() const = 0;
+ virtual webrtc::IceTransportState GetIceTransportState() const = 0;
virtual int component() const = 0;
@@ -258,8 +262,13 @@
sigslot::signal1<IceTransportInternal*> SignalRoleConflict;
// Emitted whenever the transport state changed.
+ // TODO(bugs.webrtc.org/9308): Remove once all uses have migrated to the new
+ // IceTransportState.
sigslot::signal1<IceTransportInternal*> SignalStateChanged;
+ // Emitted whenever the new standards-compliant transport state changed.
+ sigslot::signal1<IceTransportInternal*> SignalIceTransportStateChanged;
+
// Invoked when the transport is being destroyed.
sigslot::signal1<IceTransportInternal*> SignalDestroyed;
};
diff --git a/p2p/base/mockicetransport.h b/p2p/base/mockicetransport.h
index d1863c5..b18ce3d 100644
--- a/p2p/base/mockicetransport.h
+++ b/p2p/base/mockicetransport.h
@@ -47,6 +47,10 @@
IceTransportState GetState() const override {
return IceTransportState::STATE_INIT;
}
+ webrtc::IceTransportState GetIceTransportState() const override {
+ return webrtc::IceTransportState::kNew;
+ }
+
const std::string& transport_name() const override { return transport_name_; }
int component() const override { return 0; }
void SetIceRole(IceRole role) override {}
diff --git a/p2p/base/p2ptransportchannel.cc b/p2p/base/p2ptransportchannel.cc
index b0abe24..b5de0e6 100644
--- a/p2p/base/p2ptransportchannel.cc
+++ b/p2p/base/p2ptransportchannel.cc
@@ -323,6 +323,10 @@
return state_;
}
+webrtc::IceTransportState P2PTransportChannel::GetIceTransportState() const {
+ return standardized_state_;
+}
+
const std::string& P2PTransportChannel::transport_name() const {
return transport_name_;
}
@@ -387,6 +391,41 @@
return IceTransportState::STATE_COMPLETED;
}
+// Compute the current RTCIceTransportState as described in
+// https://www.w3.org/TR/webrtc/#dom-rtcicetransportstate
+// TODO(bugs.webrtc.org/9308): Return IceTransportState::kDisconnected when it
+// makes sense.
+// TODO(bugs.webrtc.org/9218): Avoid prematurely signalling kFailed once we have
+// implemented end-of-candidates signalling.
+webrtc::IceTransportState P2PTransportChannel::ComputeIceTransportState()
+ const {
+ bool has_connection = false;
+ for (Connection* connection : connections_) {
+ if (connection->active()) {
+ has_connection = true;
+ break;
+ }
+ }
+
+ switch (gathering_state_) {
+ case kIceGatheringComplete:
+ if (has_connection)
+ return webrtc::IceTransportState::kCompleted;
+ else
+ return webrtc::IceTransportState::kFailed;
+ case kIceGatheringNew:
+ return webrtc::IceTransportState::kNew;
+ case kIceGatheringGathering:
+ if (has_connection)
+ return webrtc::IceTransportState::kConnected;
+ else
+ return webrtc::IceTransportState::kChecking;
+ default:
+ RTC_NOTREACHED();
+ return webrtc::IceTransportState::kFailed;
+ }
+}
+
void P2PTransportChannel::SetIceParameters(const IceParameters& ice_params) {
RTC_DCHECK(network_thread_ == rtc::Thread::Current());
RTC_LOG(LS_INFO) << "Set ICE ufrag: " << ice_params.ufrag
@@ -1827,6 +1866,9 @@
// example, we call this at the end of SortConnectionsAndUpdateState.
void P2PTransportChannel::UpdateState() {
IceTransportState state = ComputeState();
+ webrtc::IceTransportState current_standardized_state =
+ ComputeIceTransportState();
+
if (state_ != state) {
RTC_LOG(LS_INFO) << ToString()
<< ": Transport channel state changed from "
@@ -1868,6 +1910,10 @@
SignalStateChanged(this);
}
+ if (standardized_state_ != current_standardized_state) {
+ standardized_state_ = current_standardized_state;
+ SignalIceTransportStateChanged(this);
+ }
// If our selected connection is "presumed writable" (TURN-TURN with no
// CreatePermission required), act like we're already writable to the upper
// layers, so they can start media quicker.
diff --git a/p2p/base/p2ptransportchannel.h b/p2p/base/p2ptransportchannel.h
index fbed344..84d2879 100644
--- a/p2p/base/p2ptransportchannel.h
+++ b/p2p/base/p2ptransportchannel.h
@@ -91,6 +91,8 @@
// From TransportChannelImpl:
IceTransportState GetState() const override;
+ webrtc::IceTransportState GetIceTransportState() const override;
+
const std::string& transport_name() const override;
int component() const override;
bool writable() const override;
@@ -243,7 +245,13 @@
void UpdateState();
void HandleAllTimedOut();
void MaybeStopPortAllocatorSessions();
+
+ // ComputeIceTransportState computes the RTCIceTransportState as described in
+ // https://w3c.github.io/webrtc-pc/#dom-rtcicetransportstate. ComputeState
+ // computes the value we currently export as RTCIceTransportState.
+ // TODO(bugs.webrtc.org/9308): Remove ComputeState once it's no longer used.
IceTransportState ComputeState() const;
+ webrtc::IceTransportState ComputeIceTransportState() const;
Connection* GetBestConnectionOnNetwork(rtc::Network* network) const;
bool CreateConnections(const Candidate& remote_candidate,
@@ -407,7 +415,11 @@
std::unique_ptr<webrtc::BasicRegatheringController> regathering_controller_;
int64_t last_ping_sent_ms_ = 0;
int weak_ping_interval_ = WEAK_PING_INTERVAL;
+ // TODO(jonasolsson): Remove state_ and rename standardized_state_ once state_
+ // is no longer used to compute the ICE connection state.
IceTransportState state_ = IceTransportState::STATE_INIT;
+ webrtc::IceTransportState standardized_state_ =
+ webrtc::IceTransportState::kNew;
IceConfig config_;
int last_sent_packet_id_ = -1; // -1 indicates no packet was sent before.
bool started_pinging_ = false;
diff --git a/p2p/base/p2ptransportchannel_unittest.cc b/p2p/base/p2ptransportchannel_unittest.cc
index 76b918c..9b0bcb2 100644
--- a/p2p/base/p2ptransportchannel_unittest.cc
+++ b/p2p/base/p2ptransportchannel_unittest.cc
@@ -4137,6 +4137,7 @@
clock.AdvanceTime(webrtc::TimeDelta::seconds(1));
FakePortAllocator pa(rtc::Thread::Current(), nullptr);
P2PTransportChannel ch("test channel", 1, &pa);
+ EXPECT_EQ(webrtc::IceTransportState::kNew, ch.GetIceTransportState());
PrepareChannel(&ch);
ch.MaybeStartGathering();
EXPECT_EQ(IceTransportState::STATE_INIT, ch.GetState());
@@ -4144,6 +4145,8 @@
ch.AddRemoteCandidate(CreateUdpCandidate(LOCAL_PORT_TYPE, "2.2.2.2", 2, 1));
Connection* conn1 = WaitForConnectionTo(&ch, "1.1.1.1", 1, &clock);
Connection* conn2 = WaitForConnectionTo(&ch, "2.2.2.2", 2, &clock);
+ // Gathering complete with candidates.
+ EXPECT_EQ(webrtc::IceTransportState::kCompleted, ch.GetIceTransportState());
ASSERT_TRUE(conn1 != nullptr);
ASSERT_TRUE(conn2 != nullptr);
// Now there are two connections, so the transport channel is connecting.
@@ -4156,6 +4159,7 @@
// Need to wait until the channel state is updated.
EXPECT_EQ_SIMULATED_WAIT(IceTransportState::STATE_FAILED, ch.GetState(),
kShortTimeout, clock);
+ EXPECT_EQ(webrtc::IceTransportState::kFailed, ch.GetIceTransportState());
}
// Test that when a low-priority connection is pruned, it is not deleted