diff --git a/webrtc/base/networkroute.h b/webrtc/base/networkroute.h new file mode 100644 index 0000000000..dcf9015cf7 --- /dev/null +++ b/webrtc/base/networkroute.h @@ -0,0 +1,44 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_BASE_NETWORKROUTE_H_ +#define WEBRTC_BASE_NETWORKROUTE_H_ + +// TODO(honghaiz): Make a directory that describes the interfaces and structs +// the media code can rely on and the network code can implement, and both can +// depend on that, but not depend on each other. Then, move this file to that +// directory. +namespace cricket { + +struct NetworkRoute { + bool connected; + uint16_t local_network_id; + uint16_t remote_network_id; + + NetworkRoute() + : connected(false), local_network_id(0), remote_network_id(0) {} + + // The route is connected if the local and remote network ids are provided. + NetworkRoute(uint16_t local_net_id, uint16_t remote_net_id) + : connected(true), + local_network_id(local_net_id), + remote_network_id(remote_net_id) {} + + bool operator==(const NetworkRoute& nr) const { + return connected == nr.connected && + local_network_id == nr.local_network_id && + remote_network_id == nr.remote_network_id; + } + + bool operator!=(const NetworkRoute& nr) const { return !(*this == nr); } +}; +} // namespace cricket + +#endif // WEBRTC_BASE_NETWORKROUTE_H_ diff --git a/webrtc/media/base/fakemediaengine.h b/webrtc/media/base/fakemediaengine.h index af05144b52..6feaf8e989 100644 --- a/webrtc/media/base/fakemediaengine.h +++ b/webrtc/media/base/fakemediaengine.h @@ -20,6 +20,7 @@ #include "webrtc/audio_sink.h" #include "webrtc/base/copyonwritebuffer.h" +#include "webrtc/base/networkroute.h" #include "webrtc/base/stringutils.h" #include "webrtc/media/base/audiosource.h" #include "webrtc/media/base/mediaengine.h" @@ -178,6 +179,12 @@ template class RtpHelper : public Base { return ready_to_send_; } + NetworkRoute last_network_route() const { return last_network_route_; } + int num_network_route_changes() const { return num_network_route_changes_; } + void set_num_network_route_changes(int changes) { + num_network_route_changes_ = changes; + } + protected: bool MuteStream(uint32_t ssrc, bool mute) { if (!HasSendStream(ssrc) && ssrc != 0) { @@ -216,6 +223,11 @@ template class RtpHelper : public Base { virtual void OnReadyToSend(bool ready) { ready_to_send_ = ready; } + virtual void OnNetworkRouteChanged(const std::string& transport_name, + const NetworkRoute& network_route) { + last_network_route_ = network_route; + ++num_network_route_changes_; + } bool fail_set_send_codecs() const { return fail_set_send_codecs_; } bool fail_set_recv_codecs() const { return fail_set_recv_codecs_; } @@ -235,6 +247,8 @@ template class RtpHelper : public Base { uint32_t send_ssrc_; std::string rtcp_cname_; bool ready_to_send_; + NetworkRoute last_network_route_; + int num_network_route_changes_ = 0; }; class FakeVoiceMediaChannel : public RtpHelper { diff --git a/webrtc/media/base/mediachannel.h b/webrtc/media/base/mediachannel.h index 95355c9576..5e0f2d8bc2 100644 --- a/webrtc/media/base/mediachannel.h +++ b/webrtc/media/base/mediachannel.h @@ -20,6 +20,7 @@ #include "webrtc/base/copyonwritebuffer.h" #include "webrtc/base/dscp.h" #include "webrtc/base/logging.h" +#include "webrtc/base/networkroute.h" #include "webrtc/base/optional.h" #include "webrtc/base/sigslot.h" #include "webrtc/base/socket.h" @@ -387,6 +388,9 @@ class MediaChannel : public sigslot::has_slots<> { const rtc::PacketTime& packet_time) = 0; // Called when the socket's ability to send has changed. virtual void OnReadyToSend(bool ready) = 0; + // Called when the network route used for sending packets changed. + virtual void OnNetworkRouteChanged(const std::string& transport_name, + const NetworkRoute& network_route) = 0; // Creates a new outgoing media stream with SSRCs and CNAME as described // by sp. virtual bool AddSendStream(const StreamParams& sp) = 0; @@ -1104,6 +1108,9 @@ class DataMediaChannel : public MediaChannel { virtual bool SetSend(bool send) = 0; virtual bool SetReceive(bool receive) = 0; + virtual void OnNetworkRouteChanged(const std::string& transport_name, + const NetworkRoute& network_route) {} + virtual bool SendData( const SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc index 9f74a86a84..cd05f8e6ff 100644 --- a/webrtc/media/engine/webrtcvideoengine2.cc +++ b/webrtc/media/engine/webrtcvideoengine2.cc @@ -1410,6 +1410,13 @@ void WebRtcVideoChannel2::OnReadyToSend(bool ready) { ready ? webrtc::kNetworkUp : webrtc::kNetworkDown); } +void WebRtcVideoChannel2::OnNetworkRouteChanged( + const std::string& transport_name, + const NetworkRoute& network_route) { + // TODO(honghaiz): uncomment this once the function in call is implemented. + // call_->OnNetworkRouteChanged(transport_name, network_route); +} + bool WebRtcVideoChannel2::MuteStream(uint32_t ssrc, bool mute) { LOG(LS_VERBOSE) << "MuteStream: " << ssrc << " -> " << (mute ? "mute" : "unmute"); diff --git a/webrtc/media/engine/webrtcvideoengine2.h b/webrtc/media/engine/webrtcvideoengine2.h index 9cbb640fca..8c05c60f68 100644 --- a/webrtc/media/engine/webrtcvideoengine2.h +++ b/webrtc/media/engine/webrtcvideoengine2.h @@ -19,6 +19,7 @@ #include "webrtc/base/asyncinvoker.h" #include "webrtc/base/criticalsection.h" +#include "webrtc/base/networkroute.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/base/thread_checker.h" #include "webrtc/media/base/videosinkinterface.h" @@ -167,6 +168,8 @@ class WebRtcVideoChannel2 : public VideoMediaChannel, public webrtc::Transport { void OnRtcpReceived(rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) override; void OnReadyToSend(bool ready) override; + void OnNetworkRouteChanged(const std::string& transport_name, + const NetworkRoute& network_route) override; void SetInterface(NetworkInterface* iface) override; // Implemented for VideoMediaChannelTest. diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc index 2c7f2216f5..6fe3d86fd9 100644 --- a/webrtc/media/engine/webrtcvoiceengine.cc +++ b/webrtc/media/engine/webrtcvoiceengine.cc @@ -2328,6 +2328,13 @@ void WebRtcVoiceMediaChannel::OnRtcpReceived( } } +void WebRtcVoiceMediaChannel::OnNetworkRouteChanged( + const std::string& transport_name, + const NetworkRoute& network_route) { + // TODO(honghaiz): uncomment this once the function in call is implemented. + // call_->OnNetworkRouteChanged(transport_name, network_route); +} + bool WebRtcVoiceMediaChannel::MuteStream(uint32_t ssrc, bool muted) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); int channel = GetSendChannelId(ssrc); diff --git a/webrtc/media/engine/webrtcvoiceengine.h b/webrtc/media/engine/webrtcvoiceengine.h index 056b0780ef..c9798cbc95 100644 --- a/webrtc/media/engine/webrtcvoiceengine.h +++ b/webrtc/media/engine/webrtcvoiceengine.h @@ -18,6 +18,7 @@ #include "webrtc/audio_state.h" #include "webrtc/base/buffer.h" +#include "webrtc/base/networkroute.h" #include "webrtc/base/stream.h" #include "webrtc/base/thread_checker.h" #include "webrtc/call.h" @@ -183,6 +184,8 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, const rtc::PacketTime& packet_time) override; void OnRtcpReceived(rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) override; + void OnNetworkRouteChanged(const std::string& transport_name, + const NetworkRoute& network_route) override; void OnReadyToSend(bool ready) override; bool GetStats(VoiceMediaInfo* info) override; diff --git a/webrtc/p2p/base/candidatepairinterface.h b/webrtc/p2p/base/candidatepairinterface.h new file mode 100644 index 0000000000..1d11c22a52 --- /dev/null +++ b/webrtc/p2p/base/candidatepairinterface.h @@ -0,0 +1,28 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_P2P_BASE_CANDIDATEPAIRINTERFACE_H_ +#define WEBRTC_P2P_BASE_CANDIDATEPAIRINTERFACE_H_ + +namespace cricket { + +class Candidate; + +class CandidatePairInterface { + public: + virtual ~CandidatePairInterface() {} + + virtual const Candidate& local_candidate() const = 0; + virtual const Candidate& remote_candidate() const = 0; +}; + +} // namespace cricket + +#endif // WEBRTC_P2P_BASE_CANDIDATEPAIRINTERFACE_H_ diff --git a/webrtc/p2p/base/dtlstransportchannel.cc b/webrtc/p2p/base/dtlstransportchannel.cc index 33b5b6f268..2006391463 100644 --- a/webrtc/p2p/base/dtlstransportchannel.cc +++ b/webrtc/p2p/base/dtlstransportchannel.cc @@ -119,6 +119,8 @@ DtlsTransportChannelWrapper::DtlsTransportChannelWrapper( &DtlsTransportChannelWrapper::OnRoleConflict); channel_->SignalRouteChange.connect(this, &DtlsTransportChannelWrapper::OnRouteChange); + channel_->SignalSelectedCandidatePairChanged.connect( + this, &DtlsTransportChannelWrapper::OnSelectedCandidatePairChanged); channel_->SignalConnectionRemoved.connect(this, &DtlsTransportChannelWrapper::OnConnectionRemoved); channel_->SignalReceivingState.connect(this, @@ -634,6 +636,13 @@ void DtlsTransportChannelWrapper::OnRouteChange( SignalRouteChange(this, candidate); } +void DtlsTransportChannelWrapper::OnSelectedCandidatePairChanged( + TransportChannel* channel, + CandidatePairInterface* selected_candidate_pair) { + ASSERT(channel == channel_); + SignalSelectedCandidatePairChanged(this, selected_candidate_pair); +} + void DtlsTransportChannelWrapper::OnConnectionRemoved( TransportChannelImpl* channel) { ASSERT(channel == channel_); diff --git a/webrtc/p2p/base/dtlstransportchannel.h b/webrtc/p2p/base/dtlstransportchannel.h index a58b1a0f6b..0c6b303d59 100644 --- a/webrtc/p2p/base/dtlstransportchannel.h +++ b/webrtc/p2p/base/dtlstransportchannel.h @@ -216,6 +216,9 @@ class DtlsTransportChannelWrapper : public TransportChannelImpl { const Candidates& candidates); void OnRoleConflict(TransportChannelImpl* channel); void OnRouteChange(TransportChannel* channel, const Candidate& candidate); + void OnSelectedCandidatePairChanged( + TransportChannel* channel, + CandidatePairInterface* selected_candidate_pair); void OnConnectionRemoved(TransportChannelImpl* channel); void Reconnect(); diff --git a/webrtc/p2p/base/faketransportcontroller.h b/webrtc/p2p/base/faketransportcontroller.h index d5fbec4e39..a267f20967 100644 --- a/webrtc/p2p/base/faketransportcontroller.h +++ b/webrtc/p2p/base/faketransportcontroller.h @@ -15,6 +15,7 @@ #include #include +#include "webrtc/p2p/base/candidatepairinterface.h" #include "webrtc/p2p/base/transport.h" #include "webrtc/p2p/base/transportchannel.h" #include "webrtc/p2p/base/transportcontroller.h" @@ -452,6 +453,24 @@ class FakeTransport : public Transport { rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; }; +// Fake candidate pair class, which can be passed to BaseChannel for testing +// purposes. +class FakeCandidatePair : public CandidatePairInterface { + public: + FakeCandidatePair(const Candidate& local_candidate, + const Candidate& remote_candidate) + : local_candidate_(local_candidate), + remote_candidate_(remote_candidate) {} + const Candidate& local_candidate() const override { return local_candidate_; } + const Candidate& remote_candidate() const override { + return remote_candidate_; + } + + private: + Candidate local_candidate_; + Candidate remote_candidate_; +}; + // Fake TransportController class, which can be passed into a BaseChannel object // for test purposes. Can be connected to other FakeTransportControllers via // Connect(). @@ -503,6 +522,18 @@ class FakeTransportController : public TransportController { component); } + FakeCandidatePair* CreateFakeCandidatePair( + const rtc::SocketAddress& local_address, + int16_t local_network_id, + const rtc::SocketAddress& remote_address, + int16_t remote_network_id) { + Candidate local_candidate(0, "udp", local_address, 0u, "", "", "local", 0, + "foundation", local_network_id, 0); + Candidate remote_candidate(0, "udp", remote_address, 0u, "", "", "local", 0, + "foundation", remote_network_id, 0); + return new FakeCandidatePair(local_candidate, remote_candidate); + } + void set_fail_channel_creation(bool fail_channel_creation) { fail_create_channel_ = fail_channel_creation; } diff --git a/webrtc/p2p/base/p2ptransportchannel.cc b/webrtc/p2p/base/p2ptransportchannel.cc index e0428d6383..8cb1ffe8bc 100644 --- a/webrtc/p2p/base/p2ptransportchannel.cc +++ b/webrtc/p2p/base/p2ptransportchannel.cc @@ -18,6 +18,7 @@ #include "webrtc/base/logging.h" #include "webrtc/base/stringencode.h" #include "webrtc/p2p/base/candidate.h" +#include "webrtc/p2p/base/candidatepairinterface.h" #include "webrtc/p2p/base/common.h" #include "webrtc/p2p/base/relayport.h" // For RELAY_PORT_TYPE. #include "webrtc/p2p/base/stunport.h" // For STUN_PORT_TYPE. @@ -1165,6 +1166,9 @@ void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) { } else { LOG_J(LS_INFO, this) << "No best connection"; } + // TODO(honghaiz): rename best_connection_ with selected_connection_ or + // selected_candidate pair_. + SignalSelectedCandidatePairChanged(this, best_connection_); } // Warning: UpdateState should eventually be called whenever a connection diff --git a/webrtc/p2p/base/p2ptransportchannel.h b/webrtc/p2p/base/p2ptransportchannel.h index 04bc951269..23e4d7f99e 100644 --- a/webrtc/p2p/base/p2ptransportchannel.h +++ b/webrtc/p2p/base/p2ptransportchannel.h @@ -25,6 +25,7 @@ #include #include #include "webrtc/p2p/base/candidate.h" +#include "webrtc/p2p/base/candidatepairinterface.h" #include "webrtc/p2p/base/p2ptransport.h" #include "webrtc/p2p/base/portallocator.h" #include "webrtc/p2p/base/portinterface.h" diff --git a/webrtc/p2p/base/p2ptransportchannel_unittest.cc b/webrtc/p2p/base/p2ptransportchannel_unittest.cc index d3332ebd0f..a0855c7605 100644 --- a/webrtc/p2p/base/p2ptransportchannel_unittest.cc +++ b/webrtc/p2p/base/p2ptransportchannel_unittest.cc @@ -317,6 +317,8 @@ class P2PTransportChannelTestBase : public testing::Test, this, &P2PTransportChannelTestBase::OnReadPacket); channel->SignalRoleConflict.connect( this, &P2PTransportChannelTestBase::OnRoleConflict); + channel->SignalSelectedCandidatePairChanged.connect( + this, &P2PTransportChannelTestBase::OnSelectedCandidatePairChanged); channel->SetIceCredentials(local_ice_ufrag, local_ice_pwd); if (clear_remote_candidates_ufrag_pwd_) { // This only needs to be set if we're clearing them from the @@ -741,6 +743,13 @@ class P2PTransportChannelTestBase : public testing::Test, cricket::ICEROLE_CONTROLLED : cricket::ICEROLE_CONTROLLING; channel->SetIceRole(new_role); } + + void OnSelectedCandidatePairChanged( + cricket::TransportChannel* channel, + cricket::CandidatePairInterface* candidate_pair) { + ++num_selected_candidate_pair_changes_; + } + int SendData(cricket::TransportChannel* channel, const char* data, size_t len) { rtc::PacketOptions options; @@ -794,6 +803,13 @@ class P2PTransportChannelTestBase : public testing::Test, force_relay_ = relay; } + int num_selected_candidate_pair_changes() { + return num_selected_candidate_pair_changes_; + } + void set_num_selected_candidate_pair_changes(int num) { + num_selected_candidate_pair_changes_ = num; + } + private: rtc::Thread* main_; rtc::scoped_ptr pss_; @@ -808,6 +824,7 @@ class P2PTransportChannelTestBase : public testing::Test, rtc::SocksProxyServer socks_server2_; Endpoint ep1_; Endpoint ep2_; + int num_selected_candidate_pair_changes_ = 0; bool clear_remote_candidates_ufrag_pwd_; bool force_relay_; }; @@ -1578,8 +1595,9 @@ TEST_F(P2PTransportChannelMultihomedTest, DISABLED_TestBasic) { Test(kLocalUdpToLocalUdp); } -// Test that we can quickly switch links if an interface goes down. -// The controlled side has two interfaces and one will die. +// Test that we can quickly switch links if an interface goes down. This also +// tests that when the link switches, |SignalSelectedCandidatePairChanged| will +// be fired. The controlled side has two interfaces and one will die. TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControlledSide) { AddAddress(0, kPublicAddrs[0]); // Adding alternate address will make sure |kPublicAddrs| has the higher @@ -1607,6 +1625,7 @@ TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControlledSide) { ep1_ch1()->SetIceConfig(config); ep2_ch1()->SetIceConfig(config); + set_num_selected_candidate_pair_changes(0); // Blackhole any traffic to or from the public addrs. LOG(LS_INFO) << "Failing over..."; fw()->AddRule(false, rtc::FP_ANY, rtc::FD_ANY, kPublicAddrs[1]); @@ -1627,12 +1646,15 @@ TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControlledSide) { RemoteCandidate(ep1_ch1())->address().EqualIPs(kAlternateAddrs[1])); EXPECT_TRUE( LocalCandidate(ep2_ch1())->address().EqualIPs(kAlternateAddrs[1])); + // It should have changed twice, one on each side. + EXPECT_EQ(2, num_selected_candidate_pair_changes()); DestroyChannels(); } -// Test that we can quickly switch links if an interface goes down. -// The controlling side has two interfaces and one will die. +// Test that we can quickly switch links if an interface goes down. This also +// tests that when the link switches, |SignalSelectedCandidatePairChanged| will +// be fired. The controlling side has two interfaces and one will die. TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControllingSide) { // Adding alternate address will make sure |kPublicAddrs| has the higher // priority than others. This is due to FakeNetwork::AddInterface method. @@ -1658,6 +1680,7 @@ TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControllingSide) { cricket::IceConfig config = CreateIceConfig(1000, false); ep1_ch1()->SetIceConfig(config); ep2_ch1()->SetIceConfig(config); + set_num_selected_candidate_pair_changes(0); // Blackhole any traffic to or from the public addrs. LOG(LS_INFO) << "Failing over..."; @@ -1679,6 +1702,7 @@ TEST_F(P2PTransportChannelMultihomedTest, TestFailoverControllingSide) { EXPECT_TRUE(RemoteCandidate(ep1_ch1())->address().EqualIPs(kPublicAddrs[1])); EXPECT_TRUE( RemoteCandidate(ep2_ch1())->address().EqualIPs(kAlternateAddrs[0])); + EXPECT_EQ(2, num_selected_candidate_pair_changes()); DestroyChannels(); } diff --git a/webrtc/p2p/base/port.cc b/webrtc/p2p/base/port.cc index eba15f69a3..74b9eddf55 100644 --- a/webrtc/p2p/base/port.cc +++ b/webrtc/p2p/base/port.cc @@ -813,6 +813,10 @@ const Candidate& Connection::local_candidate() const { return port_->Candidates()[local_candidate_index_]; } +const Candidate& Connection::remote_candidate() const { + return remote_candidate_; +} + uint64_t Connection::priority() const { uint64_t priority = 0; // RFC 5245 - 5.7.2. Computing Pair Priority and Ordering Pairs diff --git a/webrtc/p2p/base/port.h b/webrtc/p2p/base/port.h index 4c5a15090e..7c4468d2e6 100644 --- a/webrtc/p2p/base/port.h +++ b/webrtc/p2p/base/port.h @@ -17,6 +17,7 @@ #include #include "webrtc/p2p/base/candidate.h" +#include "webrtc/p2p/base/candidatepairinterface.h" #include "webrtc/p2p/base/packetsocketfactory.h" #include "webrtc/p2p/base/portinterface.h" #include "webrtc/p2p/base/stun.h" @@ -410,8 +411,9 @@ class Port : public PortInterface, public rtc::MessageHandler, // Represents a communication link between a port on the local client and a // port on the remote client. -class Connection : public rtc::MessageHandler, - public sigslot::has_slots<> { +class Connection : public CandidatePairInterface, + public rtc::MessageHandler, + public sigslot::has_slots<> { public: struct SentPing { SentPing(const std::string id, int64_t sent_time) @@ -435,11 +437,11 @@ class Connection : public rtc::MessageHandler, Port* port() { return port_; } const Port* port() const { return port_; } + // Implementation of virtual methods in CandidatePairInterface. // Returns the description of the local port virtual const Candidate& local_candidate() const; - // Returns the description of the remote port to which we communicate. - const Candidate& remote_candidate() const { return remote_candidate_; } + virtual const Candidate& remote_candidate() const; // Returns the pair priority. uint64_t priority() const; diff --git a/webrtc/p2p/base/transportchannel.h b/webrtc/p2p/base/transportchannel.h index b91af139b7..0dba02f084 100644 --- a/webrtc/p2p/base/transportchannel.h +++ b/webrtc/p2p/base/transportchannel.h @@ -15,6 +15,7 @@ #include #include "webrtc/p2p/base/candidate.h" +#include "webrtc/p2p/base/candidatepairinterface.h" #include "webrtc/p2p/base/transport.h" #include "webrtc/p2p/base/transportdescription.h" #include "webrtc/base/asyncpacketsocket.h" @@ -146,11 +147,18 @@ class TransportChannel : public sigslot::has_slots<> { // Signalled each time a packet is sent on this channel. sigslot::signal2 SignalSentPacket; + // Deprecated by SignalSelectedCandidatePairChanged // This signal occurs when there is a change in the way that packets are // being routed, i.e. to a different remote location. The candidate // indicates where and how we are currently sending media. sigslot::signal2 SignalRouteChange; + // Signalled when the current selected candidate pair has changed. + // The first parameter is the transport channel that signals the event. + // The second parameter is the new selected candidate pair. + sigslot::signal2 + SignalSelectedCandidatePairChanged; + // Invoked when the channel is being destroyed. sigslot::signal1 SignalDestroyed; diff --git a/webrtc/p2p/quic/quictransportchannel.cc b/webrtc/p2p/quic/quictransportchannel.cc index 8c46fb0bf1..7e68612388 100644 --- a/webrtc/p2p/quic/quictransportchannel.cc +++ b/webrtc/p2p/quic/quictransportchannel.cc @@ -140,6 +140,8 @@ QuicTransportChannel::QuicTransportChannel(TransportChannelImpl* channel) &QuicTransportChannel::OnRoleConflict); channel_->SignalRouteChange.connect(this, &QuicTransportChannel::OnRouteChange); + channel_->SignalSelectedCandidatePairChanged.connect( + this, &QuicTransportChannel::OnSelectedCandidatePairChanged); channel_->SignalConnectionRemoved.connect( this, &QuicTransportChannel::OnConnectionRemoved); channel_->SignalReceivingState.connect( @@ -387,6 +389,13 @@ void QuicTransportChannel::OnRouteChange(TransportChannel* channel, SignalRouteChange(this, candidate); } +void QuicTransportChannel::OnSelectedCandidatePairChanged( + TransportChannel* channel, + CandidatePairInterface* selected_candidate_pair) { + ASSERT(channel == channel_); + SignalSelectedCandidatePairChanged(this, selected_candidate_pair); +} + void QuicTransportChannel::OnConnectionRemoved(TransportChannelImpl* channel) { ASSERT(channel == channel_); SignalConnectionRemoved(this); diff --git a/webrtc/p2p/quic/quictransportchannel.h b/webrtc/p2p/quic/quictransportchannel.h index dff57957df..a3c0106d0a 100644 --- a/webrtc/p2p/quic/quictransportchannel.h +++ b/webrtc/p2p/quic/quictransportchannel.h @@ -230,6 +230,9 @@ class QuicTransportChannel : public TransportChannelImpl, void OnCandidateGathered(TransportChannelImpl* channel, const Candidate& c); void OnRoleConflict(TransportChannelImpl* channel); void OnRouteChange(TransportChannel* channel, const Candidate& candidate); + void OnSelectedCandidatePairChanged( + TransportChannel* channel, + CandidatePairInterface* selected_candidate_pair); void OnConnectionRemoved(TransportChannelImpl* channel); // Callbacks for |quic_|. diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc index 8e916f1279..25ba2c0586 100644 --- a/webrtc/pc/channel.cc +++ b/webrtc/pc/channel.cc @@ -19,6 +19,7 @@ #include "webrtc/base/copyonwritebuffer.h" #include "webrtc/base/dscp.h" #include "webrtc/base/logging.h" +#include "webrtc/base/networkroute.h" #include "webrtc/base/trace_event.h" #include "webrtc/media/base/mediaconstants.h" #include "webrtc/media/base/rtputils.h" @@ -346,6 +347,8 @@ void BaseChannel::ConnectToTransportChannel(TransportChannel* tc) { tc->SignalReadPacket.connect(this, &BaseChannel::OnChannelRead); tc->SignalReadyToSend.connect(this, &BaseChannel::OnReadyToSend); tc->SignalDtlsState.connect(this, &BaseChannel::OnDtlsState); + tc->SignalSelectedCandidatePairChanged.connect( + this, &BaseChannel::OnSelectedCandidatePairChanged); } void BaseChannel::DisconnectFromTransportChannel(TransportChannel* tc) { @@ -504,6 +507,20 @@ void BaseChannel::OnDtlsState(TransportChannel* channel, } } +void BaseChannel::OnSelectedCandidatePairChanged( + TransportChannel* channel, + CandidatePairInterface* selected_candidate_pair) { + ASSERT(channel == transport_channel_ || channel == rtcp_transport_channel_); + NetworkRoute network_route; + if (selected_candidate_pair) { + network_route = + NetworkRoute(selected_candidate_pair->local_candidate().network_id(), + selected_candidate_pair->remote_candidate().network_id()); + } + media_channel()->OnNetworkRouteChanged(channel->transport_name(), + network_route); +} + void BaseChannel::SetReadyToSend(bool rtcp, bool ready) { if (rtcp) { rtcp_ready_to_send_ = ready; diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h index 45657f88ee..e22196cae7 100644 --- a/webrtc/pc/channel.h +++ b/webrtc/pc/channel.h @@ -207,6 +207,10 @@ class BaseChannel void OnDtlsState(TransportChannel* channel, DtlsTransportState state); + void OnSelectedCandidatePairChanged( + TransportChannel* channel, + CandidatePairInterface* selected_candidate_pair); + bool PacketIsRtcp(const TransportChannel* channel, const char* data, size_t len); bool SendPacket(bool rtcp, diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc index ecbdad4888..9d20def32f 100644 --- a/webrtc/pc/channel_unittest.cc +++ b/webrtc/pc/channel_unittest.cc @@ -490,6 +490,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { } } + cricket::CandidatePairInterface* last_selected_candidate_pair() { + return last_selected_candidate_pair_; + } + void AddLegacyStreamInContent(uint32_t ssrc, int flags, typename T::Content* content) { @@ -951,6 +955,41 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { EXPECT_TRUE(media_channel2_->sending()); } + // Tests that when the transport channel signals a candidate pair change + // event, the media channel will receive a call on the network route change. + void TestNetworkRouteChanges() { + CreateChannels(0, 0); + + cricket::TransportChannel* transport_channel1 = + channel1_->transport_channel(); + ASSERT_TRUE(transport_channel1 != nullptr); + typename T::MediaChannel* media_channel1 = + static_cast(channel1_->media_channel()); + ASSERT_TRUE(media_channel1 != nullptr); + + media_channel1_->set_num_network_route_changes(0); + // The transport channel becomes disconnected. + transport_channel1->SignalSelectedCandidatePairChanged(transport_channel1, + nullptr); + EXPECT_EQ(1, media_channel1_->num_network_route_changes()); + EXPECT_FALSE(media_channel1->last_network_route().connected); + + media_channel1_->set_num_network_route_changes(0); + // The transport channel becomes connected. + rtc::SocketAddress local_address("192.168.1.1", 1000 /* port number */); + rtc::SocketAddress remote_address("192.168.1.2", 2000 /* port number */); + uint16_t local_net_id = 1; + uint16_t remote_net_id = 2; + rtc::scoped_ptr candidate_pair( + transport_controller1_.CreateFakeCandidatePair( + local_address, local_net_id, remote_address, remote_net_id)); + transport_channel1->SignalSelectedCandidatePairChanged( + transport_channel1, candidate_pair.get()); + EXPECT_EQ(1, media_channel1_->num_network_route_changes()); + cricket::NetworkRoute expected_network_route(local_net_id, remote_net_id); + EXPECT_EQ(expected_network_route, media_channel1->last_network_route()); + } + // Test setting up a call. void TestCallSetup() { CreateChannels(0, 0); @@ -1871,6 +1910,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { std::string rtcp_packet_; int media_info_callbacks1_; int media_info_callbacks2_; + cricket::CandidatePairInterface* last_selected_candidate_pair_; }; template<> @@ -1996,7 +2036,6 @@ class VideoChannelTest // VoiceChannelTest - TEST_F(VoiceChannelTest, TestInit) { Base::TestInit(); EXPECT_FALSE(media_channel1_->IsStreamMuted(0)); @@ -2069,6 +2108,10 @@ TEST_F(VoiceChannelTest, TestMediaContentDirection) { Base::TestMediaContentDirection(); } +TEST_F(VoiceChannelTest, TestNetworkRouteChanges) { + Base::TestNetworkRouteChanges(); +} + TEST_F(VoiceChannelTest, TestCallSetup) { Base::TestCallSetup(); } @@ -2399,6 +2442,10 @@ TEST_F(VideoChannelTest, TestMediaContentDirection) { Base::TestMediaContentDirection(); } +TEST_F(VideoChannelTest, TestNetworkRouteChanges) { + Base::TestNetworkRouteChanges(); +} + TEST_F(VideoChannelTest, TestCallSetup) { Base::TestCallSetup(); }