From 9763d56464b9f660e21a6737a73155009d5b3e00 Mon Sep 17 00:00:00 2001 From: zhihuang Date: Fri, 5 Aug 2016 11:14:50 -0700 Subject: [PATCH] Modified PeerConnection and WebRtcSession for end-to-end QuicDataChannel usage. To allow end-to-end QuicDataChannel usage with a PeerConnection, RTCConfiguration has been modified to include a boolean for whether to do QUIC, since negotiation of QUIC is not implemented. If one peer does QUIC, then it will be assumed that the other peer must do QUIC or the connection will fail. PeerConnection has been modified to create data channels of type QuicDataChannel when the peer wants to do QUIC. WebRtcSession has ben modified to use a QuicDataTransport instead of a DtlsTransportChannelWrapper/DataChannel when QUIC should be used QuicDataTransport implements the generic functions of BaseChannel to manage the QuicTransportChannel. Committed: https://crrev.com/34b54c36a533dadb6ceb70795119194e6f530ef5 Review-Url: https://codereview.webrtc.org/2166873002 Cr-Original-Commit-Position: refs/heads/master@{#13645} Cr-Commit-Position: refs/heads/master@{#13657} --- webrtc/api/peerconnection.cc | 40 +++++- webrtc/api/peerconnection_unittest.cc | 131 ++++++++++++++---- webrtc/api/peerconnectionendtoend_unittest.cc | 85 +++++++++++- webrtc/api/peerconnectioninterface.h | 1 + .../api/peerconnectioninterface_unittest.cc | 131 +++++++++--------- webrtc/api/quicdatatransport.cc | 59 +++++++- webrtc/api/quicdatatransport.h | 34 ++++- webrtc/api/quicdatatransport_unittest.cc | 56 ++++---- webrtc/api/test/peerconnectiontestwrapper.cc | 8 +- webrtc/api/test/peerconnectiontestwrapper.h | 4 +- webrtc/api/webrtcsession.cc | 87 ++++++++++-- webrtc/api/webrtcsession.h | 23 +++ webrtc/api/webrtcsession_unittest.cc | 26 +++- webrtc/media/base/mediaengine.h | 6 +- webrtc/p2p/base/faketransportcontroller.h | 24 ++++ webrtc/p2p/quic/quictransportchannel.h | 2 + 16 files changed, 554 insertions(+), 163 deletions(-) diff --git a/webrtc/api/peerconnection.cc b/webrtc/api/peerconnection.cc index 4ccd6e83ad..c675015ac9 100644 --- a/webrtc/api/peerconnection.cc +++ b/webrtc/api/peerconnection.cc @@ -907,6 +907,23 @@ PeerConnection::CreateDataChannel( const std::string& label, const DataChannelInit* config) { TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel"); +#ifdef HAVE_QUIC + if (session_->data_channel_type() == cricket::DCT_QUIC) { + // TODO(zhihuang): Handle case when config is NULL. + if (!config) { + LOG(LS_ERROR) << "Missing config for QUIC data channel."; + return nullptr; + } + // TODO(zhihuang): Allow unreliable or ordered QUIC data channels. + if (!config->reliable || config->ordered) { + LOG(LS_ERROR) << "QUIC data channel does not implement unreliable or " + "ordered delivery."; + return nullptr; + } + return session_->quic_data_transport()->CreateDataChannel(label, config); + } +#endif // HAVE_QUIC + bool first_datachannel = !HasDataChannels(); std::unique_ptr internal_config; @@ -1618,8 +1635,13 @@ bool PeerConnection::GetOptionsForOffer( (session_options->has_audio() || session_options->has_video() || session_options->has_data()); - if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) { - session_options->data_channel_type = cricket::DCT_SCTP; + // Intentionally unset the data channel type for RTP data channel with the + // second condition. Otherwise the RTP data channels would be successfully + // negotiated by default and the unit tests in WebRtcDataBrowserTest will fail + // when building with chromium. We want to leave RTP data channels broken, so + // people won't try to use them. + if (HasDataChannels() && session_->data_channel_type() != cricket::DCT_RTP) { + session_options->data_channel_type = session_->data_channel_type(); } session_options->rtcp_cname = rtcp_cname_; @@ -1648,8 +1670,12 @@ void PeerConnection::FinishOptionsForAnswer( // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams // are not signaled in the SDP so does not go through that path and must be // handled here. - if (session_->data_channel_type() == cricket::DCT_SCTP) { - session_options->data_channel_type = cricket::DCT_SCTP; + // Intentionally unset the data channel type for RTP data channel. Otherwise + // the RTP data channels would be successfully negotiated by default and the + // unit tests in WebRtcDataBrowserTest will fail when building with chromium. + // We want to leave RTP data channels broken, so people won't try to use them. + if (session_->data_channel_type() != cricket::DCT_RTP) { + session_options->data_channel_type = session_->data_channel_type(); } session_options->crypto_options = factory_->options().crypto_options; } @@ -2054,7 +2080,13 @@ rtc::scoped_refptr PeerConnection::InternalCreateDataChannel( } bool PeerConnection::HasDataChannels() const { +#ifdef HAVE_QUIC + return !rtp_data_channels_.empty() || !sctp_data_channels_.empty() || + (session_->quic_data_transport() && + session_->quic_data_transport()->HasDataChannels()); +#else return !rtp_data_channels_.empty() || !sctp_data_channels_.empty(); +#endif // HAVE_QUIC } void PeerConnection::AllocateSctpSids(rtc::SSLRole role) { diff --git a/webrtc/api/peerconnection_unittest.cc b/webrtc/api/peerconnection_unittest.cc index 18d360692f..406fab0d89 100644 --- a/webrtc/api/peerconnection_unittest.cc +++ b/webrtc/api/peerconnection_unittest.cc @@ -174,12 +174,13 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, const std::string& id, const MediaConstraintsInterface* constraints, const PeerConnectionFactory::Options* options, + const PeerConnectionInterface::RTCConfiguration& config, std::unique_ptr cert_generator, bool prefer_constraint_apis, rtc::Thread* network_thread, rtc::Thread* worker_thread) { PeerConnectionTestClient* client(new PeerConnectionTestClient(id)); - if (!client->Init(constraints, options, std::move(cert_generator), + if (!client->Init(constraints, options, config, std::move(cert_generator), prefer_constraint_apis, network_thread, worker_thread)) { delete client; return nullptr; @@ -191,29 +192,31 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, const std::string& id, const MediaConstraintsInterface* constraints, const PeerConnectionFactory::Options* options, + const PeerConnectionInterface::RTCConfiguration& config, rtc::Thread* network_thread, rtc::Thread* worker_thread) { std::unique_ptr cert_generator( rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeRTCCertificateGenerator() : nullptr); - return CreateClientWithDtlsIdentityStore( - id, constraints, options, std::move(cert_generator), true, - network_thread, worker_thread); + return CreateClientWithDtlsIdentityStore(id, constraints, options, config, + std::move(cert_generator), true, + network_thread, worker_thread); } static PeerConnectionTestClient* CreateClientPreferNoConstraints( const std::string& id, const PeerConnectionFactory::Options* options, + const PeerConnectionInterface::RTCConfiguration& config, rtc::Thread* network_thread, rtc::Thread* worker_thread) { std::unique_ptr cert_generator( rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeRTCCertificateGenerator() : nullptr); - return CreateClientWithDtlsIdentityStore( - id, nullptr, options, std::move(cert_generator), false, - network_thread, worker_thread); + return CreateClientWithDtlsIdentityStore(id, nullptr, options, config, + std::move(cert_generator), false, + network_thread, worker_thread); } ~PeerConnectionTestClient() { @@ -457,8 +460,10 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, data_observer_.reset(new MockDataChannelObserver(data_channel)); } - void CreateDataChannel() { - data_channel_ = pc()->CreateDataChannel(kDataChannelLabel, nullptr); + void CreateDataChannel() { CreateDataChannel(nullptr); } + + void CreateDataChannel(const webrtc::DataChannelInit* init) { + data_channel_ = pc()->CreateDataChannel(kDataChannelLabel, init); ASSERT_TRUE(data_channel_.get() != nullptr); data_observer_.reset(new MockDataChannelObserver(data_channel_)); } @@ -845,6 +850,7 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, bool Init( const MediaConstraintsInterface* constraints, const PeerConnectionFactory::Options* options, + const PeerConnectionInterface::RTCConfiguration& config, std::unique_ptr cert_generator, bool prefer_constraint_apis, rtc::Thread* network_thread, @@ -876,21 +882,18 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, if (options) { peer_connection_factory_->SetOptions(*options); } - peer_connection_ = CreatePeerConnection( - std::move(port_allocator), constraints, std::move(cert_generator)); + peer_connection_ = + CreatePeerConnection(std::move(port_allocator), constraints, config, + std::move(cert_generator)); + return peer_connection_.get() != nullptr; } rtc::scoped_refptr CreatePeerConnection( std::unique_ptr port_allocator, const MediaConstraintsInterface* constraints, + const PeerConnectionInterface::RTCConfiguration& config, std::unique_ptr cert_generator) { - // CreatePeerConnection with RTCConfiguration. - webrtc::PeerConnectionInterface::RTCConfiguration config; - webrtc::PeerConnectionInterface::IceServer ice_server; - ice_server.uri = "stun:stun.l.google.com:19302"; - config.servers.push_back(ice_server); - return peer_connection_factory_->CreatePeerConnection( config, constraints, std::move(port_allocator), std::move(cert_generator), this); @@ -1078,6 +1081,9 @@ class P2PTestConductor : public testing::Test { worker_thread_(rtc::Thread::Create()) { RTC_CHECK(network_thread_->Start()); RTC_CHECK(worker_thread_->Start()); + webrtc::PeerConnectionInterface::IceServer ice_server; + ice_server.uri = "stun:stun.l.google.com:19302"; + config_.servers.push_back(ice_server); } bool SessionActive() { @@ -1187,10 +1193,12 @@ class P2PTestConductor : public testing::Test { bool CreateTestClientsThatPreferNoConstraints() { initiating_client_.reset( PeerConnectionTestClient::CreateClientPreferNoConstraints( - "Caller: ", nullptr, network_thread_.get(), worker_thread_.get())); + "Caller: ", nullptr, config_, network_thread_.get(), + worker_thread_.get())); receiving_client_.reset( PeerConnectionTestClient::CreateClientPreferNoConstraints( - "Callee: ", nullptr, network_thread_.get(), worker_thread_.get())); + "Callee: ", nullptr, config_, network_thread_.get(), + worker_thread_.get())); if (!initiating_client_ || !receiving_client_) { return false; } @@ -1210,11 +1218,11 @@ class P2PTestConductor : public testing::Test { MediaConstraintsInterface* recv_constraints, PeerConnectionFactory::Options* recv_options) { initiating_client_.reset(PeerConnectionTestClient::CreateClient( - "Caller: ", init_constraints, init_options, network_thread_.get(), - worker_thread_.get())); + "Caller: ", init_constraints, init_options, config_, + network_thread_.get(), worker_thread_.get())); receiving_client_.reset(PeerConnectionTestClient::CreateClient( - "Callee: ", recv_constraints, recv_options, network_thread_.get(), - worker_thread_.get())); + "Callee: ", recv_constraints, recv_options, config_, + network_thread_.get(), worker_thread_.get())); if (!initiating_client_ || !receiving_client_) { return false; } @@ -1314,7 +1322,7 @@ class P2PTestConductor : public testing::Test { // Make sure the new client is using a different certificate. return PeerConnectionTestClient::CreateClientWithDtlsIdentityStore( - "New Peer: ", &setup_constraints, nullptr, + "New Peer: ", &setup_constraints, nullptr, config_, std::move(cert_generator), prefer_constraint_apis_, network_thread_.get(), worker_thread_.get()); } @@ -1354,6 +1362,9 @@ class P2PTestConductor : public testing::Test { receiving_client_.reset(client); return old; } + webrtc::PeerConnectionInterface::RTCConfiguration* config() { + return &config_; + } bool AllObserversReceived( const std::vector>& observers) { @@ -1399,6 +1410,7 @@ class P2PTestConductor : public testing::Test { std::unique_ptr initiating_client_; std::unique_ptr receiving_client_; bool prefer_constraint_apis_ = true; + webrtc::PeerConnectionInterface::RTCConfiguration config_; }; // Disable for TSan v2, see @@ -2116,6 +2128,77 @@ TEST_F(P2PTestConductor, EarlyWarmupTest) { kMaxWaitForFramesMs); } +#ifdef HAVE_QUIC +// This test sets up a call between two parties using QUIC instead of DTLS for +// audio and video, and a QUIC data channel. +TEST_F(P2PTestConductor, LocalP2PTestQuicDataChannel) { + config()->enable_quic = true; + ASSERT_TRUE(CreateTestClients()); + webrtc::DataChannelInit init; + init.ordered = false; + init.reliable = true; + init.id = 1; + initializing_client()->CreateDataChannel(&init); + receiving_client()->CreateDataChannel(&init); + LocalP2PTest(); + ASSERT_NE(nullptr, initializing_client()->data_channel()); + ASSERT_NE(nullptr, receiving_client()->data_channel()); + EXPECT_TRUE_WAIT(initializing_client()->data_observer()->IsOpen(), + kMaxWaitMs); + EXPECT_TRUE_WAIT(receiving_client()->data_observer()->IsOpen(), kMaxWaitMs); + + std::string data = "hello world"; + + initializing_client()->data_channel()->Send(DataBuffer(data)); + EXPECT_EQ_WAIT(data, receiving_client()->data_observer()->last_message(), + kMaxWaitMs); + + receiving_client()->data_channel()->Send(DataBuffer(data)); + EXPECT_EQ_WAIT(data, initializing_client()->data_observer()->last_message(), + kMaxWaitMs); +} + +// Tests that negotiation of QUIC data channels is completed without error. +TEST_F(P2PTestConductor, NegotiateQuicDataChannel) { + config()->enable_quic = true; + FakeConstraints constraints; + constraints.SetMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, true); + ASSERT_TRUE(CreateTestClients(&constraints, &constraints)); + webrtc::DataChannelInit init; + init.ordered = false; + init.reliable = true; + init.id = 1; + initializing_client()->CreateDataChannel(&init); + initializing_client()->Negotiate(false, false); +} + +// This test sets up a JSEP call using QUIC. The callee only receives video. +TEST_F(P2PTestConductor, LocalP2PTestVideoOnlyWithQuic) { + config()->enable_quic = true; + ASSERT_TRUE(CreateTestClients()); + receiving_client()->SetReceiveAudioVideo(false, true); + LocalP2PTest(); +} + +// This test sets up a JSEP call using QUIC. The callee only receives audio. +TEST_F(P2PTestConductor, LocalP2PTestAudioOnlyWithQuic) { + config()->enable_quic = true; + ASSERT_TRUE(CreateTestClients()); + receiving_client()->SetReceiveAudioVideo(true, false); + LocalP2PTest(); +} + +// This test sets up a JSEP call using QUIC. The callee rejects both audio and +// video. +TEST_F(P2PTestConductor, LocalP2PTestNoVideoAudioWithQuic) { + config()->enable_quic = true; + ASSERT_TRUE(CreateTestClients()); + receiving_client()->SetReceiveAudioVideo(false, false); + LocalP2PTest(); +} + +#endif // HAVE_QUIC + TEST_F(P2PTestConductor, ForwardVideoOnlyStream) { ASSERT_TRUE(CreateTestClients()); // One-way stream diff --git a/webrtc/api/peerconnectionendtoend_unittest.cc b/webrtc/api/peerconnectionendtoend_unittest.cc index e01daa9439..2298cf482c 100644 --- a/webrtc/api/peerconnectionendtoend_unittest.cc +++ b/webrtc/api/peerconnectionendtoend_unittest.cc @@ -56,6 +56,10 @@ class PeerConnectionEndToEndTest "caller", &network_thread_, &worker_thread_); callee_ = new rtc::RefCountedObject( "callee", &network_thread_, &worker_thread_); + webrtc::PeerConnectionInterface::IceServer ice_server; + ice_server.uri = "stun:stun.l.google.com:19302"; + config_.servers.push_back(ice_server); + #ifdef WEBRTC_ANDROID webrtc::InitializeAndroidObjects(); #endif @@ -66,8 +70,8 @@ class PeerConnectionEndToEndTest } void CreatePcs(const MediaConstraintsInterface* pc_constraints) { - EXPECT_TRUE(caller_->CreatePc(pc_constraints)); - EXPECT_TRUE(callee_->CreatePc(pc_constraints)); + EXPECT_TRUE(caller_->CreatePc(pc_constraints, config_)); + EXPECT_TRUE(callee_->CreatePc(pc_constraints, config_)); PeerConnectionTestWrapper::Connect(caller_.get(), callee_.get()); caller_->SignalOnDataChannel.connect( @@ -162,6 +166,7 @@ class PeerConnectionEndToEndTest rtc::scoped_refptr callee_; DataChannelList caller_signaled_data_channels_; DataChannelList callee_signaled_data_channels_; + webrtc::PeerConnectionInterface::RTCConfiguration config_; }; // Disabled for TSan v2, see @@ -313,6 +318,82 @@ TEST_F(PeerConnectionEndToEndTest, EXPECT_EQ(1U, dc_2_observer->received_message_count()); } +#ifdef HAVE_QUIC +// Test that QUIC data channels can be used and that messages go to the correct +// remote data channel when both peers want to use QUIC. It is assumed that the +// application has externally negotiated the data channel parameters. +TEST_F(PeerConnectionEndToEndTest, MessageTransferBetweenQuicDataChannels) { + config_.enable_quic = true; + CreatePcs(); + + webrtc::DataChannelInit init_1; + init_1.id = 0; + init_1.ordered = false; + init_1.reliable = true; + + webrtc::DataChannelInit init_2; + init_2.id = 1; + init_2.ordered = false; + init_2.reliable = true; + + rtc::scoped_refptr caller_dc_1( + caller_->CreateDataChannel("data", init_1)); + ASSERT_NE(nullptr, caller_dc_1); + rtc::scoped_refptr caller_dc_2( + caller_->CreateDataChannel("data", init_2)); + ASSERT_NE(nullptr, caller_dc_2); + rtc::scoped_refptr callee_dc_1( + callee_->CreateDataChannel("data", init_1)); + ASSERT_NE(nullptr, callee_dc_1); + rtc::scoped_refptr callee_dc_2( + callee_->CreateDataChannel("data", init_2)); + ASSERT_NE(nullptr, callee_dc_2); + + Negotiate(); + WaitForConnection(); + EXPECT_TRUE_WAIT(caller_dc_1->state() == webrtc::DataChannelInterface::kOpen, + kMaxWait); + EXPECT_TRUE_WAIT(callee_dc_1->state() == webrtc::DataChannelInterface::kOpen, + kMaxWait); + EXPECT_TRUE_WAIT(caller_dc_2->state() == webrtc::DataChannelInterface::kOpen, + kMaxWait); + EXPECT_TRUE_WAIT(callee_dc_2->state() == webrtc::DataChannelInterface::kOpen, + kMaxWait); + + std::unique_ptr dc_1_observer( + new webrtc::MockDataChannelObserver(callee_dc_1.get())); + + std::unique_ptr dc_2_observer( + new webrtc::MockDataChannelObserver(callee_dc_2.get())); + + const std::string message_1 = "hello 1"; + const std::string message_2 = "hello 2"; + + // Send data from caller to callee. + caller_dc_1->Send(webrtc::DataBuffer(message_1)); + EXPECT_EQ_WAIT(message_1, dc_1_observer->last_message(), kMaxWait); + + caller_dc_2->Send(webrtc::DataBuffer(message_2)); + EXPECT_EQ_WAIT(message_2, dc_2_observer->last_message(), kMaxWait); + + EXPECT_EQ(1U, dc_1_observer->received_message_count()); + EXPECT_EQ(1U, dc_2_observer->received_message_count()); + + // Send data from callee to caller. + dc_1_observer.reset(new webrtc::MockDataChannelObserver(caller_dc_1.get())); + dc_2_observer.reset(new webrtc::MockDataChannelObserver(caller_dc_2.get())); + + callee_dc_1->Send(webrtc::DataBuffer(message_1)); + EXPECT_EQ_WAIT(message_1, dc_1_observer->last_message(), kMaxWait); + + callee_dc_2->Send(webrtc::DataBuffer(message_2)); + EXPECT_EQ_WAIT(message_2, dc_2_observer->last_message(), kMaxWait); + + EXPECT_EQ(1U, dc_1_observer->received_message_count()); + EXPECT_EQ(1U, dc_2_observer->received_message_count()); +} +#endif // HAVE_QUIC + // Verifies that a DataChannel added from an OPEN message functions after // a channel has been previously closed (webrtc issue 3778). // This previously failed because the new channel re-uses the ID of the closed diff --git a/webrtc/api/peerconnectioninterface.h b/webrtc/api/peerconnectioninterface.h index e0eb1a46d4..fdf9cef51e 100644 --- a/webrtc/api/peerconnectioninterface.h +++ b/webrtc/api/peerconnectioninterface.h @@ -296,6 +296,7 @@ class PeerConnectionInterface : public rtc::RefCountInterface { // default applies. bool disable_ipv6 = false; bool enable_rtp_data_channel = false; + bool enable_quic = false; rtc::Optional screencast_min_bitrate; rtc::Optional combined_audio_video_bwe; rtc::Optional enable_dtls_srtp; diff --git a/webrtc/api/peerconnectioninterface_unittest.cc b/webrtc/api/peerconnectioninterface_unittest.cc index 419f69c563..0b24fcb7cf 100644 --- a/webrtc/api/peerconnectioninterface_unittest.cc +++ b/webrtc/api/peerconnectioninterface_unittest.cc @@ -242,7 +242,6 @@ static const char kSdpStringMs1Video1[] = using ::testing::Exactly; using cricket::StreamParams; -using rtc::scoped_refptr; using webrtc::AudioSourceInterface; using webrtc::AudioTrack; using webrtc::AudioTrackInterface; @@ -535,18 +534,18 @@ class MockPeerConnectionObserver : public PeerConnectionObserver { return ""; } - scoped_refptr pc_; + rtc::scoped_refptr pc_; PeerConnectionInterface::SignalingState state_; std::unique_ptr last_candidate_; - scoped_refptr last_datachannel_; + rtc::scoped_refptr last_datachannel_; rtc::scoped_refptr remote_streams_; bool renegotiation_needed_ = false; bool ice_complete_ = false; bool callback_triggered = false; private: - scoped_refptr last_added_stream_; - scoped_refptr last_removed_stream_; + rtc::scoped_refptr last_added_stream_; + rtc::scoped_refptr last_removed_stream_; }; } // namespace @@ -664,7 +663,7 @@ class PeerConnectionInterfaceTest : public testing::Test { server.uri = uri; config.servers.push_back(server); - scoped_refptr pc; + rtc::scoped_refptr pc; pc = pc_factory_->CreatePeerConnection(config, nullptr, nullptr, nullptr, &observer_); EXPECT_EQ(nullptr, pc); @@ -700,11 +699,11 @@ class PeerConnectionInterfaceTest : public testing::Test { void AddVideoStream(const std::string& label) { // Create a local stream. - scoped_refptr stream( + rtc::scoped_refptr stream( pc_factory_->CreateLocalMediaStream(label)); - scoped_refptr video_source( + rtc::scoped_refptr video_source( pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer(), NULL)); - scoped_refptr video_track( + rtc::scoped_refptr video_track( pc_factory_->CreateVideoTrack(label + "v0", video_source)); stream->AddTrack(video_track.get()); EXPECT_TRUE(pc_->AddStream(stream)); @@ -714,9 +713,9 @@ class PeerConnectionInterfaceTest : public testing::Test { void AddVoiceStream(const std::string& label) { // Create a local stream. - scoped_refptr stream( + rtc::scoped_refptr stream( pc_factory_->CreateLocalMediaStream(label)); - scoped_refptr audio_track( + rtc::scoped_refptr audio_track( pc_factory_->CreateAudioTrack(label + "a0", NULL)); stream->AddTrack(audio_track.get()); EXPECT_TRUE(pc_->AddStream(stream)); @@ -728,13 +727,13 @@ class PeerConnectionInterfaceTest : public testing::Test { const std::string& audio_track_label, const std::string& video_track_label) { // Create a local stream. - scoped_refptr stream( + rtc::scoped_refptr stream( pc_factory_->CreateLocalMediaStream(stream_label)); - scoped_refptr audio_track( + rtc::scoped_refptr audio_track( pc_factory_->CreateAudioTrack( audio_track_label, static_cast(NULL))); stream->AddTrack(audio_track.get()); - scoped_refptr video_track( + rtc::scoped_refptr video_track( pc_factory_->CreateVideoTrack( video_track_label, pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer()))); @@ -1042,9 +1041,9 @@ class PeerConnectionInterfaceTest : public testing::Test { } cricket::FakePortAllocator* port_allocator_ = nullptr; - scoped_refptr pc_factory_; - scoped_refptr pc_factory_for_test_; - scoped_refptr pc_; + rtc::scoped_refptr pc_factory_; + rtc::scoped_refptr pc_factory_for_test_; + rtc::scoped_refptr pc_; MockPeerConnectionObserver observer_; rtc::scoped_refptr reference_collection_; }; @@ -1052,7 +1051,7 @@ class PeerConnectionInterfaceTest : public testing::Test { // Test that no callbacks on the PeerConnectionObserver are called after the // PeerConnection is closed. TEST_F(PeerConnectionInterfaceTest, CloseAndTestCallbackFunctions) { - scoped_refptr pc( + rtc::scoped_refptr pc( pc_factory_for_test_->CreatePeerConnection( PeerConnectionInterface::RTCConfiguration(), nullptr, nullptr, nullptr, &observer_)); @@ -1170,11 +1169,11 @@ TEST_F(PeerConnectionInterfaceTest, AddStreams) { ASSERT_EQ(2u, pc_->local_streams()->count()); // Test we can add multiple local streams to one peerconnection. - scoped_refptr stream( + rtc::scoped_refptr stream( pc_factory_->CreateLocalMediaStream(kStreamLabel3)); - scoped_refptr audio_track( - pc_factory_->CreateAudioTrack( - kStreamLabel3, static_cast(NULL))); + rtc::scoped_refptr audio_track( + pc_factory_->CreateAudioTrack(kStreamLabel3, + static_cast(NULL))); stream->AddTrack(audio_track.get()); EXPECT_TRUE(pc_->AddStream(stream)); EXPECT_EQ(3u, pc_->local_streams()->count()); @@ -1252,15 +1251,16 @@ TEST_F(PeerConnectionInterfaceTest, RemoveStream) { TEST_F(PeerConnectionInterfaceTest, AddTrackRemoveTrack) { CreatePeerConnection(); // Create a dummy stream, so tracks share a stream label. - scoped_refptr stream( + rtc::scoped_refptr stream( pc_factory_->CreateLocalMediaStream(kStreamLabel1)); std::vector stream_list; stream_list.push_back(stream.get()); - scoped_refptr audio_track( + rtc::scoped_refptr audio_track( pc_factory_->CreateAudioTrack("audio_track", nullptr)); - scoped_refptr video_track(pc_factory_->CreateVideoTrack( - "video_track", - pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer()))); + rtc::scoped_refptr video_track( + pc_factory_->CreateVideoTrack( + "video_track", + pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer()))); auto audio_sender = pc_->AddTrack(audio_track, stream_list); auto video_sender = pc_->AddTrack(video_track, stream_list); EXPECT_EQ(1UL, audio_sender->stream_ids().size()); @@ -1326,11 +1326,12 @@ TEST_F(PeerConnectionInterfaceTest, AddTrackRemoveTrack) { TEST_F(PeerConnectionInterfaceTest, AddTrackWithoutStream) { CreatePeerConnection(); // Create a dummy stream, so tracks share a stream label. - scoped_refptr audio_track( + rtc::scoped_refptr audio_track( pc_factory_->CreateAudioTrack("audio_track", nullptr)); - scoped_refptr video_track(pc_factory_->CreateVideoTrack( - "video_track", - pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer()))); + rtc::scoped_refptr video_track( + pc_factory_->CreateVideoTrack( + "video_track", + pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer()))); auto audio_sender = pc_->AddTrack(audio_track, std::vector()); auto video_sender = @@ -1489,9 +1490,10 @@ TEST_F(PeerConnectionInterfaceTest, AddTrackAfterAddStream) { MediaStreamInterface* stream = pc_->local_streams()->at(0); // Add video track to the audio-only stream. - scoped_refptr video_track(pc_factory_->CreateVideoTrack( - "video_label", - pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer()))); + rtc::scoped_refptr video_track( + pc_factory_->CreateVideoTrack( + "video_label", + pc_factory_->CreateVideoSource(new cricket::FakeVideoCapturer()))); stream->AddTrack(video_track.get()); std::unique_ptr offer; @@ -1543,7 +1545,7 @@ TEST_F(PeerConnectionInterfaceTest, GetStatsForSpecificTrack) { InitiateCall(); ASSERT_LT(0u, pc_->remote_streams()->count()); ASSERT_LT(0u, pc_->remote_streams()->at(0)->GetAudioTracks().size()); - scoped_refptr remote_audio = + rtc::scoped_refptr remote_audio = pc_->remote_streams()->at(0)->GetAudioTracks()[0]; EXPECT_TRUE(DoGetStats(remote_audio)); @@ -1565,7 +1567,7 @@ TEST_F(PeerConnectionInterfaceTest, GetStatsForVideoTrack) { InitiateCall(); ASSERT_LT(0u, pc_->remote_streams()->count()); ASSERT_LT(0u, pc_->remote_streams()->at(0)->GetVideoTracks().size()); - scoped_refptr remote_video = + rtc::scoped_refptr remote_video = pc_->remote_streams()->at(0)->GetVideoTracks()[0]; EXPECT_TRUE(DoGetStats(remote_video)); } @@ -1576,7 +1578,7 @@ TEST_F(PeerConnectionInterfaceTest, GetStatsForVideoTrack) { // data is returned for the track. TEST_F(PeerConnectionInterfaceTest, DISABLED_GetStatsForInvalidTrack) { InitiateCall(); - scoped_refptr unknown_audio_track( + rtc::scoped_refptr unknown_audio_track( pc_factory_->CreateAudioTrack("unknown track", NULL)); EXPECT_FALSE(DoGetStats(unknown_audio_track)); } @@ -1586,9 +1588,9 @@ TEST_F(PeerConnectionInterfaceTest, TestDataChannel) { FakeConstraints constraints; constraints.SetAllowRtpDataChannels(); CreatePeerConnection(&constraints); - scoped_refptr data1 = + rtc::scoped_refptr data1 = pc_->CreateDataChannel("test1", NULL); - scoped_refptr data2 = + rtc::scoped_refptr data2 = pc_->CreateDataChannel("test2", NULL); ASSERT_TRUE(data1 != NULL); std::unique_ptr observer1( @@ -1633,9 +1635,9 @@ TEST_F(PeerConnectionInterfaceTest, TestSendBinaryOnRtpDataChannel) { FakeConstraints constraints; constraints.SetAllowRtpDataChannels(); CreatePeerConnection(&constraints); - scoped_refptr data1 = + rtc::scoped_refptr data1 = pc_->CreateDataChannel("test1", NULL); - scoped_refptr data2 = + rtc::scoped_refptr data2 = pc_->CreateDataChannel("test2", NULL); ASSERT_TRUE(data1 != NULL); std::unique_ptr observer1( @@ -1663,7 +1665,7 @@ TEST_F(PeerConnectionInterfaceTest, TestSendOnlyDataChannel) { FakeConstraints constraints; constraints.SetAllowRtpDataChannels(); CreatePeerConnection(&constraints); - scoped_refptr data1 = + rtc::scoped_refptr data1 = pc_->CreateDataChannel("test1", NULL); std::unique_ptr observer1( new MockDataChannelObserver(data1)); @@ -1687,7 +1689,7 @@ TEST_F(PeerConnectionInterfaceTest, TestReceiveOnlyDataChannel) { CreatePeerConnection(&constraints); std::string offer_label = "offer_channel"; - scoped_refptr offer_channel = + rtc::scoped_refptr offer_channel = pc_->CreateDataChannel(offer_label, NULL); CreateOfferAsLocalDescription(); @@ -1730,7 +1732,7 @@ TEST_F(PeerConnectionInterfaceTest, CreateReliableRtpDataChannelShouldFail) { std::string label = "test"; webrtc::DataChannelInit config; config.reliable = true; - scoped_refptr channel = + rtc::scoped_refptr channel = pc_->CreateDataChannel(label, &config); EXPECT_TRUE(channel == NULL); } @@ -1742,11 +1744,11 @@ TEST_F(PeerConnectionInterfaceTest, RtpDuplicatedLabelNotAllowed) { CreatePeerConnection(&constraints); std::string label = "test"; - scoped_refptr channel = + rtc::scoped_refptr channel = pc_->CreateDataChannel(label, nullptr); EXPECT_NE(channel, nullptr); - scoped_refptr dup_channel = + rtc::scoped_refptr dup_channel = pc_->CreateDataChannel(label, nullptr); EXPECT_EQ(dup_channel, nullptr); } @@ -1760,7 +1762,7 @@ TEST_F(PeerConnectionInterfaceTest, CreateSctpDataChannel) { webrtc::DataChannelInit config; - scoped_refptr channel = + rtc::scoped_refptr channel = pc_->CreateDataChannel("1", &config); EXPECT_TRUE(channel != NULL); EXPECT_TRUE(channel->reliable()); @@ -1801,7 +1803,7 @@ TEST_F(PeerConnectionInterfaceTest, config.maxRetransmits = 0; config.maxRetransmitTime = 0; - scoped_refptr channel = + rtc::scoped_refptr channel = pc_->CreateDataChannel(label, &config); EXPECT_TRUE(channel == NULL); } @@ -1815,7 +1817,7 @@ TEST_F(PeerConnectionInterfaceTest, CreatePeerConnection(&constraints); webrtc::DataChannelInit config; - scoped_refptr channel; + rtc::scoped_refptr channel; config.id = 1; channel = pc_->CreateDataChannel("1", &config); @@ -1843,11 +1845,11 @@ TEST_F(PeerConnectionInterfaceTest, SctpDuplicatedLabelAllowed) { CreatePeerConnection(&constraints); std::string label = "test"; - scoped_refptr channel = + rtc::scoped_refptr channel = pc_->CreateDataChannel(label, nullptr); EXPECT_NE(channel, nullptr); - scoped_refptr dup_channel = + rtc::scoped_refptr dup_channel = pc_->CreateDataChannel(label, nullptr); EXPECT_NE(dup_channel, nullptr); } @@ -1859,12 +1861,12 @@ TEST_F(PeerConnectionInterfaceTest, RenegotiationNeededForNewRtpDataChannel) { constraints.SetAllowRtpDataChannels(); CreatePeerConnection(&constraints); - scoped_refptr dc1 = + rtc::scoped_refptr dc1 = pc_->CreateDataChannel("test1", NULL); EXPECT_TRUE(observer_.renegotiation_needed_); observer_.renegotiation_needed_ = false; - scoped_refptr dc2 = + rtc::scoped_refptr dc2 = pc_->CreateDataChannel("test2", NULL); EXPECT_TRUE(observer_.renegotiation_needed_); } @@ -1875,9 +1877,9 @@ TEST_F(PeerConnectionInterfaceTest, DataChannelCloseWhenPeerConnectionClose) { constraints.SetAllowRtpDataChannels(); CreatePeerConnection(&constraints); - scoped_refptr data1 = + rtc::scoped_refptr data1 = pc_->CreateDataChannel("test1", NULL); - scoped_refptr data2 = + rtc::scoped_refptr data2 = pc_->CreateDataChannel("test2", NULL); ASSERT_TRUE(data1 != NULL); std::unique_ptr observer1( @@ -1900,7 +1902,7 @@ TEST_F(PeerConnectionInterfaceTest, TestRejectDataChannelInAnswer) { constraints.SetAllowRtpDataChannels(); CreatePeerConnection(&constraints); - scoped_refptr offer_channel( + rtc::scoped_refptr offer_channel( pc_->CreateDataChannel("offer_channel", NULL)); CreateOfferAsLocalDescription(); @@ -2106,8 +2108,8 @@ TEST_F(PeerConnectionInterfaceTest, CloseAndTestStreamsAndStates) { EXPECT_EQ(1u, pc_->local_streams()->count()); EXPECT_EQ(1u, pc_->remote_streams()->count()); - scoped_refptr remote_stream = - pc_->remote_streams()->at(0); + rtc::scoped_refptr remote_stream = + pc_->remote_streams()->at(0); // Track state may be updated asynchronously. EXPECT_EQ_WAIT(MediaStreamTrackInterface::kEnded, remote_stream->GetAudioTracks()[0]->state(), kTimeout); @@ -2124,7 +2126,7 @@ TEST_F(PeerConnectionInterfaceTest, CloseAndTestMethods) { CreateAnswerAsLocalDescription(); ASSERT_EQ(1u, pc_->local_streams()->count()); - scoped_refptr local_stream = + rtc::scoped_refptr local_stream = pc_->local_streams()->at(0); pc_->Close(); @@ -2217,10 +2219,10 @@ TEST_F(PeerConnectionInterfaceTest, EXPECT_TRUE(DoSetRemoteDescription(desc_ms1_two_tracks.release())); EXPECT_TRUE(CompareStreamCollections(observer_.remote_streams(), reference_collection_)); - scoped_refptr audio_track2 = + rtc::scoped_refptr audio_track2 = observer_.remote_streams()->at(0)->GetAudioTracks()[1]; EXPECT_EQ(webrtc::MediaStreamTrackInterface::kLive, audio_track2->state()); - scoped_refptr video_track2 = + rtc::scoped_refptr video_track2 = observer_.remote_streams()->at(0)->GetVideoTracks()[1]; EXPECT_EQ(webrtc::MediaStreamTrackInterface::kLive, video_track2->state()); @@ -2641,15 +2643,14 @@ class PeerConnectionMediaConfigTest : public testing::Test { const MediaConstraintsInterface *constraints) { pcf_->create_media_controller_called_ = false; - scoped_refptr pc( - pcf_->CreatePeerConnection(config, constraints, nullptr, nullptr, - &observer_)); + rtc::scoped_refptr pc(pcf_->CreatePeerConnection( + config, constraints, nullptr, nullptr, &observer_)); EXPECT_TRUE(pc.get()); EXPECT_TRUE(pcf_->create_media_controller_called_); return pcf_->create_media_controller_config_; } - scoped_refptr pcf_; + rtc::scoped_refptr pcf_; MockPeerConnectionObserver observer_; }; diff --git a/webrtc/api/quicdatatransport.cc b/webrtc/api/quicdatatransport.cc index c1caf54067..ff3ac09335 100644 --- a/webrtc/api/quicdatatransport.cc +++ b/webrtc/api/quicdatatransport.cc @@ -10,24 +10,48 @@ #include "webrtc/api/quicdatatransport.h" +#include "webrtc/base/bind.h" #include "webrtc/base/logging.h" #include "webrtc/p2p/quic/quictransportchannel.h" #include "webrtc/p2p/quic/reliablequicstream.h" namespace webrtc { -QuicDataTransport::QuicDataTransport(rtc::Thread* signaling_thread, - rtc::Thread* worker_thread, - rtc::Thread* network_thread) +QuicDataTransport::QuicDataTransport( + rtc::Thread* signaling_thread, + rtc::Thread* worker_thread, + rtc::Thread* network_thread, + cricket::TransportController* transport_controller) : signaling_thread_(signaling_thread), worker_thread_(worker_thread), - network_thread_(network_thread) { + network_thread_(network_thread), + transport_controller_(transport_controller) { RTC_DCHECK(signaling_thread_); RTC_DCHECK(worker_thread_); RTC_DCHECK(network_thread_); } -QuicDataTransport::~QuicDataTransport() {} +QuicDataTransport::~QuicDataTransport() { + DestroyTransportChannel(quic_transport_channel_); + LOG(LS_INFO) << "Destroyed the QUIC data transport."; +} + +bool QuicDataTransport::SetTransport(const std::string& transport_name) { + if (transport_name_ == transport_name) { + // Nothing to do if transport name isn't changing + return true; + } + + cricket::QuicTransportChannel* transport_channel = + CreateTransportChannel(transport_name); + if (!SetTransportChannel(transport_channel)) { + DestroyTransportChannel(transport_channel); + return false; + } + + transport_name_ = transport_name; + return true; +} bool QuicDataTransport::SetTransportChannel( cricket::QuicTransportChannel* channel) { @@ -48,7 +72,6 @@ bool QuicDataTransport::SetTransportChannel( quic_transport_channel_ = channel; quic_transport_channel_->SignalIncomingStream.connect( this, &QuicDataTransport::OnIncomingStream); - bool success = true; for (const auto& kv : data_channel_by_id_) { rtc::scoped_refptr data_channel = kv.second; @@ -147,4 +170,28 @@ void QuicDataTransport::OnDataReceived(net::QuicStreamId id, data_channel->OnIncomingMessage(std::move(message)); } +cricket::QuicTransportChannel* QuicDataTransport::CreateTransportChannel( + const std::string& transport_name) { + DCHECK(transport_controller_->quic()); + + cricket::TransportChannel* transport_channel = + network_thread_->Invoke( + RTC_FROM_HERE, + rtc::Bind(&cricket::TransportController::CreateTransportChannel_n, + transport_controller_, transport_name, + cricket::ICE_CANDIDATE_COMPONENT_DEFAULT)); + return static_cast(transport_channel); +} + +void QuicDataTransport::DestroyTransportChannel( + cricket::TransportChannel* transport_channel) { + if (transport_channel) { + network_thread_->Invoke( + RTC_FROM_HERE, + rtc::Bind(&cricket::TransportController::DestroyTransportChannel_n, + transport_controller_, transport_channel->transport_name(), + cricket::ICE_CANDIDATE_COMPONENT_DEFAULT)); + } +} + } // namespace webrtc diff --git a/webrtc/api/quicdatatransport.h b/webrtc/api/quicdatatransport.h index 96fe2a0ad7..b8d3f84bfb 100644 --- a/webrtc/api/quicdatatransport.h +++ b/webrtc/api/quicdatatransport.h @@ -19,6 +19,7 @@ #include "webrtc/base/scoped_ref_ptr.h" #include "webrtc/base/sigslot.h" #include "webrtc/base/thread.h" +#include "webrtc/p2p/base/transportcontroller.h" namespace cricket { class QuicTransportChannel; @@ -38,14 +39,17 @@ class QuicDataTransport : public sigslot::has_slots<> { public: QuicDataTransport(rtc::Thread* signaling_thread, rtc::Thread* worker_thread, - rtc::Thread* network_thread); + rtc::Thread* network_thread, + cricket::TransportController* transport_controller); ~QuicDataTransport() override; - // Sets the QUIC transport channel for the QuicDataChannels and the - // QuicDataTransport. Returns false if a different QUIC transport channel is - // already set, the QUIC transport channel cannot be set for any of the - // QuicDataChannels, or |channel| is NULL. - bool SetTransportChannel(cricket::QuicTransportChannel* channel); + // The QuicDataTransport acts like a BaseChannel with these functions. + bool SetTransport(const std::string& transport_name); + const std::string& transport_name() const { return transport_name_; } + const std::string& content_name() const { return content_name_; } + void set_content_name(const std::string& content_name) { + content_name_ = content_name; + } // Creates a QuicDataChannel that uses this QuicDataTransport. rtc::scoped_refptr CreateDataChannel( @@ -62,7 +66,17 @@ class QuicDataTransport : public sigslot::has_slots<> { // True if the QuicDataTransport has data channels. bool HasDataChannels() const; + cricket::QuicTransportChannel* quic_transport_channel() { + return quic_transport_channel_; + } + private: + // Sets the QUIC transport channel for the QuicDataChannels and the + // QuicDataTransport. Returns false if a different QUIC transport channel is + // already set, the QUIC transport channel cannot be set for any of the + // QuicDataChannels, or |channel| is NULL. + bool SetTransportChannel(cricket::QuicTransportChannel* channel); + // Called from the QuicTransportChannel when a ReliableQuicStream is created // to receive incoming data. void OnIncomingStream(cricket::ReliableQuicStream* stream); @@ -74,6 +88,10 @@ class QuicDataTransport : public sigslot::has_slots<> { const char* data, size_t len); + cricket::QuicTransportChannel* CreateTransportChannel( + const std::string& transport_name); + void DestroyTransportChannel(cricket::TransportChannel* transport_channel); + // Map of data channel ID => QUIC data channel values. std::unordered_map> data_channel_by_id_; @@ -86,6 +104,10 @@ class QuicDataTransport : public sigslot::has_slots<> { rtc::Thread* const signaling_thread_; rtc::Thread* const worker_thread_; rtc::Thread* const network_thread_; + + cricket::TransportController* transport_controller_; + std::string content_name_; + std::string transport_name_; }; } // namespace webrtc diff --git a/webrtc/api/quicdatatransport_unittest.cc b/webrtc/api/quicdatatransport_unittest.cc index 975898ef1f..a9c605ff2a 100644 --- a/webrtc/api/quicdatatransport_unittest.cc +++ b/webrtc/api/quicdatatransport_unittest.cc @@ -30,6 +30,7 @@ using webrtc::DataChannelObserver; using webrtc::QuicDataChannel; using webrtc::QuicDataTransport; using cricket::FakeTransportChannel; +using cricket::FakeTransportController; using cricket::QuicTransportChannel; using cricket::ReliableQuicStream; @@ -37,6 +38,7 @@ namespace { // Timeout for asynchronous operations. static const int kTimeoutMs = 1000; // milliseconds +static const char kTransportName[] = "data"; // FakeObserver receives messages from the data channel. class FakeObserver : public DataChannelObserver { @@ -64,11 +66,16 @@ class FakeObserver : public DataChannelObserver { class QuicDataTransportPeer { public: QuicDataTransportPeer() - : quic_data_transport_(rtc::Thread::Current(), + : fake_transport_controller_(new FakeTransportController()), + quic_data_transport_(rtc::Thread::Current(), rtc::Thread::Current(), - rtc::Thread::Current()), - ice_transport_channel_(new FakeTransportChannel("data", 0)), - quic_transport_channel_(ice_transport_channel_) { + rtc::Thread::Current(), + fake_transport_controller_.get()) { + fake_transport_controller_->use_quic(); + quic_data_transport_.set_content_name("data"); + quic_data_transport_.SetTransport(kTransportName); + ice_transport_channel_ = static_cast( + quic_data_transport_.quic_transport_channel()->ice_transport_channel()); ice_transport_channel_->SetAsync(true); } @@ -76,7 +83,8 @@ class QuicDataTransportPeer { rtc::scoped_refptr local_cert = rtc::RTCCertificate::Create(std::unique_ptr( rtc::SSLIdentity::Generate("cert_name", rtc::KT_DEFAULT))); - quic_transport_channel_.SetLocalCertificate(local_cert); + quic_data_transport_.quic_transport_channel()->SetLocalCertificate( + local_cert); local_fingerprint_.reset(CreateFingerprint(local_cert.get())); } @@ -90,14 +98,15 @@ class QuicDataTransportPeer { } QuicTransportChannel* quic_transport_channel() { - return &quic_transport_channel_; + return quic_data_transport_.quic_transport_channel(); } // Write a messge directly to the ReliableQuicStream. void WriteMessage(int data_channel_id, uint64_t message_id, const std::string& message) { - ReliableQuicStream* stream = quic_transport_channel_.CreateQuicStream(); + ReliableQuicStream* stream = + quic_data_transport_.quic_transport_channel()->CreateQuicStream(); rtc::CopyOnWriteBuffer payload; webrtc::WriteQuicDataChannelMessageHeader(data_channel_id, message_id, &payload); @@ -122,9 +131,9 @@ class QuicDataTransportPeer { return fingerprint.release(); } + std::unique_ptr fake_transport_controller_; QuicDataTransport quic_data_transport_; FakeTransportChannel* ice_transport_channel_; - QuicTransportChannel quic_transport_channel_; std::unique_ptr local_fingerprint_; }; @@ -140,13 +149,6 @@ class QuicDataTransportTest : public testing::Test { kTimeoutMs); } - void SetTransportChannels() { - ASSERT_TRUE(peer1_.quic_data_transport()->SetTransportChannel( - peer1_.quic_transport_channel())); - ASSERT_TRUE(peer2_.quic_data_transport()->SetTransportChannel( - peer2_.quic_transport_channel())); - } - // Sets crypto parameters required for the QUIC handshake. void SetCryptoParameters() { peer1_.GenerateCertificateAndFingerprint(); @@ -207,7 +209,7 @@ TEST_F(QuicDataTransportTest, CannotCreateDataChannelsWithSameId) { } // Tests that any data channels created by the QuicDataTransport are in state -// kConnecting before the QuicTransportChannel is set, then transiton to state +// kConnecting before the QuicTransportChannel is set, then transition to state // kOpen when the transport channel becomes writable. TEST_F(QuicDataTransportTest, DataChannelsOpenWhenTransportChannelWritable) { webrtc::DataChannelInit config1; @@ -215,7 +217,6 @@ TEST_F(QuicDataTransportTest, DataChannelsOpenWhenTransportChannelWritable) { rtc::scoped_refptr data_channel1 = peer2_.CreateDataChannel(&config1); EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel1->state()); - SetTransportChannels(); EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel1->state()); webrtc::DataChannelInit config2; config2.id = 14; @@ -239,7 +240,6 @@ TEST_F(QuicDataTransportTest, DataChannelsOpenWhenTransportChannelWritable) { // Tests that the QuicTransport dispatches messages for one QuicDataChannel. TEST_F(QuicDataTransportTest, ReceiveMessagesForSingleDataChannel) { ConnectTransportChannels(); - SetTransportChannels(); int data_channel_id = 1337; webrtc::DataChannelInit config; @@ -269,7 +269,6 @@ TEST_F(QuicDataTransportTest, ReceiveMessagesForSingleDataChannel) { // when multiple are in use. TEST_F(QuicDataTransportTest, ReceiveMessagesForMultipleDataChannels) { ConnectTransportChannels(); - SetTransportChannels(); std::vector> data_channels; for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) { @@ -299,7 +298,6 @@ TEST_F(QuicDataTransportTest, ReceiveMessagesForMultipleDataChannels) { // send/receive messages using a QuicDataTransport. TEST_F(QuicDataTransportTest, EndToEndSendReceiveMessages) { ConnectTransportChannels(); - SetTransportChannels(); std::vector> peer1_data_channels; std::vector> peer2_data_channels; @@ -339,18 +337,14 @@ TEST_F(QuicDataTransportTest, EndToEndSendReceiveMessages) { } } -// Tests that SetTransportChannel returns false when setting a NULL transport -// channel or a transport channel that is not equivalent to the one already set. -TEST_F(QuicDataTransportTest, SetTransportChannelReturnValue) { +// Tests that SetTransport returns false when setting a transport that is not +// equivalent to the one already set. +TEST_F(QuicDataTransportTest, SetTransportReturnValue) { QuicDataTransport* quic_data_transport = peer1_.quic_data_transport(); - EXPECT_FALSE(quic_data_transport->SetTransportChannel(nullptr)); - QuicTransportChannel* transport_channel = peer1_.quic_transport_channel(); - EXPECT_TRUE(quic_data_transport->SetTransportChannel(transport_channel)); - EXPECT_TRUE(quic_data_transport->SetTransportChannel(transport_channel)); - QuicTransportChannel* other_transport_channel = - peer2_.quic_transport_channel(); - EXPECT_FALSE( - quic_data_transport->SetTransportChannel(other_transport_channel)); + // Ignore the same transport name. + EXPECT_TRUE(quic_data_transport->SetTransport(kTransportName)); + // Return false when setting a different transport name. + EXPECT_FALSE(quic_data_transport->SetTransport("another transport name")); } } // namespace diff --git a/webrtc/api/test/peerconnectiontestwrapper.cc b/webrtc/api/test/peerconnectiontestwrapper.cc index 450a908520..b1eb58677d 100644 --- a/webrtc/api/test/peerconnectiontestwrapper.cc +++ b/webrtc/api/test/peerconnectiontestwrapper.cc @@ -58,7 +58,8 @@ PeerConnectionTestWrapper::PeerConnectionTestWrapper( PeerConnectionTestWrapper::~PeerConnectionTestWrapper() {} bool PeerConnectionTestWrapper::CreatePc( - const MediaConstraintsInterface* constraints) { + const MediaConstraintsInterface* constraints, + const webrtc::PeerConnectionInterface::RTCConfiguration& config) { std::unique_ptr port_allocator( new cricket::FakePortAllocator(network_thread_, nullptr)); @@ -74,11 +75,6 @@ bool PeerConnectionTestWrapper::CreatePc( return false; } - // CreatePeerConnection with RTCConfiguration. - webrtc::PeerConnectionInterface::RTCConfiguration config; - webrtc::PeerConnectionInterface::IceServer ice_server; - ice_server.uri = "stun:stun.l.google.com:19302"; - config.servers.push_back(ice_server); std::unique_ptr cert_generator( rtc::SSLStreamAdapter::HaveDtlsSrtp() ? new FakeRTCCertificateGenerator() : nullptr); diff --git a/webrtc/api/test/peerconnectiontestwrapper.h b/webrtc/api/test/peerconnectiontestwrapper.h index 0fa0f7ceec..c56035de79 100644 --- a/webrtc/api/test/peerconnectiontestwrapper.h +++ b/webrtc/api/test/peerconnectiontestwrapper.h @@ -32,7 +32,9 @@ class PeerConnectionTestWrapper rtc::Thread* worker_thread); virtual ~PeerConnectionTestWrapper(); - bool CreatePc(const webrtc::MediaConstraintsInterface* constraints); + bool CreatePc( + const webrtc::MediaConstraintsInterface* constraints, + const webrtc::PeerConnectionInterface::RTCConfiguration& config); rtc::scoped_refptr CreateDataChannel( const std::string& label, diff --git a/webrtc/api/webrtcsession.cc b/webrtc/api/webrtcsession.cc index 7497e2c7e0..35a5fab4c6 100644 --- a/webrtc/api/webrtcsession.cc +++ b/webrtc/api/webrtcsession.cc @@ -24,6 +24,7 @@ #include "webrtc/api/webrtcsessiondescriptionfactory.h" #include "webrtc/audio_sink.h" #include "webrtc/base/basictypes.h" +#include "webrtc/base/bind.h" #include "webrtc/base/checks.h" #include "webrtc/base/helpers.h" #include "webrtc/base/logging.h" @@ -38,6 +39,10 @@ #include "webrtc/pc/channelmanager.h" #include "webrtc/pc/mediasession.h" +#ifdef HAVE_QUIC +#include "webrtc/p2p/quic/quictransportchannel.h" +#endif // HAVE_QUIC + using cricket::ContentInfo; using cricket::ContentInfos; using cricket::MediaContentDescription; @@ -460,7 +465,8 @@ WebRtcSession::WebRtcSession( rtc::Thread* signaling_thread, cricket::PortAllocator* port_allocator, std::unique_ptr transport_controller) - : worker_thread_(worker_thread), + : network_thread_(network_thread), + worker_thread_(worker_thread), signaling_thread_(signaling_thread), // RFC 3264: The numeric value of the session id and version in the // o line MUST be representable with a "64 bit signed integer". @@ -505,6 +511,11 @@ WebRtcSession::~WebRtcSession() { SignalDataChannelDestroyed(); channel_manager_->DestroyDataChannel(data_channel_.release()); } +#ifdef HAVE_QUIC + if (quic_data_transport_) { + quic_data_transport_.reset(); + } +#endif SignalDestroyed(); LOG(LS_INFO) << "Session: " << id() << " is destroyed."; @@ -545,7 +556,21 @@ bool WebRtcSession::Initialize( // PeerConnectionFactoryInterface::Options. if (rtc_configuration.enable_rtp_data_channel) { data_channel_type_ = cricket::DCT_RTP; - } else { + } +#ifdef HAVE_QUIC + else if (rtc_configuration.enable_quic) { + // Use QUIC instead of DTLS when |enable_quic| is true. + data_channel_type_ = cricket::DCT_QUIC; + transport_controller_->use_quic(); + if (dtls_enabled_) { + LOG(LS_INFO) << "Using QUIC instead of DTLS"; + } + quic_data_transport_.reset( + new QuicDataTransport(signaling_thread(), worker_thread(), + network_thread(), transport_controller_.get())); + } +#endif // HAVE_QUIC + else { // DTLS has to be enabled to use SCTP. if (!options.disable_sctp_data_channels && dtls_enabled_) { data_channel_type_ = cricket::DCT_SCTP; @@ -1035,6 +1060,15 @@ bool WebRtcSession::EnableBundle(const cricket::ContentGroup& bundle) { const std::string& transport_name = *first_content_name; cricket::BaseChannel* first_channel = GetChannel(transport_name); +#ifdef HAVE_QUIC + if (quic_data_transport_ && + bundle.HasContentName(quic_data_transport_->content_name()) && + quic_data_transport_->transport_name() != transport_name) { + LOG(LS_ERROR) << "Unable to BUNDLE " << quic_data_transport_->content_name() + << " on " << transport_name << "with QUIC."; + } +#endif + auto maybe_set_transport = [this, bundle, transport_name, first_channel](cricket::BaseChannel* ch) { if (!ch || !bundle.HasContentName(ch->content_name())) { @@ -1543,9 +1577,17 @@ void WebRtcSession::RemoveUnusedChannels(const SessionDescription* desc) { const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc); - if ((!data_info || data_info->rejected) && data_channel_) { - SignalDataChannelDestroyed(); - channel_manager_->DestroyDataChannel(data_channel_.release()); + if (!data_info || data_info->rejected) { + if (data_channel_) { + SignalDataChannelDestroyed(); + channel_manager_->DestroyDataChannel(data_channel_.release()); + } +#ifdef HAVE_QUIC + // Clean up the existing QuicDataTransport and its QuicTransportChannels. + if (quic_data_transport_) { + quic_data_transport_.reset(); + } +#endif } } @@ -1659,6 +1701,15 @@ bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content, bool WebRtcSession::CreateDataChannel(const cricket::ContentInfo* content, const std::string* bundle_transport) { +#ifdef HAVE_QUIC + if (data_channel_type_ == cricket::DCT_QUIC) { + RTC_DCHECK(transport_controller_->quic()); + const std::string transport_name = + bundle_transport ? *bundle_transport : content->name; + quic_data_transport_->SetTransport(transport_name); + return true; + } +#endif // HAVE_QUIC bool sctp = (data_channel_type_ == cricket::DCT_SCTP); bool require_rtcp_mux = rtcp_mux_policy_ == PeerConnectionInterface::kRtcpMuxPolicyRequire; @@ -1842,7 +1893,7 @@ bool WebRtcSession::ReadyToUseRemoteCandidate( const IceCandidateInterface* candidate, const SessionDescriptionInterface* remote_desc, bool* valid) { - *valid = true;; + *valid = true; const SessionDescriptionInterface* current_remote_desc = remote_desc ? remote_desc : remote_desc_.get(); @@ -1865,13 +1916,12 @@ bool WebRtcSession::ReadyToUseRemoteCandidate( cricket::ContentInfo content = current_remote_desc->description()->contents()[mediacontent_index]; - cricket::BaseChannel* channel = GetChannel(content.name); - if (!channel) { + + const std::string transport_name = GetTransportName(content.name); + if (transport_name.empty()) { return false; } - - return transport_controller_->ReadyForRemoteCandidates( - channel->transport_name()); + return transport_controller_->ReadyForRemoteCandidates(transport_name); } void WebRtcSession::OnTransportControllerGatheringState( @@ -2008,4 +2058,19 @@ void WebRtcSession::OnSentPacket_w(const rtc::SentPacket& sent_packet) { media_controller_->call_w()->OnSentPacket(sent_packet); } +const std::string WebRtcSession::GetTransportName( + const std::string& content_name) { + cricket::BaseChannel* channel = GetChannel(content_name); + if (!channel) { +#ifdef HAVE_QUIC + if (data_channel_type_ == cricket::DCT_QUIC && quic_data_transport_ && + content_name == quic_data_transport_->transport_name()) { + return quic_data_transport_->transport_name(); + } +#endif + // Return an empty string if failed to retrieve the transport name. + return ""; + } + return channel->transport_name(); +} } // namespace webrtc diff --git a/webrtc/api/webrtcsession.h b/webrtc/api/webrtcsession.h index 1314c59d1b..3174568b7b 100644 --- a/webrtc/api/webrtcsession.h +++ b/webrtc/api/webrtcsession.h @@ -30,6 +30,10 @@ #include "webrtc/p2p/base/transportcontroller.h" #include "webrtc/pc/mediasession.h" +#ifdef HAVE_QUIC +#include "webrtc/api/quicdatatransport.h" +#endif // HAVE_QUIC + namespace cricket { class ChannelManager; @@ -38,6 +42,10 @@ class StatsReport; class VideoChannel; class VoiceChannel; +#ifdef HAVE_QUIC +class QuicTransportChannel; +#endif // HAVE_QUIC + } // namespace cricket namespace webrtc { @@ -146,6 +154,7 @@ class WebRtcSession : virtual ~WebRtcSession(); // These are const to allow them to be called from const methods. + rtc::Thread* network_thread() const { return network_thread_; } rtc::Thread* worker_thread() const { return worker_thread_; } rtc::Thread* signaling_thread() const { return signaling_thread_; } @@ -301,6 +310,11 @@ class WebRtcSession : // std::string represents the data channel label. sigslot::signal2 SignalDataChannelOpenMessage; +#ifdef HAVE_QUIC + QuicDataTransport* quic_data_transport() { + return quic_data_transport_.get(); + } +#endif // HAVE_QUIC private: // Indicates the type of SessionDescription in a call to SetLocalDescription @@ -445,6 +459,9 @@ class WebRtcSession : void OnSentPacket_w(const rtc::SentPacket& sent_packet); + const std::string GetTransportName(const std::string& content_name); + + rtc::Thread* const network_thread_; rtc::Thread* const worker_thread_; rtc::Thread* const signaling_thread_; @@ -476,6 +493,8 @@ class WebRtcSession : // not set or false, SCTP is allowed (DCT_SCTP); // 2. If constraint kEnableRtpDataChannels is true, RTP is allowed (DCT_RTP); // 3. If both 1&2 are false, data channel is not allowed (DCT_NONE). + // The data channel type could be DCT_QUIC if the QUIC data channel is + // enabled. cricket::DataChannelType data_channel_type_; // List of content names for which the remote side triggered an ICE restart. std::set pending_ice_restarts_; @@ -496,6 +515,10 @@ class WebRtcSession : bool received_first_video_packet_ = false; bool received_first_audio_packet_ = false; +#ifdef HAVE_QUIC + std::unique_ptr quic_data_transport_; +#endif // HAVE_QUIC + RTC_DISALLOW_COPY_AND_ASSIGN(WebRtcSession); }; } // namespace webrtc diff --git a/webrtc/api/webrtcsession_unittest.cc b/webrtc/api/webrtcsession_unittest.cc index 1aff50f1ca..c0d8a3bbdf 100644 --- a/webrtc/api/webrtcsession_unittest.cc +++ b/webrtc/api/webrtcsession_unittest.cc @@ -558,6 +558,8 @@ class WebRtcSessionTest if (session_->data_channel_type() == cricket::DCT_SCTP && data_channel_) { session_options->data_channel_type = cricket::DCT_SCTP; + } else if (session_->data_channel_type() == cricket::DCT_QUIC) { + session_options->data_channel_type = cricket::DCT_QUIC; } if (with_gcm_) { @@ -575,8 +577,8 @@ class WebRtcSessionTest (session_options->has_audio() || session_options->has_video() || session_options->has_data()); - if (session_->data_channel_type() == cricket::DCT_SCTP) { - session_options->data_channel_type = cricket::DCT_SCTP; + if (session_->data_channel_type() != cricket::DCT_RTP) { + session_options->data_channel_type = session_->data_channel_type(); } if (with_gcm_) { @@ -4212,6 +4214,26 @@ TEST_P(WebRtcSessionTest, TestRenegotiateNewMediaWithCandidatesSeparated) { SetLocalDescriptionWithoutError(answer); } +#ifdef HAVE_QUIC +TEST_P(WebRtcSessionTest, TestNegotiateQuic) { + configuration_.enable_quic = true; + InitWithDtls(GetParam()); + EXPECT_TRUE(session_->data_channel_type() == cricket::DCT_QUIC); + SessionDescriptionInterface* offer = CreateOffer(); + ASSERT_TRUE(offer); + ASSERT_TRUE(offer->description()); + SetLocalDescriptionWithoutError(offer); + cricket::MediaSessionOptions options; + options.recv_audio = true; + options.recv_video = true; + SessionDescriptionInterface* answer = + CreateRemoteAnswer(offer, options, cricket::SEC_DISABLED); + ASSERT_TRUE(answer); + ASSERT_TRUE(answer->description()); + SetRemoteDescriptionWithoutError(answer); +} +#endif // HAVE_QUIC + // Tests that RTX codec is removed from the answer when it isn't supported // by local side. TEST_F(WebRtcSessionTest, TestRtxRemovedByCreateAnswer) { diff --git a/webrtc/media/base/mediaengine.h b/webrtc/media/base/mediaengine.h index 4fbb71b17c..559617f536 100644 --- a/webrtc/media/base/mediaengine.h +++ b/webrtc/media/base/mediaengine.h @@ -168,11 +168,7 @@ class CompositeMediaEngine : public MediaEngineInterface { VIDEO video_; }; -enum DataChannelType { - DCT_NONE = 0, - DCT_RTP = 1, - DCT_SCTP = 2 -}; +enum DataChannelType { DCT_NONE = 0, DCT_RTP = 1, DCT_SCTP = 2, DCT_QUIC = 3 }; class DataEngineInterface { public: diff --git a/webrtc/p2p/base/faketransportcontroller.h b/webrtc/p2p/base/faketransportcontroller.h index b8c67ecd17..c15e164f41 100644 --- a/webrtc/p2p/base/faketransportcontroller.h +++ b/webrtc/p2p/base/faketransportcontroller.h @@ -29,6 +29,10 @@ #include "webrtc/base/sslfingerprint.h" #include "webrtc/base/thread.h" +#ifdef HAVE_QUIC +#include "webrtc/p2p/quic/quictransport.h" +#endif + namespace cricket { class FakeTransport; @@ -453,6 +457,21 @@ class FakeTransport : public Transport { rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; }; +#ifdef HAVE_QUIC +class FakeQuicTransport : public QuicTransport { + public: + FakeQuicTransport(const std::string& transport_name) + : QuicTransport(transport_name, nullptr, nullptr) {} + + protected: + QuicTransportChannel* CreateTransportChannel(int component) override { + FakeTransportChannel* fake_ice_transport_channel = + new FakeTransportChannel(name(), component); + return new QuicTransportChannel(fake_ice_transport_channel); + } +}; +#endif + // Fake candidate pair class, which can be passed to BaseChannel for testing // purposes. class FakeCandidatePair : public CandidatePairInterface { @@ -541,6 +560,11 @@ class FakeTransportController : public TransportController { protected: Transport* CreateTransport_n(const std::string& transport_name) override { +#ifdef HAVE_QUIC + if (quic()) { + return new FakeQuicTransport(transport_name); + } +#endif return new FakeTransport(transport_name); } diff --git a/webrtc/p2p/quic/quictransportchannel.h b/webrtc/p2p/quic/quictransportchannel.h index 1ab13fa0b2..eec82be73f 100644 --- a/webrtc/p2p/quic/quictransportchannel.h +++ b/webrtc/p2p/quic/quictransportchannel.h @@ -211,6 +211,8 @@ class QuicTransportChannel : public TransportChannelImpl, // Creates a new QUIC stream that can send data. ReliableQuicStream* CreateQuicStream(); + TransportChannelImpl* ice_transport_channel() { return channel_.get(); } + // Emitted when |quic_| creates a QUIC stream to receive data from the remote // peer, when the stream did not exist previously. sigslot::signal1 SignalIncomingStream;