diff --git a/talk/app/webrtc/java/jni/peerconnection_jni.cc b/talk/app/webrtc/java/jni/peerconnection_jni.cc index 3ff20c9add..bf0f006629 100644 --- a/talk/app/webrtc/java/jni/peerconnection_jni.cc +++ b/talk/app/webrtc/java/jni/peerconnection_jni.cc @@ -1486,6 +1486,13 @@ JOW(void, PeerConnection_setRemoteDescription)( observer, JavaSdpToNativeSdp(jni, j_sdp)); } +JOW(void, PeerConnection_setIceConnectionReceivingTimeout)(JNIEnv* jni, + jobject j_pc, + jint timeout_ms) { + return ExtractNativePC(jni, j_pc) + ->SetIceConnectionReceivingTimeout(timeout_ms); +} + JOW(jboolean, PeerConnection_updateIce)( JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) { PeerConnectionInterface::IceServers ice_servers; diff --git a/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java b/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java index f20079b635..829f0fb297 100644 --- a/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java +++ b/talk/app/webrtc/java/src/org/webrtc/PeerConnection.java @@ -180,6 +180,8 @@ public class PeerConnection { public native void setRemoteDescription( SdpObserver observer, SessionDescription sdp); + public native void setIceConnectionReceivingTimeout(int timeoutMs); + public native boolean updateIce( List iceServers, MediaConstraints constraints); diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc index 0a243077bc..dba77da219 100644 --- a/talk/app/webrtc/peerconnection.cc +++ b/talk/app/webrtc/peerconnection.cc @@ -650,6 +650,10 @@ void PeerConnection::PostSetSessionDescriptionFailure( signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg); } +void PeerConnection::SetIceConnectionReceivingTimeout(int timeout_ms) { + session_->SetIceConnectionReceivingTimeout(timeout_ms); +} + bool PeerConnection::UpdateIce(const IceServers& configuration, const MediaConstraintsInterface* constraints) { return false; diff --git a/talk/app/webrtc/peerconnection.h b/talk/app/webrtc/peerconnection.h index 1f6b59f832..0162596616 100644 --- a/talk/app/webrtc/peerconnection.h +++ b/talk/app/webrtc/peerconnection.h @@ -99,6 +99,7 @@ class PeerConnection : public PeerConnectionInterface, SessionDescriptionInterface* desc); virtual void SetRemoteDescription(SetSessionDescriptionObserver* observer, SessionDescriptionInterface* desc); + virtual void SetIceConnectionReceivingTimeout(int timeout_ms); // TODO(mallinath) : Deprecated version, remove after all clients are updated. virtual bool UpdateIce(const IceServers& configuration, const MediaConstraintsInterface* constraints); diff --git a/talk/app/webrtc/peerconnectioninterface.h b/talk/app/webrtc/peerconnectioninterface.h index 521dad2695..367bafe47c 100644 --- a/talk/app/webrtc/peerconnectioninterface.h +++ b/talk/app/webrtc/peerconnectioninterface.h @@ -335,6 +335,8 @@ class PeerConnectionInterface : public rtc::RefCountInterface { // The |observer| callback will be called when done. virtual void SetRemoteDescription(SetSessionDescriptionObserver* observer, SessionDescriptionInterface* desc) = 0; + // Sets the ICE connection receiving timeout value in milliseconds. + virtual void SetIceConnectionReceivingTimeout(int timeout_ms) = 0; // Restarts or updates the ICE Agent process of gathering local candidates // and pinging remote candidates. virtual bool UpdateIce(const IceServers& configuration, diff --git a/talk/app/webrtc/peerconnectionproxy.h b/talk/app/webrtc/peerconnectionproxy.h index 2f015cdf19..0959d3fe91 100644 --- a/talk/app/webrtc/peerconnectionproxy.h +++ b/talk/app/webrtc/peerconnectionproxy.h @@ -62,6 +62,7 @@ BEGIN_PROXY_MAP(PeerConnection) const MediaConstraintsInterface*) PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*) PROXY_METHOD1(void, RegisterUMAObserver, UMAObserver*) + PROXY_METHOD1(void, SetIceConnectionReceivingTimeout, int) PROXY_METHOD0(SignalingState, signaling_state) PROXY_METHOD0(IceState, ice_state) PROXY_METHOD0(IceConnectionState, ice_connection_state) diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h index ee6ac7e347..1bf77b6566 100644 --- a/webrtc/p2p/base/dtlstransportchannel.h +++ b/webrtc/p2p/base/dtlstransportchannel.h @@ -204,6 +204,10 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl { channel_->OnCandidate(candidate); } + void SetReceivingTimeout(int receiving_timeout_ms) { + channel_->SetReceivingTimeout(receiving_timeout_ms); + } + // Needed by DtlsTransport. TransportChannelImpl* channel() { return channel_; } diff --git a/webrtc/p2p/base/fakesession.h b/webrtc/p2p/base/fakesession.h index c6da75480f..67b770ae5c 100644 --- a/webrtc/p2p/base/fakesession.h +++ b/webrtc/p2p/base/fakesession.h @@ -181,6 +181,8 @@ class FakeTransportChannel : public TransportChannelImpl, set_receiving(receiving); } + void SetReceivingTimeout(int timeout) override {} + virtual int SendPacket(const char* data, size_t len, const rtc::PacketOptions& options, int flags) { if (state_ != STATE_CONNECTED) { diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc index 1484d17158..46ed40ad76 100644 --- a/webrtc/p2p/base/p2ptransportchannel.cc +++ b/webrtc/p2p/base/p2ptransportchannel.cc @@ -359,10 +359,15 @@ void P2PTransportChannel::SetRemoteIceMode(IceMode mode) { remote_ice_mode_ = mode; } -void P2PTransportChannel::set_receiving_timeout(int receiving_timeout_ms) { +void P2PTransportChannel::SetReceivingTimeout(int receiving_timeout_ms) { + if (receiving_timeout_ms < 0) { + return; + } receiving_timeout_ = receiving_timeout_ms; check_receiving_delay_ = std::max(MIN_CHECK_RECEIVING_DELAY, receiving_timeout_ / 10); + LOG(LS_VERBOSE) << "Set ICE receiving timeout to " << receiving_timeout_ + << " milliseconds"; } // Go into the state of processing candidates, and running in general diff --git a/webrtc/p2p/base/p2ptransportchannel.h b/webrtc/p2p/base/p2ptransportchannel.h index 5405a9c0c7..b8ad5e23bc 100644 --- a/webrtc/p2p/base/p2ptransportchannel.h +++ b/webrtc/p2p/base/p2ptransportchannel.h @@ -87,7 +87,7 @@ class P2PTransportChannel : public TransportChannelImpl, // Sets the receiving timeout in milliseconds. // This also sets the check_receiving_delay proportionally. - void set_receiving_timeout(int receiving_timeout_ms); + void SetReceivingTimeout(int receiving_timeout_ms) override; // Note: This is only for testing purpose. // |ports_| should not be changed from outside. diff --git a/webrtc/p2p/base/p2ptransportchannel_unittest.cc b/webrtc/p2p/base/p2ptransportchannel_unittest.cc index 80e59bacf0..68c46d6a74 100644 --- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc +++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc @@ -1870,7 +1870,7 @@ TEST_F(P2PTransportChannelPingTest, TestReceivingStateChange) { // small. EXPECT_LE(1000, ch.receiving_timeout()); EXPECT_LE(200, ch.check_receiving_delay()); - ch.set_receiving_timeout(500); + ch.SetReceivingTimeout(500); EXPECT_EQ(500, ch.receiving_timeout()); EXPECT_EQ(50, ch.check_receiving_delay()); ch.Connect(); diff --git a/webrtc/p2p/base/rawtransportchannel.h b/webrtc/p2p/base/rawtransportchannel.h index 10da168aa1..75b494e65a 100644 --- a/webrtc/p2p/base/rawtransportchannel.h +++ b/webrtc/p2p/base/rawtransportchannel.h @@ -156,6 +156,8 @@ class RawTransportChannel : public TransportChannelImpl, return false; } + void SetReceivingTimeout(int timeout) override {} + private: RawTransport* raw_transport_; rtc::Thread *worker_thread_; diff --git a/webrtc/p2p/base/session.cc b/webrtc/p2p/base/session.cc index ca0525dd85..fb8480ee5e 100644 --- a/webrtc/p2p/base/session.cc +++ b/webrtc/p2p/base/session.cc @@ -344,7 +344,8 @@ BaseSession::BaseSession(rtc::Thread* signaling_thread, identity_(NULL), ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_10), ice_tiebreaker_(rtc::CreateRandomId64()), - role_switch_(false) { + role_switch_(false), + ice_receiving_timeout_(-1) { ASSERT(signaling_thread->IsCurrent()); } @@ -477,6 +478,16 @@ bool BaseSession::PushdownRemoteTransportDescription( return true; } +void BaseSession::SetIceConnectionReceivingTimeout(int timeout_ms) { + ice_receiving_timeout_ = timeout_ms; + for (const auto& kv : transport_proxies()) { + Transport* transport = kv.second->impl(); + if (transport) { + transport->SetChannelReceivingTimeout(timeout_ms); + } + } +} + TransportChannel* BaseSession::CreateChannel(const std::string& content_name, int component) { // We create the proxy "on demand" here because we need to support @@ -566,12 +577,13 @@ void BaseSession::DestroyTransportProxy( } } -cricket::Transport* BaseSession::CreateTransport( - const std::string& content_name) { +Transport* BaseSession::CreateTransport(const std::string& content_name) { ASSERT(transport_type_ == NS_GINGLE_P2P); - return new cricket::DtlsTransport( - signaling_thread(), worker_thread(), content_name, - port_allocator(), identity_); + Transport* transport = new DtlsTransport( + signaling_thread(), worker_thread(), content_name, port_allocator(), + identity_); + transport->SetChannelReceivingTimeout(ice_receiving_timeout_); + return transport; } void BaseSession::SetState(State state) { diff --git a/webrtc/p2p/base/session.h b/webrtc/p2p/base/session.h index 8f9e308a86..19ce3611b0 100644 --- a/webrtc/p2p/base/session.h +++ b/webrtc/p2p/base/session.h @@ -319,6 +319,9 @@ class BaseSession : public sigslot::has_slots<>, rtc::SSLIdentity* identity() { return identity_; } + // Set the ice connection receiving timeout. + void SetIceConnectionReceivingTimeout(int timeout_ms); + protected: // Specifies the identity to use in this session. bool SetIdentity(rtc::SSLIdentity* identity); @@ -453,6 +456,10 @@ class BaseSession : public sigslot::has_slots<>, // will enable us to stop any role switch during the call. bool role_switch_; TransportMap transports_; + + // Timeout value in milliseconds for which no ICE connection receives + // any packets. + int ice_receiving_timeout_; }; } // namespace cricket diff --git a/webrtc/p2p/base/session_unittest.cc b/webrtc/p2p/base/session_unittest.cc new file mode 100644 index 0000000000..3419cc3c46 --- /dev/null +++ b/webrtc/p2p/base/session_unittest.cc @@ -0,0 +1,100 @@ +/* + * Copyright 2015 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. + */ + +#include "webrtc/base/gunit.h" +#include "webrtc/base/helpers.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/base/thread.h" +#include "webrtc/p2p/base/dtlstransportchannel.h" +#include "webrtc/p2p/base/p2ptransportchannel.h" +#include "webrtc/p2p/base/portallocator.h" +#include "webrtc/p2p/base/session.h" +#include "webrtc/p2p/base/transportchannelproxy.h" +#include "webrtc/p2p/client/fakeportallocator.h" + +using cricket::BaseSession; +using cricket::DtlsTransportChannelWrapper; +using cricket::FakePortAllocator; +using cricket::P2PTransportChannel; +using cricket::PortAllocator; +using cricket::TransportChannelProxy; +using cricket::TransportProxy; + +class BaseSessionForTest : public BaseSession { + public: + BaseSessionForTest(rtc::Thread* signaling_thread, + rtc::Thread* worker_thread, + PortAllocator* port_allocator, + const std::string& sid, + const std::string& content_type, + bool initiator) + : BaseSession(signaling_thread, + worker_thread, + port_allocator, + sid, + content_type, + initiator) {} + using BaseSession::GetOrCreateTransportProxy; +}; + +class BaseSessionTest : public testing::Test { + public: + BaseSessionTest() + : port_allocator_(new FakePortAllocator(rtc::Thread::Current(), nullptr)), + session_(new BaseSessionForTest(rtc::Thread::Current(), + rtc::Thread::Current(), + port_allocator_.get(), + "123", + cricket::NS_JINGLE_RTP, + false)) {} + P2PTransportChannel* CreateChannel(const std::string& content, + int component) { + TransportProxy* transport_proxy = + session_->GetOrCreateTransportProxy(content); + // This hacking is needed in order that the p2p transport channel + // will be created in the following. + transport_proxy->CompleteNegotiation(); + + TransportChannelProxy* channel_proxy = static_cast( + session_->CreateChannel(content, component)); + DtlsTransportChannelWrapper* dtls_channel = + static_cast(channel_proxy->impl()); + return static_cast(dtls_channel->channel()); + } + + rtc::scoped_ptr port_allocator_; + rtc::scoped_ptr session_; +}; + +TEST_F(BaseSessionTest, TestSetIceReceivingTimeout) { + P2PTransportChannel* channel1 = CreateChannel("audio", 1); + ASSERT_NE(channel1, nullptr); + // These are the default values. + EXPECT_EQ(2500, channel1->receiving_timeout()); + EXPECT_EQ(250, channel1->check_receiving_delay()); + // Set the timeout to a different value. + session_->SetIceConnectionReceivingTimeout(1000); + EXPECT_EQ(1000, channel1->receiving_timeout()); + EXPECT_EQ(100, channel1->check_receiving_delay()); + + // Even if a channel is created after setting the receiving timeout, + // the set timeout value is applied to the new channel. + P2PTransportChannel* channel2 = CreateChannel("video", 2); + ASSERT_NE(channel2, nullptr); + EXPECT_EQ(1000, channel2->receiving_timeout()); + EXPECT_EQ(100, channel2->check_receiving_delay()); + + // Test minimum checking delay. + session_->SetIceConnectionReceivingTimeout(200); + EXPECT_EQ(200, channel1->receiving_timeout()); + EXPECT_EQ(50, channel1->check_receiving_delay()); + EXPECT_EQ(200, channel2->receiving_timeout()); + EXPECT_EQ(50, channel2->check_receiving_delay()); +} diff --git a/webrtc/p2p/base/transport.cc b/webrtc/p2p/base/transport.cc index f9b7fd4a04..b96ae842b4 100644 --- a/webrtc/p2p/base/transport.cc +++ b/webrtc/p2p/base/transport.cc @@ -121,21 +121,22 @@ Transport::Transport(rtc::Thread* signaling_thread, const std::string& content_name, const std::string& type, PortAllocator* allocator) - : signaling_thread_(signaling_thread), - worker_thread_(worker_thread), - content_name_(content_name), - type_(type), - allocator_(allocator), - destroyed_(false), - readable_(TRANSPORT_STATE_NONE), - writable_(TRANSPORT_STATE_NONE), - receiving_(TRANSPORT_STATE_NONE), - was_writable_(false), - connect_requested_(false), - ice_role_(ICEROLE_UNKNOWN), - tiebreaker_(0), - protocol_(ICEPROTO_HYBRID), - remote_ice_mode_(ICEMODE_FULL) { + : signaling_thread_(signaling_thread), + worker_thread_(worker_thread), + content_name_(content_name), + type_(type), + allocator_(allocator), + destroyed_(false), + readable_(TRANSPORT_STATE_NONE), + writable_(TRANSPORT_STATE_NONE), + receiving_(TRANSPORT_STATE_NONE), + was_writable_(false), + connect_requested_(false), + ice_role_(ICEROLE_UNKNOWN), + tiebreaker_(0), + protocol_(ICEPROTO_HYBRID), + remote_ice_mode_(ICEMODE_FULL), + channel_receiving_timeout_(-1) { } Transport::~Transport() { @@ -174,6 +175,19 @@ bool Transport::GetRemoteCertificate_w(rtc::SSLCertificate** cert) { return iter->second->GetRemoteCertificate(cert); } +void Transport::SetChannelReceivingTimeout(int timeout_ms) { + worker_thread_->Invoke( + Bind(&Transport::SetChannelReceivingTimeout_w, this, timeout_ms)); +} + +void Transport::SetChannelReceivingTimeout_w(int timeout_ms) { + ASSERT(worker_thread()->IsCurrent()); + channel_receiving_timeout_ = timeout_ms; + for (const auto& kv : channels_) { + kv.second->SetReceivingTimeout(timeout_ms); + } +} + bool Transport::SetLocalTransportDescription( const TransportDescription& description, ContentAction action, @@ -233,6 +247,7 @@ TransportChannelImpl* Transport::CreateChannel_w(int component) { // Push down our transport state to the new channel. impl->SetIceRole(ice_role_); impl->SetIceTiebreaker(tiebreaker_); + impl->SetReceivingTimeout(channel_receiving_timeout_); // TODO(ronghuawu): Change CreateChannel_w to be able to return error since // below Apply**Description_w calls can fail. if (local_description_) diff --git a/webrtc/p2p/base/transport.h b/webrtc/p2p/base/transport.h index 2230b9fe8a..6064bdb54d 100644 --- a/webrtc/p2p/base/transport.h +++ b/webrtc/p2p/base/transport.h @@ -200,6 +200,8 @@ class Transport : public rtc::MessageHandler, void SetIceTiebreaker(uint64 IceTiebreaker) { tiebreaker_ = IceTiebreaker; } uint64 IceTiebreaker() { return tiebreaker_; } + void SetChannelReceivingTimeout(int timeout_ms); + // Must be called before applying local session description. void SetIdentity(rtc::SSLIdentity* identity); @@ -438,6 +440,8 @@ class Transport : public rtc::MessageHandler, bool GetStats_w(TransportStats* infos); bool GetRemoteCertificate_w(rtc::SSLCertificate** cert); + void SetChannelReceivingTimeout_w(int timeout_ms); + // Sends SignalCompleted if we are now in that state. void MaybeCompleted_w(); @@ -456,6 +460,7 @@ class Transport : public rtc::MessageHandler, uint64 tiebreaker_; TransportProtocol protocol_; IceMode remote_ice_mode_; + int channel_receiving_timeout_; rtc::scoped_ptr local_description_; rtc::scoped_ptr remote_description_; diff --git a/webrtc/p2p/base/transportchannelimpl.h b/webrtc/p2p/base/transportchannelimpl.h index f57b76e33d..705550b52a 100644 --- a/webrtc/p2p/base/transportchannelimpl.h +++ b/webrtc/p2p/base/transportchannelimpl.h @@ -52,6 +52,8 @@ class TransportChannelImpl : public TransportChannel { // SetRemoteIceMode must be implemented only by the ICE transport channels. virtual void SetRemoteIceMode(IceMode mode) = 0; + virtual void SetReceivingTimeout(int timeout_ms) = 0; + // Begins the process of attempting to make a connection to the other client. virtual void Connect() = 0; diff --git a/webrtc/p2p/p2p_tests.gypi b/webrtc/p2p/p2p_tests.gypi index c685a95412..133e9880ff 100644 --- a/webrtc/p2p/p2p_tests.gypi +++ b/webrtc/p2p/p2p_tests.gypi @@ -21,6 +21,7 @@ 'base/pseudotcp_unittest.cc', 'base/relayport_unittest.cc', 'base/relayserver_unittest.cc', + 'base/session_unittest.cc', 'base/stun_unittest.cc', 'base/stunport_unittest.cc', 'base/stunrequest_unittest.cc',