diff --git a/webrtc/pc/BUILD.gn b/webrtc/pc/BUILD.gn index 2585416a7c..71e29d8a6c 100644 --- a/webrtc/pc/BUILD.gn +++ b/webrtc/pc/BUILD.gn @@ -48,10 +48,13 @@ rtc_static_library("rtc_pc_base") { "rtcpmuxfilter.h", "rtptransport.cc", "rtptransport.h", + "rtptransportinternal.h", "srtpfilter.cc", "srtpfilter.h", "srtpsession.cc", "srtpsession.h", + "srtptransport.cc", + "srtptransport.h", "voicechannel.h", ] @@ -258,9 +261,11 @@ if (rtc_include_tests) { "mediasession_unittest.cc", "rtcpmuxfilter_unittest.cc", "rtptransport_unittest.cc", + "rtptransporttestutil.h", "srtpfilter_unittest.cc", "srtpsession_unittest.cc", "srtptestutil.h", + "srtptransport_unittest.cc", ] include_dirs = [ "//third_party/libsrtp/srtp" ] @@ -289,6 +294,7 @@ if (rtc_include_tests) { "../rtc_base:rtc_base_tests_main", "../rtc_base:rtc_base_tests_utils", "../system_wrappers:metrics_default", + "../test:test_support", ] if (rtc_build_libsrtp) { diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc index f6568c3c18..59f0869431 100644 --- a/webrtc/pc/channel.cc +++ b/webrtc/pc/channel.cc @@ -31,6 +31,8 @@ #include "webrtc/media/engine/webrtcvoiceengine.h" // nogncheck #include "webrtc/p2p/base/packettransportinternal.h" #include "webrtc/pc/channelmanager.h" +#include "webrtc/pc/rtptransport.h" +#include "webrtc/pc/srtptransport.h" namespace cricket { using rtc::Bind; @@ -156,7 +158,11 @@ BaseChannel::BaseChannel(rtc::Thread* worker_thread, signaling_thread_(signaling_thread), content_name_(content_name), rtcp_mux_required_(rtcp_mux_required), - rtp_transport_(rtc::MakeUnique(rtcp_mux_required)), + rtp_transport_( + srtp_required + ? rtc::WrapUnique( + new webrtc::SrtpTransport(rtcp_mux_required, content_name)) + : rtc::MakeUnique(rtcp_mux_required)), srtp_required_(srtp_required), media_channel_(media_channel), selected_candidate_pair_(nullptr) { @@ -170,7 +176,7 @@ BaseChannel::BaseChannel(rtc::Thread* worker_thread, // with a callback interface later so that the demuxer can select which // channel to signal. rtp_transport_->SignalPacketReceived.connect(this, - &BaseChannel::OnPacketReceived); + &BaseChannel::OnPacketReceived); LOG(LS_INFO) << "Created channel for " << content_name; } diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h index 11d21212f8..c6dc29dd08 100644 --- a/webrtc/pc/channel.h +++ b/webrtc/pc/channel.h @@ -33,7 +33,7 @@ #include "webrtc/pc/mediamonitor.h" #include "webrtc/pc/mediasession.h" #include "webrtc/pc/rtcpmuxfilter.h" -#include "webrtc/pc/rtptransport.h" +#include "webrtc/pc/rtptransportinternal.h" #include "webrtc/pc/srtpfilter.h" #include "webrtc/rtc_base/asyncinvoker.h" #include "webrtc/rtc_base/asyncudpsocket.h" @@ -397,7 +397,7 @@ class BaseChannel // If non-null, "X_dtls_transport_" will always equal "X_packet_transport_". DtlsTransportInternal* rtp_dtls_transport_ = nullptr; DtlsTransportInternal* rtcp_dtls_transport_ = nullptr; - std::unique_ptr rtp_transport_; + std::unique_ptr rtp_transport_; std::vector > socket_options_; std::vector > rtcp_socket_options_; SrtpFilter srtp_filter_; diff --git a/webrtc/pc/rtptransport.cc b/webrtc/pc/rtptransport.cc index d530c73c50..8a524dd07a 100644 --- a/webrtc/pc/rtptransport.cc +++ b/webrtc/pc/rtptransport.cc @@ -77,7 +77,7 @@ bool RtpTransport::IsWritable(bool rtcp) const { } bool RtpTransport::SendPacket(bool rtcp, - const rtc::CopyOnWriteBuffer* packet, + rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options, int flags) { rtc::PacketTransportInternal* transport = rtcp && !rtcp_mux_enabled_ diff --git a/webrtc/pc/rtptransport.h b/webrtc/pc/rtptransport.h index a86fa126bb..cf64a0003d 100644 --- a/webrtc/pc/rtptransport.h +++ b/webrtc/pc/rtptransport.h @@ -11,8 +11,8 @@ #ifndef WEBRTC_PC_RTPTRANSPORT_H_ #define WEBRTC_PC_RTPTRANSPORT_H_ -#include "webrtc/api/ortc/rtptransportinterface.h" #include "webrtc/pc/bundlefilter.h" +#include "webrtc/pc/rtptransportinternal.h" #include "webrtc/rtc_base/sigslot.h" namespace rtc { @@ -26,7 +26,7 @@ class PacketTransportInternal; namespace webrtc { -class RtpTransport : public RtpTransportInterface, public sigslot::has_slots<> { +class RtpTransport : public RtpTransportInternal { public: RtpTransport(const RtpTransport&) = delete; RtpTransport& operator=(const RtpTransport&) = delete; @@ -35,17 +35,17 @@ class RtpTransport : public RtpTransportInterface, public sigslot::has_slots<> { : rtcp_mux_enabled_(rtcp_mux_enabled) {} bool rtcp_mux_enabled() const { return rtcp_mux_enabled_; } - void SetRtcpMuxEnabled(bool enable); + void SetRtcpMuxEnabled(bool enable) override; - rtc::PacketTransportInternal* rtp_packet_transport() const { + rtc::PacketTransportInternal* rtp_packet_transport() const override { return rtp_packet_transport_; } - void SetRtpPacketTransport(rtc::PacketTransportInternal* rtp); + void SetRtpPacketTransport(rtc::PacketTransportInternal* rtp) override; - rtc::PacketTransportInternal* rtcp_packet_transport() const { + rtc::PacketTransportInternal* rtcp_packet_transport() const override { return rtcp_packet_transport_; } - void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp); + void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp) override; PacketTransportInterface* GetRtpPacketTransport() const override; PacketTransportInterface* GetRtcpPacketTransport() const override; @@ -54,27 +54,16 @@ class RtpTransport : public RtpTransportInterface, public sigslot::has_slots<> { RTCError SetRtcpParameters(const RtcpParameters& parameters) override; RtcpParameters GetRtcpParameters() const override; - // Called whenever a transport's ready-to-send state changes. The argument - // is true if all used transports are ready to send. This is more specific - // than just "writable"; it means the last send didn't return ENOTCONN. - sigslot::signal1 SignalReadyToSend; - - bool IsWritable(bool rtcp) const; + bool IsWritable(bool rtcp) const override; bool SendPacket(bool rtcp, - const rtc::CopyOnWriteBuffer* packet, + rtc::CopyOnWriteBuffer* packet, const rtc::PacketOptions& options, - int flags); + int flags) override; - bool HandlesPayloadType(int payload_type) const; + bool HandlesPayloadType(int payload_type) const override; - void AddHandledPayloadType(int payload_type); - - // TODO(zstein): Consider having two signals - RtcPacketReceived and - // RtcpPacketReceived. - // The first argument is true for RTCP packets and false for RTP packets. - sigslot::signal3 - SignalPacketReceived; + void AddHandledPayloadType(int payload_type) override; protected: // TODO(zstein): Remove this when we remove RtpTransportAdapter. diff --git a/webrtc/pc/rtptransport_unittest.cc b/webrtc/pc/rtptransport_unittest.cc index 9b9e6cf377..27c77abcb5 100644 --- a/webrtc/pc/rtptransport_unittest.cc +++ b/webrtc/pc/rtptransport_unittest.cc @@ -12,6 +12,7 @@ #include "webrtc/p2p/base/fakepackettransport.h" #include "webrtc/pc/rtptransport.h" +#include "webrtc/pc/rtptransporttestutil.h" #include "webrtc/rtc_base/gunit.h" namespace webrtc { @@ -151,29 +152,6 @@ TEST(RtpTransportTest, ChangingReadyToSendStateOnlySignalsWhenChanged) { EXPECT_EQ(observer.count(), 2); } -class SignalPacketReceivedCounter : public sigslot::has_slots<> { - public: - explicit SignalPacketReceivedCounter(RtpTransport* transport) { - transport->SignalPacketReceived.connect( - this, &SignalPacketReceivedCounter::OnPacketReceived); - } - int rtcp_count() const { return rtcp_count_; } - int rtp_count() const { return rtp_count_; } - - private: - void OnPacketReceived(bool rtcp, - rtc::CopyOnWriteBuffer*, - const rtc::PacketTime&) { - if (rtcp) { - ++rtcp_count_; - } else { - ++rtp_count_; - } - } - int rtcp_count_ = 0; - int rtp_count_ = 0; -}; - // Test that SignalPacketReceived fires with rtcp=true when a RTCP packet is // received. TEST(RtpTransportTest, SignalDemuxedRtcp) { diff --git a/webrtc/pc/rtptransportinternal.h b/webrtc/pc/rtptransportinternal.h new file mode 100644 index 0000000000..fd94d8e8f0 --- /dev/null +++ b/webrtc/pc/rtptransportinternal.h @@ -0,0 +1,69 @@ +/* + * Copyright 2017 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_PC_RTPTRANSPORTINTERNAL_H_ +#define WEBRTC_PC_RTPTRANSPORTINTERNAL_H_ + +#include "webrtc/api/ortc/rtptransportinterface.h" +#include "webrtc/rtc_base/sigslot.h" + +namespace rtc { +class CopyOnWriteBuffer; +struct PacketOptions; +struct PacketTime; +} // namespace rtc + +namespace webrtc { + +// This represents the internal interface beneath RtpTransportInterface; +// it is not accessible to API consumers but is accessible to internal classes +// in order to send and receive RTP and RTCP packets belonging to a single RTP +// session. Additional convenience and configuration methods are also provided. +class RtpTransportInternal : public RtpTransportInterface, + public sigslot::has_slots<> { + public: + virtual void SetRtcpMuxEnabled(bool enable) = 0; + + // TODO(zstein): Remove PacketTransport setters. Clients should pass these + // in to constructors instead and construct a new RtpTransportInternal instead + // of updating them. + + virtual rtc::PacketTransportInternal* rtp_packet_transport() const = 0; + virtual void SetRtpPacketTransport(rtc::PacketTransportInternal* rtp) = 0; + + virtual rtc::PacketTransportInternal* rtcp_packet_transport() const = 0; + virtual void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp) = 0; + + // Called whenever a transport's ready-to-send state changes. The argument + // is true if all used transports are ready to send. This is more specific + // than just "writable"; it means the last send didn't return ENOTCONN. + sigslot::signal1 SignalReadyToSend; + + // TODO(zstein): Consider having two signals - RtpPacketReceived and + // RtcpPacketReceived. + // The first argument is true for RTCP packets and false for RTP packets. + sigslot::signal3 + SignalPacketReceived; + + virtual bool IsWritable(bool rtcp) const = 0; + + virtual bool SendPacket(bool rtcp, + rtc::CopyOnWriteBuffer* packet, + const rtc::PacketOptions& options, + int flags) = 0; + + virtual bool HandlesPayloadType(int payload_type) const = 0; + + virtual void AddHandledPayloadType(int payload_type) = 0; +}; + +} // namespace webrtc + +#endif // WEBRTC_PC_RTPTRANSPORTINTERNAL_H_ diff --git a/webrtc/pc/rtptransporttestutil.h b/webrtc/pc/rtptransporttestutil.h new file mode 100644 index 0000000000..92cfaec703 --- /dev/null +++ b/webrtc/pc/rtptransporttestutil.h @@ -0,0 +1,44 @@ +/* + * Copyright 2017 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_PC_RTPTRANSPORTTESTUTIL_H_ +#define WEBRTC_PC_RTPTRANSPORTTESTUTIL_H_ + +#include "webrtc/pc/rtptransportinternal.h" +#include "webrtc/rtc_base/sigslot.h" + +namespace webrtc { + +class SignalPacketReceivedCounter : public sigslot::has_slots<> { + public: + explicit SignalPacketReceivedCounter(RtpTransportInternal* transport) { + transport->SignalPacketReceived.connect( + this, &SignalPacketReceivedCounter::OnPacketReceived); + } + int rtcp_count() const { return rtcp_count_; } + int rtp_count() const { return rtp_count_; } + + private: + void OnPacketReceived(bool rtcp, + rtc::CopyOnWriteBuffer*, + const rtc::PacketTime&) { + if (rtcp) { + ++rtcp_count_; + } else { + ++rtp_count_; + } + } + int rtcp_count_ = 0; + int rtp_count_ = 0; +}; + +} // namespace webrtc + +#endif // WEBRTC_PC_RTPTRANSPORTTESTUTIL_H_ diff --git a/webrtc/pc/srtptransport.cc b/webrtc/pc/srtptransport.cc new file mode 100644 index 0000000000..6e6ff06274 --- /dev/null +++ b/webrtc/pc/srtptransport.cc @@ -0,0 +1,62 @@ +/* + * Copyright 2017 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/pc/srtptransport.h" + +#include + +#include "webrtc/media/base/rtputils.h" +#include "webrtc/pc/rtptransport.h" +#include "webrtc/pc/srtpsession.h" +#include "webrtc/rtc_base/asyncpacketsocket.h" +#include "webrtc/rtc_base/copyonwritebuffer.h" +#include "webrtc/rtc_base/ptr_util.h" +#include "webrtc/rtc_base/trace_event.h" + +namespace webrtc { + +SrtpTransport::SrtpTransport(bool rtcp_mux_enabled, + const std::string& content_name) + : content_name_(content_name), + rtp_transport_(rtc::MakeUnique(rtcp_mux_enabled)) { + ConnectToRtpTransport(); +} + +SrtpTransport::SrtpTransport(std::unique_ptr transport, + const std::string& content_name) + : content_name_(content_name), rtp_transport_(std::move(transport)) { + ConnectToRtpTransport(); +} + +void SrtpTransport::ConnectToRtpTransport() { + rtp_transport_->SignalPacketReceived.connect( + this, &SrtpTransport::OnPacketReceived); + rtp_transport_->SignalReadyToSend.connect(this, + &SrtpTransport::OnReadyToSend); +} + +bool SrtpTransport::SendPacket(bool rtcp, + rtc::CopyOnWriteBuffer* packet, + const rtc::PacketOptions& options, + int flags) { + // TODO(zstein): Protect packet. + + return rtp_transport_->SendPacket(rtcp, packet, options, flags); +} + +void SrtpTransport::OnPacketReceived(bool rtcp, + rtc::CopyOnWriteBuffer* packet, + const rtc::PacketTime& packet_time) { + // TODO(zstein): Unprotect packet. + + SignalPacketReceived(rtcp, packet, packet_time); +} + +} // namespace webrtc diff --git a/webrtc/pc/srtptransport.h b/webrtc/pc/srtptransport.h new file mode 100644 index 0000000000..be746d50c8 --- /dev/null +++ b/webrtc/pc/srtptransport.h @@ -0,0 +1,108 @@ +/* + * Copyright 2017 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_PC_SRTPTRANSPORT_H_ +#define WEBRTC_PC_SRTPTRANSPORT_H_ + +#include +#include +#include + +#include "webrtc/pc/rtptransportinternal.h" +#include "webrtc/pc/srtpfilter.h" +#include "webrtc/rtc_base/checks.h" + +namespace webrtc { + +// This class will eventually be a wrapper around RtpTransportInternal +// that protects and unprotects sent and received RTP packets. This +// functionality is currently implemented by SrtpFilter and BaseChannel, but +// will be moved here in the future. +class SrtpTransport : public RtpTransportInternal { + public: + SrtpTransport(bool rtcp_mux_enabled, const std::string& content_name); + + // TODO(zstein): Consider taking an RtpTransport instead of an + // RtpTransportInternal. + SrtpTransport(std::unique_ptr transport, + const std::string& content_name); + + void SetRtcpMuxEnabled(bool enable) override { + rtp_transport_->SetRtcpMuxEnabled(enable); + } + + rtc::PacketTransportInternal* rtp_packet_transport() const override { + return rtp_transport_->rtp_packet_transport(); + } + + void SetRtpPacketTransport(rtc::PacketTransportInternal* rtp) override { + rtp_transport_->SetRtpPacketTransport(rtp); + } + + PacketTransportInterface* GetRtpPacketTransport() const override { + return rtp_transport_->GetRtpPacketTransport(); + } + + rtc::PacketTransportInternal* rtcp_packet_transport() const override { + return rtp_transport_->rtcp_packet_transport(); + } + void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp) override { + rtp_transport_->SetRtcpPacketTransport(rtcp); + } + + PacketTransportInterface* GetRtcpPacketTransport() const override { + return rtp_transport_->GetRtcpPacketTransport(); + } + + bool IsWritable(bool rtcp) const override { + return rtp_transport_->IsWritable(rtcp); + } + + bool SendPacket(bool rtcp, + rtc::CopyOnWriteBuffer* packet, + const rtc::PacketOptions& options, + int flags) override; + + bool HandlesPayloadType(int payload_type) const override { + return rtp_transport_->HandlesPayloadType(payload_type); + } + + void AddHandledPayloadType(int payload_type) override { + rtp_transport_->AddHandledPayloadType(payload_type); + } + + RtcpParameters GetRtcpParameters() const override { + return rtp_transport_->GetRtcpParameters(); + } + + RTCError SetRtcpParameters(const RtcpParameters& parameters) override { + return rtp_transport_->SetRtcpParameters(parameters); + } + + // TODO(zstein): Remove this when we remove RtpTransportAdapter. + RtpTransportAdapter* GetInternal() override { return nullptr; } + + private: + void ConnectToRtpTransport(); + + void OnPacketReceived(bool rtcp, + rtc::CopyOnWriteBuffer* packet, + const rtc::PacketTime& packet_time); + + void OnReadyToSend(bool ready) { SignalReadyToSend(ready); } + + const std::string content_name_; + + std::unique_ptr rtp_transport_; +}; + +} // namespace webrtc + +#endif // WEBRTC_PC_SRTPTRANSPORT_H_ diff --git a/webrtc/pc/srtptransport_unittest.cc b/webrtc/pc/srtptransport_unittest.cc new file mode 100644 index 0000000000..e54dac3ea2 --- /dev/null +++ b/webrtc/pc/srtptransport_unittest.cc @@ -0,0 +1,76 @@ +/* + * Copyright 2017 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/pc/srtptransport.h" + +#include "webrtc/pc/rtptransport.h" +#include "webrtc/pc/rtptransporttestutil.h" +#include "webrtc/rtc_base/asyncpacketsocket.h" +#include "webrtc/rtc_base/gunit.h" +#include "webrtc/rtc_base/ptr_util.h" +#include "webrtc/test/gmock.h" + +namespace webrtc { + +using testing::_; +using testing::Return; + +class MockRtpTransport : public RtpTransport { + public: + MockRtpTransport() : RtpTransport(true) {} + + MOCK_METHOD4(SendPacket, + bool(bool rtcp, + rtc::CopyOnWriteBuffer* packet, + const rtc::PacketOptions& options, + int flags)); + + void PretendReceivedPacket() { + bool rtcp = false; + rtc::CopyOnWriteBuffer buffer; + rtc::PacketTime time; + SignalPacketReceived(rtcp, &buffer, time); + } +}; + +TEST(SrtpTransportTest, SendPacket) { + auto rtp_transport = rtc::MakeUnique(); + EXPECT_CALL(*rtp_transport, SendPacket(_, _, _, _)).WillOnce(Return(true)); + + SrtpTransport srtp_transport(std::move(rtp_transport), "a"); + + const bool rtcp = false; + rtc::CopyOnWriteBuffer packet; + rtc::PacketOptions options; + int flags = 0; + EXPECT_TRUE(srtp_transport.SendPacket(rtcp, &packet, options, flags)); + + // TODO(zstein): Also verify that the packet received by RtpTransport has been + // protected once SrtpTransport handles that. +} + +// Test that SrtpTransport fires SignalPacketReceived when the underlying +// RtpTransport fires SignalPacketReceived. +TEST(SrtpTransportTest, SignalPacketReceived) { + auto rtp_transport = rtc::MakeUnique(); + MockRtpTransport* rtp_transport_raw = rtp_transport.get(); + SrtpTransport srtp_transport(std::move(rtp_transport), "a"); + + SignalPacketReceivedCounter counter(&srtp_transport); + + rtp_transport_raw->PretendReceivedPacket(); + + EXPECT_EQ(1, counter.rtp_count()); + + // TODO(zstein): Also verify that the packet is unprotected once SrtpTransport + // handles that. +} + +} // namespace webrtc