Compute RTCConnectionState and RTCIceConnectionState.
Compute these states in jseptransportController and store them. Eventually they should be passed on to the peer connection observer and exposed in the blink layer.
Bug: webrtc:9308
Change-Id: Ifdec39c24a607fcb8211c4acf6b9704eaff371b1
Reviewed-on: https://webrtc-review.googlesource.com/c/103506
Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25288}
diff --git a/api/peerconnectioninterface.cc b/api/peerconnectioninterface.cc
index b4148d7..f2953b5 100644
--- a/api/peerconnectioninterface.cc
+++ b/api/peerconnectioninterface.cc
@@ -159,6 +159,11 @@
return SetBitrate(bitrate);
}
+PeerConnectionInterface::PeerConnectionState
+PeerConnectionInterface::peer_connection_state() {
+ return PeerConnectionInterface::PeerConnectionState::kNew;
+}
+
bool PeerConnectionInterface::StartRtcEventLog(rtc::PlatformFile file,
int64_t max_size_bytes) {
return false;
diff --git a/api/peerconnectioninterface.h b/api/peerconnectioninterface.h
index d0f96a0..a8063b10 100644
--- a/api/peerconnectioninterface.h
+++ b/api/peerconnectioninterface.h
@@ -160,7 +160,7 @@
class PeerConnectionInterface : public rtc::RefCountInterface {
public:
- // See https://w3c.github.io/webrtc-pc/#state-definitions
+ // See https://w3c.github.io/webrtc-pc/#dom-rtcsignalingstate
enum SignalingState {
kStable,
kHaveLocalOffer,
@@ -170,12 +170,24 @@
kClosed,
};
+ // See https://w3c.github.io/webrtc-pc/#dom-rtcicegatheringstate
enum IceGatheringState {
kIceGatheringNew,
kIceGatheringGathering,
kIceGatheringComplete
};
+ // See https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnectionstate
+ enum class PeerConnectionState {
+ kNew,
+ kConnecting,
+ kConnected,
+ kDisconnected,
+ kFailed,
+ kClosed,
+ };
+
+ // See https://w3c.github.io/webrtc-pc/#dom-rtciceconnectionstate
enum IceConnectionState {
kIceConnectionNew,
kIceConnectionChecking,
@@ -978,11 +990,13 @@
virtual SignalingState signaling_state() = 0;
// Returns the aggregate state of all ICE *and* DTLS transports.
- // TODO(deadbeef): Implement "PeerConnectionState" according to the standard,
- // to aggregate ICE+DTLS state, and change the scope of IceConnectionState to
- // be just the ICE layer. See: crbug.com/webrtc/6145
+ // TODO(jonasolsson): Replace with standardized_ice_connection_state once it
+ // is ready, see crbug.com/webrtc/6145
virtual IceConnectionState ice_connection_state() = 0;
+ // Returns the aggregated state of all ICE and DTLS transports.
+ virtual PeerConnectionState peer_connection_state();
+
virtual IceGatheringState ice_gathering_state() = 0;
// Starts RtcEventLog using existing file. Takes ownership of |file| and
@@ -1051,6 +1065,10 @@
virtual void OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) = 0;
+ // Called any time the PeerConnectionState changes.
+ virtual void OnConnectionChange(
+ PeerConnectionInterface::PeerConnectionState new_state) {}
+
// Called any time the IceGatheringState changes.
virtual void OnIceGatheringChange(
PeerConnectionInterface::IceGatheringState new_state) = 0;
diff --git a/p2p/base/fakedtlstransport.h b/p2p/base/fakedtlstransport.h
index 085d6e0..f28f727 100644
--- a/p2p/base/fakedtlstransport.h
+++ b/p2p/base/fakedtlstransport.h
@@ -83,6 +83,7 @@
ice_transport_->SetReceiving(receiving);
set_receiving(receiving);
}
+ void SetDtlsState(DtlsTransportState state) { dtls_state_ = state; }
// Simulates the two DTLS transports connecting to each other.
// If |asymmetric| is true this method only affects this FakeDtlsTransport.
diff --git a/p2p/base/fakeicetransport.h b/p2p/base/fakeicetransport.h
index 4ba0a2d..646aed4 100644
--- a/p2p/base/fakeicetransport.h
+++ b/p2p/base/fakeicetransport.h
@@ -115,6 +115,15 @@
}
webrtc::IceTransportState GetIceTransportState() const override {
+ if (connection_count_ == 0) {
+ return had_connection_ ? webrtc::IceTransportState::kFailed
+ : webrtc::IceTransportState::kNew;
+ }
+
+ if (connection_count_ == 1) {
+ return webrtc::IceTransportState::kCompleted;
+ }
+
return webrtc::IceTransportState::kConnected;
}
diff --git a/pc/dtlssrtptransport.cc b/pc/dtlssrtptransport.cc
index e31b2f5..2835d34 100644
--- a/pc/dtlssrtptransport.cc
+++ b/pc/dtlssrtptransport.cc
@@ -301,6 +301,8 @@
RTC_DCHECK(transport == rtp_dtls_transport_ ||
transport == rtcp_dtls_transport_);
+ SignalDtlsStateChange();
+
if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
ResetParams();
return;
diff --git a/pc/dtlssrtptransport.h b/pc/dtlssrtptransport.h
index 498f02e..cac560e 100644
--- a/pc/dtlssrtptransport.h
+++ b/pc/dtlssrtptransport.h
@@ -42,7 +42,8 @@
void UpdateRecvEncryptedHeaderExtensionIds(
const std::vector<int>& recv_extension_ids);
- sigslot::signal2<DtlsSrtpTransport*, bool> SignalDtlsSrtpSetupFailure;
+ sigslot::signal<DtlsSrtpTransport*, bool> SignalDtlsSrtpSetupFailure;
+ sigslot::signal<> SignalDtlsStateChange;
RTCError SetSrtpSendKey(const cricket::CryptoParams& params) override {
return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
diff --git a/pc/jseptransportcontroller.cc b/pc/jseptransportcontroller.cc
index 991d769..f00c22d 100644
--- a/pc/jseptransportcontroller.cc
+++ b/pc/jseptransportcontroller.cc
@@ -488,6 +488,8 @@
rtcp_dtls_transport);
dtls_srtp_transport->SetActiveResetSrtpParams(
config_.active_reset_srtp_params);
+ dtls_srtp_transport->SignalDtlsStateChange.connect(
+ this, &JsepTransportController::UpdateAggregateStates_n);
return dtls_srtp_transport;
}
@@ -1158,12 +1160,20 @@
auto dtls_transports = GetDtlsTransports();
cricket::IceConnectionState new_connection_state =
cricket::kIceConnectionConnecting;
+ PeerConnectionInterface::IceConnectionState new_ice_connection_state =
+ PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
+ PeerConnectionInterface::PeerConnectionState new_combined_state =
+ PeerConnectionInterface::PeerConnectionState::kNew;
cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
bool any_failed = false;
bool all_connected = !dtls_transports.empty();
bool all_completed = !dtls_transports.empty();
bool any_gathering = false;
bool all_done_gathering = !dtls_transports.empty();
+
+ std::map<IceTransportState, int> ice_state_counts;
+ std::map<cricket::DtlsTransportState, int> dtls_state_counts;
+
for (const auto& dtls : dtls_transports) {
any_failed = any_failed || dtls->ice_transport()->GetState() ==
cricket::IceTransportState::STATE_FAILED;
@@ -1180,6 +1190,9 @@
all_done_gathering =
all_done_gathering && dtls->ice_transport()->gathering_state() ==
cricket::kIceGatheringComplete;
+
+ dtls_state_counts[dtls->dtls_state()]++;
+ ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
}
if (any_failed) {
new_connection_state = cricket::kIceConnectionFailed;
@@ -1196,6 +1209,127 @@
});
}
+ // Compute the current RTCIceConnectionState as described in
+ // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
+ // The PeerConnection is responsible for handling the "closed" state.
+ int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
+ int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
+ int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
+ int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
+ int total_ice_disconnected =
+ ice_state_counts[IceTransportState::kDisconnected];
+ int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
+ int total_ice_new = ice_state_counts[IceTransportState::kNew];
+ int total_ice = dtls_transports.size();
+
+ if (total_ice_failed > 0) {
+ // Any of the RTCIceTransports are in the "failed" state.
+ new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
+ } else if (total_ice_disconnected > 0) {
+ // Any of the RTCIceTransports are in the "disconnected" state and none of
+ // them are in the "failed" state.
+ new_ice_connection_state =
+ PeerConnectionInterface::kIceConnectionDisconnected;
+ } else if (total_ice_checking > 0) {
+ // Any of the RTCIceTransports are in the "checking" state and none of them
+ // are in the "disconnected" or "failed" state.
+ new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
+ } else if (total_ice_completed + total_ice_closed == total_ice &&
+ total_ice_completed > 0) {
+ // All RTCIceTransports are in the "completed" or "closed" state and at
+ // least one of them is in the "completed" state.
+ new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
+ } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
+ total_ice &&
+ total_ice_connected > 0) {
+ // All RTCIceTransports are in the "connected", "completed" or "closed"
+ // state and at least one of them is in the "connected" state.
+ new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
+ } else if ((total_ice_new > 0 &&
+ total_ice_checking + total_ice_disconnected + total_ice_failed ==
+ 0) ||
+ total_ice == total_ice_closed) {
+ // Any of the RTCIceTransports are in the "new" state and none of them are
+ // in the "checking", "disconnected" or "failed" state, or all
+ // RTCIceTransports are in the "closed" state, or there are no transports.
+ new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
+ } else {
+ RTC_NOTREACHED();
+ }
+
+ if (standardized_ice_connection_state_ != new_ice_connection_state) {
+ standardized_ice_connection_state_ = new_ice_connection_state;
+ invoker_.AsyncInvoke<void>(
+ RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
+ SignalStandardizedIceConnectionState(new_ice_connection_state);
+ });
+ }
+
+ // Compute the current RTCPeerConnectionState as described in
+ // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
+ // The PeerConnection is responsible for handling the "closed" state.
+ // Note that "connecting" is only a valid state for DTLS transports while
+ // "checking", "completed" and "disconnected" are only valid for ICE
+ // transports.
+ int total_connected = total_ice_connected +
+ dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
+ int total_dtls_connecting =
+ dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
+ int total_failed =
+ total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
+ int total_closed =
+ total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
+ int total_new =
+ total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
+ int total_transports = total_ice * 2;
+
+ if (total_failed > 0) {
+ // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
+ new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
+ } else if (total_ice_disconnected > 0 &&
+ total_dtls_connecting + total_ice_checking == 0) {
+ // Any of the RTCIceTransports or RTCDtlsTransports are in the
+ // "disconnected" state and none of them are in the "failed" or "connecting"
+ // or "checking" state.
+ new_combined_state =
+ PeerConnectionInterface::PeerConnectionState::kDisconnected;
+ } else if (total_dtls_connecting + total_ice_checking > 0) {
+ // Any of the RTCIceTransports or RTCDtlsTransports are in the "connecting"
+ // or "checking" state and none of them is in the "failed" state.
+ new_combined_state =
+ PeerConnectionInterface::PeerConnectionState::kConnecting;
+ } else if (total_connected + total_ice_completed + total_closed ==
+ total_transports &&
+ total_connected + total_ice_completed > 0) {
+ // All RTCIceTransports and RTCDtlsTransports are in the "connected",
+ // "completed" or "closed" state and at least one of them is in the
+ // "connected" or "completed" state.
+ new_combined_state =
+ PeerConnectionInterface::PeerConnectionState::kConnected;
+ } else if ((total_new > 0 && total_dtls_connecting + total_ice_checking +
+ total_failed + total_ice_disconnected ==
+ 0) ||
+ total_transports == total_closed) {
+ // Any of the RTCIceTransports or RTCDtlsTransports are in the "new" state
+ // and none of the transports are in the "connecting", "checking", "failed"
+ // or "disconnected" state, or all transports are in the "closed" state, or
+ // there are no transports.
+ //
+ // Note that if none of the other conditions hold this is guaranteed to be
+ // true.
+ new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
+ } else {
+ RTC_NOTREACHED();
+ }
+
+ if (combined_connection_state_ != new_combined_state) {
+ combined_connection_state_ = new_combined_state;
+ invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
+ [this, new_combined_state] {
+ SignalConnectionState(new_combined_state);
+ });
+ }
+
if (all_done_gathering) {
new_gathering_state = cricket::kIceGatheringComplete;
} else if (any_gathering) {
diff --git a/pc/jseptransportcontroller.h b/pc/jseptransportcontroller.h
index 5d0f5ce..5747990 100644
--- a/pc/jseptransportcontroller.h
+++ b/pc/jseptransportcontroller.h
@@ -181,6 +181,11 @@
// Else => connecting
sigslot::signal1<cricket::IceConnectionState> SignalIceConnectionState;
+ sigslot::signal1<PeerConnectionInterface::PeerConnectionState>
+ SignalConnectionState;
+ sigslot::signal1<PeerConnectionInterface::IceConnectionState>
+ SignalStandardizedIceConnectionState;
+
// If all transports done gathering => complete,
// Else if any are gathering => gathering,
// Else => new
@@ -322,9 +327,16 @@
// (BaseChannel/SctpTransport) and the JsepTransport underneath.
std::map<std::string, cricket::JsepTransport*> mid_to_transport_;
- // Aggregate state for Transports.
+ // Aggregate states for Transports.
+ // standardized_ice_connection_state_ is intended to replace
+ // ice_connection_state, see bugs.webrtc.org/9308
cricket::IceConnectionState ice_connection_state_ =
cricket::kIceConnectionConnecting;
+ PeerConnectionInterface::IceConnectionState
+ standardized_ice_connection_state_ =
+ PeerConnectionInterface::kIceConnectionNew;
+ PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
+ PeerConnectionInterface::PeerConnectionState::kNew;
cricket::IceGatheringState ice_gathering_state_ = cricket::kIceGatheringNew;
Config config_;
diff --git a/pc/jseptransportcontroller_unittest.cc b/pc/jseptransportcontroller_unittest.cc
index d36b8f3..ba9b72d 100644
--- a/pc/jseptransportcontroller_unittest.cc
+++ b/pc/jseptransportcontroller_unittest.cc
@@ -84,6 +84,10 @@
void ConnectTransportControllerSignals() {
transport_controller_->SignalIceConnectionState.connect(
this, &JsepTransportControllerTest::OnConnectionState);
+ transport_controller_->SignalStandardizedIceConnectionState.connect(
+ this, &JsepTransportControllerTest::OnStandardizedIceConnectionState);
+ transport_controller_->SignalConnectionState.connect(
+ this, &JsepTransportControllerTest::OnCombinedConnectionState);
transport_controller_->SignalIceGatheringState.connect(
this, &JsepTransportControllerTest::OnGatheringState);
transport_controller_->SignalIceCandidatesGathered.connect(
@@ -243,6 +247,24 @@
++connection_state_signal_count_;
}
+ void OnStandardizedIceConnectionState(
+ PeerConnectionInterface::IceConnectionState state) {
+ if (!signaling_thread_->IsCurrent()) {
+ signaled_on_non_signaling_thread_ = true;
+ }
+ ice_connection_state_ = state;
+ ++ice_connection_state_signal_count_;
+ }
+
+ void OnCombinedConnectionState(
+ PeerConnectionInterface::PeerConnectionState state) {
+ if (!signaling_thread_->IsCurrent()) {
+ signaled_on_non_signaling_thread_ = true;
+ }
+ combined_connection_state_ = state;
+ ++combined_connection_state_signal_count_;
+ }
+
void OnGatheringState(cricket::IceGatheringState state) {
if (!signaling_thread_->IsCurrent()) {
signaled_on_non_signaling_thread_ = true;
@@ -274,12 +296,18 @@
// Information received from signals from transport controller.
cricket::IceConnectionState connection_state_ =
cricket::kIceConnectionConnecting;
+ PeerConnectionInterface::IceConnectionState ice_connection_state_ =
+ PeerConnectionInterface::kIceConnectionNew;
+ PeerConnectionInterface::PeerConnectionState combined_connection_state_ =
+ PeerConnectionInterface::PeerConnectionState::kNew;
bool receiving_ = false;
cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
// transport_name => candidates
std::map<std::string, Candidates> candidates_;
// Counts of each signal emitted.
int connection_state_signal_count_ = 0;
+ int ice_connection_state_signal_count_ = 0;
+ int combined_connection_state_signal_count_ = 0;
int receiving_signal_count_ = 0;
int gathering_state_signal_count_ = 0;
int candidates_signal_count_ = 0;
@@ -617,6 +645,12 @@
fake_ice->SetConnectionCount(0);
EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
EXPECT_EQ(1, connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::kIceConnectionFailed,
+ ice_connection_state_);
+ EXPECT_EQ(1, ice_connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kFailed,
+ combined_connection_state_);
+ EXPECT_EQ(1, combined_connection_state_signal_count_);
}
TEST_F(JsepTransportControllerTest, SignalConnectionStateConnected) {
@@ -644,13 +678,27 @@
EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
EXPECT_EQ(1, connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::kIceConnectionFailed,
+ ice_connection_state_);
+ EXPECT_EQ(1, ice_connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kFailed,
+ combined_connection_state_);
+ EXPECT_EQ(1, combined_connection_state_signal_count_);
+ fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
+ fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
// Set the connection count to be 2 and the cricket::FakeIceTransport will set
// the transport state to be STATE_CONNECTING.
fake_video_dtls->fake_ice_transport()->SetConnectionCount(2);
fake_video_dtls->SetWritable(true);
EXPECT_EQ_WAIT(cricket::kIceConnectionConnected, connection_state_, kTimeout);
EXPECT_EQ(2, connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::kIceConnectionConnected,
+ ice_connection_state_);
+ EXPECT_EQ(2, ice_connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
+ combined_connection_state_);
+ EXPECT_EQ(2, combined_connection_state_signal_count_);
}
TEST_F(JsepTransportControllerTest, SignalConnectionStateComplete) {
@@ -678,13 +726,27 @@
EXPECT_EQ_WAIT(cricket::kIceConnectionFailed, connection_state_, kTimeout);
EXPECT_EQ(1, connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::kIceConnectionFailed,
+ ice_connection_state_);
+ EXPECT_EQ(1, ice_connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kFailed,
+ combined_connection_state_);
+ EXPECT_EQ(1, combined_connection_state_signal_count_);
+ fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
+ fake_video_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
// Set the connection count to be 1 and the cricket::FakeIceTransport will set
// the transport state to be STATE_COMPLETED.
fake_video_dtls->fake_ice_transport()->SetConnectionCount(1);
fake_video_dtls->SetWritable(true);
EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
EXPECT_EQ(2, connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
+ ice_connection_state_);
+ EXPECT_EQ(2, ice_connection_state_signal_count_);
+ EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
+ combined_connection_state_);
+ EXPECT_EQ(2, combined_connection_state_signal_count_);
}
TEST_F(JsepTransportControllerTest, SignalIceGatheringStateGathering) {
@@ -758,6 +820,7 @@
fake_audio_dtls->SetWritable(true);
fake_audio_dtls->fake_ice_transport()->SetCandidatesGatheringComplete();
fake_audio_dtls->fake_ice_transport()->SetConnectionCount(1);
+ fake_audio_dtls->SetDtlsState(cricket::DTLS_TRANSPORT_CONNECTED);
EXPECT_EQ(1, gathering_state_signal_count_);
// Set the remote description and enable the bundle.
@@ -770,6 +833,10 @@
transport_controller_->GetDtlsTransport(kVideoMid1));
EXPECT_EQ(fake_audio_dtls, fake_video_dtls);
EXPECT_EQ_WAIT(cricket::kIceConnectionCompleted, connection_state_, kTimeout);
+ EXPECT_EQ(PeerConnectionInterface::kIceConnectionCompleted,
+ ice_connection_state_);
+ EXPECT_EQ(PeerConnectionInterface::PeerConnectionState::kConnected,
+ combined_connection_state_);
EXPECT_EQ_WAIT(cricket::kIceGatheringComplete, gathering_state_, kTimeout);
EXPECT_EQ(2, gathering_state_signal_count_);
}
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index ecdec61..9dc5e66 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -956,6 +956,10 @@
async_resolver_factory_.get(), config));
transport_controller_->SignalIceConnectionState.connect(
this, &PeerConnection::OnTransportControllerConnectionState);
+ transport_controller_->SignalStandardizedIceConnectionState.connect(
+ this, &PeerConnection::SetStandardizedIceConnectionState);
+ transport_controller_->SignalConnectionState.connect(
+ this, &PeerConnection::SetConnectionState);
transport_controller_->SignalIceGatheringState.connect(
this, &PeerConnection::OnTransportControllerGatheringState);
transport_controller_->SignalIceCandidatesGathered.connect(
@@ -1707,6 +1711,16 @@
return ice_connection_state_;
}
+PeerConnectionInterface::IceConnectionState
+PeerConnection::standardized_ice_connection_state() {
+ return standardized_ice_connection_state_;
+}
+
+PeerConnectionInterface::PeerConnectionState
+PeerConnection::peer_connection_state() {
+ return connection_state_;
+}
+
PeerConnectionInterface::IceGatheringState
PeerConnection::ice_gathering_state() {
return ice_gathering_state_;
@@ -3528,6 +3542,29 @@
Observer()->OnIceConnectionChange(ice_connection_state_);
}
+void PeerConnection::SetStandardizedIceConnectionState(
+ PeerConnectionInterface::IceConnectionState new_state) {
+ RTC_DCHECK(signaling_thread()->IsCurrent());
+ if (standardized_ice_connection_state_ == new_state)
+ return;
+ if (IsClosed())
+ return;
+ standardized_ice_connection_state_ = new_state;
+ // TODO(jonasolsson): Pass this value on to OnIceConnectionChange instead of
+ // the old one once disconnects are handled properly.
+}
+
+void PeerConnection::SetConnectionState(
+ PeerConnectionInterface::PeerConnectionState new_state) {
+ RTC_DCHECK(signaling_thread()->IsCurrent());
+ if (connection_state_ == new_state)
+ return;
+ if (IsClosed())
+ return;
+ connection_state_ = new_state;
+ Observer()->OnConnectionChange(new_state);
+}
+
void PeerConnection::OnIceGatheringChange(
PeerConnectionInterface::IceGatheringState new_state) {
RTC_DCHECK(signaling_thread()->IsCurrent());
@@ -3575,6 +3612,10 @@
if (signaling_state == kClosed) {
ice_connection_state_ = kIceConnectionClosed;
Observer()->OnIceConnectionChange(ice_connection_state_);
+ standardized_ice_connection_state_ =
+ PeerConnectionInterface::IceConnectionState::kIceConnectionClosed;
+ connection_state_ = PeerConnectionInterface::PeerConnectionState::kClosed;
+ Observer()->OnConnectionChange(connection_state_);
if (ice_gathering_state_ != kIceGatheringComplete) {
ice_gathering_state_ = kIceGatheringComplete;
Observer()->OnIceGatheringChange(ice_gathering_state_);
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index c1d3d40..604a5d3 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -146,6 +146,8 @@
SignalingState signaling_state() override;
IceConnectionState ice_connection_state() override;
+ IceConnectionState standardized_ice_connection_state();
+ PeerConnectionState peer_connection_state() override;
IceGatheringState ice_gathering_state() override;
const SessionDescriptionInterface* local_description() const override;
@@ -373,6 +375,11 @@
receiver);
void SetIceConnectionState(IceConnectionState new_state);
+ void SetStandardizedIceConnectionState(
+ PeerConnectionInterface::IceConnectionState new_state);
+ void SetConnectionState(
+ PeerConnectionInterface::PeerConnectionState new_state);
+
// Called any time the IceGatheringState changes
void OnIceGatheringChange(IceGatheringState new_state);
// New ICE candidate has been gathered.
@@ -950,6 +957,11 @@
SignalingState signaling_state_ = kStable;
IceConnectionState ice_connection_state_ = kIceConnectionNew;
+ PeerConnectionInterface::IceConnectionState
+ standardized_ice_connection_state_ = kIceConnectionNew;
+ PeerConnectionInterface::PeerConnectionState connection_state_ =
+ PeerConnectionState::kNew;
+
IceGatheringState ice_gathering_state_ = kIceGatheringNew;
PeerConnectionInterface::RTCConfiguration configuration_;
diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc
index 36a832c..b645ab1 100644
--- a/pc/peerconnection_integrationtest.cc
+++ b/pc/peerconnection_integrationtest.cc
@@ -318,6 +318,12 @@
ice_connection_state_history_.clear();
}
+ // Every PeerConnection state in order that has been seen by the observer.
+ std::vector<PeerConnectionInterface::PeerConnectionState>
+ peer_connection_state_history() const {
+ return peer_connection_state_history_;
+ }
+
// Every ICE gathering state in order that has been seen by the observer.
std::vector<PeerConnectionInterface::IceGatheringState>
ice_gathering_state_history() const {
@@ -914,6 +920,11 @@
EXPECT_EQ(pc()->ice_connection_state(), new_state);
ice_connection_state_history_.push_back(new_state);
}
+ void OnConnectionChange(
+ webrtc::PeerConnectionInterface::PeerConnectionState new_state) override {
+ peer_connection_state_history_.push_back(new_state);
+ }
+
void OnIceGatheringChange(
webrtc::PeerConnectionInterface::IceGatheringState new_state) override {
EXPECT_EQ(pc()->ice_gathering_state(), new_state);
@@ -1010,6 +1021,8 @@
std::vector<PeerConnectionInterface::IceConnectionState>
ice_connection_state_history_;
+ std::vector<PeerConnectionInterface::PeerConnectionState>
+ peer_connection_state_history_;
std::vector<PeerConnectionInterface::IceGatheringState>
ice_gathering_state_history_;
@@ -3562,6 +3575,17 @@
ElementsAre(PeerConnectionInterface::kIceConnectionChecking,
PeerConnectionInterface::kIceConnectionConnected,
PeerConnectionInterface::kIceConnectionCompleted));
+ // After the ice transport transitions from checking to connected we revert
+ // back to new as the standard requires, as at that point the DTLS transport
+ // is in the "new" state while no transports are "connecting", "checking",
+ // "failed" or disconnected. This is pretty unintuitive, and we might want to
+ // amend the spec to handle this case more gracefully.
+ EXPECT_THAT(
+ caller()->peer_connection_state_history(),
+ ElementsAre(PeerConnectionInterface::PeerConnectionState::kConnecting,
+ PeerConnectionInterface::PeerConnectionState::kNew,
+ PeerConnectionInterface::PeerConnectionState::kConnecting,
+ PeerConnectionInterface::PeerConnectionState::kConnected));
EXPECT_THAT(caller()->ice_gathering_state_history(),
ElementsAre(PeerConnectionInterface::kIceGatheringGathering,
PeerConnectionInterface::kIceGatheringComplete));