Move ready to send logic from BaseChannel to RtpTransport.
BUG=webrtc:7013
Review-Url: https://codereview.webrtc.org/2812243005
Cr-Commit-Position: refs/heads/master@{#17853}
diff --git a/webrtc/pc/BUILD.gn b/webrtc/pc/BUILD.gn
index fe9348b..ff99c19 100644
--- a/webrtc/pc/BUILD.gn
+++ b/webrtc/pc/BUILD.gn
@@ -190,6 +190,7 @@
"currentspeakermonitor_unittest.cc",
"mediasession_unittest.cc",
"rtcpmuxfilter_unittest.cc",
+ "rtptransport_unittest.cc",
"srtpfilter_unittest.cc",
]
diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc
index 59fca4a..f5428a4 100644
--- a/webrtc/pc/channel.cc
+++ b/webrtc/pc/channel.cc
@@ -168,6 +168,7 @@
network_thread_(network_thread),
signaling_thread_(signaling_thread),
content_name_(content_name),
+ rtcp_mux_required_(rtcp_mux_required),
rtp_transport_(rtcp_mux_required),
srtp_required_(srtp_required),
media_channel_(media_channel),
@@ -176,6 +177,8 @@
#if defined(ENABLE_EXTERNAL_AUTH)
srtp_filter_.EnableExternalAuth();
#endif
+ rtp_transport_.SignalReadyToSend.connect(
+ this, &BaseChannel::OnTransportReadyToSend);
LOG(LS_INFO) << "Created channel for " << content_name;
}
@@ -242,7 +245,7 @@
SetTransports_n(rtp_dtls_transport, rtcp_dtls_transport, rtp_packet_transport,
rtcp_packet_transport);
- if (rtp_transport_.rtcp_mux_required()) {
+ if (rtcp_mux_required_) {
rtcp_mux_filter_.SetActive();
}
return true;
@@ -335,19 +338,6 @@
// Update aggregate writable/ready-to-send state between RTP and RTCP upon
// setting new transport channels.
UpdateWritableState_n();
- // We can only update ready-to-send after updating writability.
- //
- // On setting a new channel, assume it's ready to send if it's writable,
- // because we have no way of knowing otherwise (the channel doesn't give us
- // "was last send successful?").
- //
- // This won't always be accurate (the last SendPacket call from another
- // BaseChannel could have resulted in an error), but even so, we'll just
- // encounter the error again and update "ready to send" accordingly.
- SetTransportChannelReadyToSend(
- false, rtp_packet_transport && rtp_packet_transport->writable());
- SetTransportChannelReadyToSend(
- true, rtcp_packet_transport && rtcp_packet_transport->writable());
}
void BaseChannel::SetTransport_n(
@@ -374,9 +364,9 @@
}
if (rtcp) {
- rtp_transport_.set_rtcp_packet_transport(new_packet_transport);
+ rtp_transport_.SetRtcpPacketTransport(new_packet_transport);
} else {
- rtp_transport_.set_rtp_packet_transport(new_packet_transport);
+ rtp_transport_.SetRtpPacketTransport(new_packet_transport);
}
old_dtls_transport = new_dtls_transport;
@@ -390,6 +380,7 @@
<< "Setting RTCP for DTLS/SRTP after SrtpFilter is active "
<< "should never happen.";
}
+
if (new_dtls_transport) {
ConnectToDtlsTransport(new_dtls_transport);
} else {
@@ -404,9 +395,9 @@
void BaseChannel::ConnectToDtlsTransport(DtlsTransportInternal* transport) {
RTC_DCHECK(network_thread_->IsCurrent());
+ // TODO(zstein): de-dup with ConnectToPacketTransport
transport->SignalWritableState.connect(this, &BaseChannel::OnWritableState);
transport->SignalReadPacket.connect(this, &BaseChannel::OnPacketRead);
- transport->SignalReadyToSend.connect(this, &BaseChannel::OnReadyToSend);
transport->SignalDtlsState.connect(this, &BaseChannel::OnDtlsState);
transport->SignalSentPacket.connect(this, &BaseChannel::SignalSentPacket_n);
transport->ice_transport()->SignalSelectedCandidatePairChanged.connect(
@@ -421,7 +412,6 @@
transport->SignalWritableState.disconnect(this);
transport->SignalReadPacket.disconnect(this);
- transport->SignalReadyToSend.disconnect(this);
transport->SignalDtlsState.disconnect(this);
transport->SignalSentPacket.disconnect(this);
transport->ice_transport()->SignalSelectedCandidatePairChanged.disconnect(
@@ -433,7 +423,6 @@
RTC_DCHECK_RUN_ON(network_thread_);
transport->SignalWritableState.connect(this, &BaseChannel::OnWritableState);
transport->SignalReadPacket.connect(this, &BaseChannel::OnPacketRead);
- transport->SignalReadyToSend.connect(this, &BaseChannel::OnReadyToSend);
transport->SignalSentPacket.connect(this, &BaseChannel::SignalSentPacket_n);
}
@@ -442,7 +431,6 @@
RTC_DCHECK_RUN_ON(network_thread_);
transport->SignalWritableState.disconnect(this);
transport->SignalReadPacket.disconnect(this);
- transport->SignalReadyToSend.disconnect(this);
transport->SignalSentPacket.disconnect(this);
}
@@ -522,8 +510,7 @@
bool BaseChannel::NeedsRtcpTransport() {
// If this BaseChannel doesn't require RTCP mux and we haven't fully
// negotiated RTCP mux, we need an RTCP transport.
- return !rtp_transport_.rtcp_mux_required() &&
- !rtcp_mux_filter_.IsFullyActive();
+ return !rtcp_mux_required_ && !rtcp_mux_filter_.IsFullyActive();
}
bool BaseChannel::IsReadyToReceiveMedia_w() const {
@@ -605,13 +592,6 @@
HandlePacket(rtcp, &packet, packet_time);
}
-void BaseChannel::OnReadyToSend(rtc::PacketTransportInternal* transport) {
- RTC_DCHECK(transport == rtp_transport_.rtp_packet_transport() ||
- transport == rtp_transport_.rtcp_packet_transport());
- SetTransportChannelReadyToSend(
- transport == rtp_transport_.rtcp_packet_transport(), true);
-}
-
void BaseChannel::OnDtlsState(DtlsTransportInternal* transport,
DtlsTransportState state) {
if (!ShouldSetupDtlsSrtp_n()) {
@@ -655,22 +635,10 @@
network_route));
}
-void BaseChannel::SetTransportChannelReadyToSend(bool rtcp, bool ready) {
- RTC_DCHECK(network_thread_->IsCurrent());
- if (rtcp) {
- rtcp_ready_to_send_ = ready;
- } else {
- rtp_ready_to_send_ = ready;
- }
-
- bool ready_to_send =
- (rtp_ready_to_send_ &&
- // In the case of rtcp mux |rtcp_packet_transport_| will be null.
- (rtcp_ready_to_send_ || !rtp_transport_.rtcp_packet_transport()));
-
+void BaseChannel::OnTransportReadyToSend(bool ready) {
invoker_.AsyncInvoke<void>(
RTC_FROM_HERE, worker_thread_,
- Bind(&MediaChannel::OnReadyToSend, media_channel_, ready_to_send));
+ Bind(&MediaChannel::OnReadyToSend, media_channel_, ready));
}
bool BaseChannel::PacketIsRtcp(const rtc::PacketTransportInternal* transport,
@@ -705,11 +673,7 @@
// packet before doing anything. (We might get RTCP packets that we don't
// intend to send.) If we've negotiated RTCP mux, send RTCP over the RTP
// transport.
- rtc::PacketTransportInternal* transport =
- (!rtcp || rtcp_mux_filter_.IsActive())
- ? rtp_transport_.rtp_packet_transport()
- : rtp_transport_.rtcp_packet_transport();
- if (!transport || !transport->writable()) {
+ if (!rtp_transport_.IsWritable(rtcp)) {
return false;
}
@@ -805,16 +769,7 @@
// Bon voyage.
int flags = (secure() && secure_dtls()) ? PF_SRTP_BYPASS : PF_NORMAL;
- int ret = transport->SendPacket(packet->data<char>(), packet->size(),
- updated_options, flags);
- if (ret != static_cast<int>(packet->size())) {
- if (transport->GetError() == ENOTCONN) {
- LOG(LS_WARNING) << "Got ENOTCONN from transport.";
- SetTransportChannelReadyToSend(rtcp, false);
- }
- return false;
- }
- return true;
+ return rtp_transport_.SendPacket(rtcp, packet, updated_options, flags);
}
bool BaseChannel::WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet) {
@@ -1233,7 +1188,7 @@
std::string* error_desc) {
// Provide a more specific error message for the RTCP mux "require" policy
// case.
- if (rtp_transport_.rtcp_mux_required() && !enable) {
+ if (rtcp_mux_required_ && !enable) {
SafeSetError(
"rtcpMuxPolicy is 'require', but media description does not "
"contain 'a=rtcp-mux'.",
@@ -1267,7 +1222,6 @@
SignalRtcpMuxFullyActive(transport_name_);
}
UpdateWritableState_n();
- SetTransportChannelReadyToSend(true, false);
}
break;
case CA_UPDATE:
@@ -1281,6 +1235,7 @@
SafeSetError("Failed to setup RTCP mux filter.", error_desc);
return false;
}
+ rtp_transport_.SetRtcpMuxEnabled(rtcp_mux_filter_.IsActive());
// |rtcp_mux_filter_| can be active if |action| is CA_PRANSWER or
// CA_ANSWER, but we only want to tear down the RTCP transport if we received
// a final answer.
diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h
index 56d51f6..48259e5 100644
--- a/webrtc/pc/channel.h
+++ b/webrtc/pc/channel.h
@@ -183,16 +183,8 @@
bool NeedsRtcpTransport();
- // Made public for easier testing.
- //
- // Updates "ready to send" for an individual channel, and informs the media
- // channel that the transport is ready to send if each channel (in use) is
- // ready to send. This is more specific than just "writable"; it means the
- // last send didn't return ENOTCONN.
- //
- // This should be called whenever a channel's ready-to-send state changes,
- // or when RTCP muxing becomes active/inactive.
- void SetTransportChannelReadyToSend(bool rtcp, bool ready);
+ // From RtpTransport - public for testing only
+ void OnTransportReadyToSend(bool ready);
// Only public for unit tests. Otherwise, consider protected.
int SetOption(SocketType type, rtc::Socket::Option o, int val)
@@ -261,7 +253,6 @@
size_t len,
const rtc::PacketTime& packet_time,
int flags);
- void OnReadyToSend(rtc::PacketTransportInternal* transport);
void OnDtlsState(DtlsTransportInternal* transport, DtlsTransportState state);
@@ -391,6 +382,8 @@
// Won't be set when using raw packet transports. SDP-specific thing.
std::string transport_name_;
+ const bool rtcp_mux_required_;
+
// Separate DTLS/non-DTLS pointers to support using BaseChannel without DTLS.
// Temporary measure until more refactoring is done.
// If non-null, "X_dtls_transport_" will always equal "X_packet_transport_".
@@ -402,8 +395,6 @@
SrtpFilter srtp_filter_;
RtcpMuxFilter rtcp_mux_filter_;
BundleFilter bundle_filter_;
- bool rtp_ready_to_send_ = false;
- bool rtcp_ready_to_send_ = false;
bool writable_ = false;
bool was_ever_writable_ = false;
bool has_received_packet_ = false;
diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc
index baacac8..6c4aa0f 100644
--- a/webrtc/pc/channel_unittest.cc
+++ b/webrtc/pc/channel_unittest.cc
@@ -1844,52 +1844,20 @@
EXPECT_TRUE(Terminate());
}
- void TestOnReadyToSend() {
+ void TestOnTransportReadyToSend() {
CreateChannels(0, 0);
- cricket::FakeDtlsTransport* rtp = fake_rtp_dtls_transport1_.get();
- cricket::FakeDtlsTransport* rtcp = fake_rtcp_dtls_transport1_.get();
EXPECT_FALSE(media_channel1_->ready_to_send());
- network_thread_->Invoke<void>(RTC_FROM_HERE,
- [rtp] { rtp->SignalReadyToSend(rtp); });
- WaitForThreads();
- EXPECT_FALSE(media_channel1_->ready_to_send());
-
- network_thread_->Invoke<void>(RTC_FROM_HERE,
- [rtcp] { rtcp->SignalReadyToSend(rtcp); });
- WaitForThreads();
- // MediaChannel::OnReadyToSend only be called when both rtp and rtcp
- // channel are ready to send.
- EXPECT_TRUE(media_channel1_->ready_to_send());
-
- // rtp channel becomes not ready to send will be propagated to mediachannel
- network_thread_->Invoke<void>(RTC_FROM_HERE, [this] {
- channel1_->SetTransportChannelReadyToSend(false, false);
- });
- WaitForThreads();
- EXPECT_FALSE(media_channel1_->ready_to_send());
-
- network_thread_->Invoke<void>(RTC_FROM_HERE, [this] {
- channel1_->SetTransportChannelReadyToSend(false, true);
- });
+ channel1_->OnTransportReadyToSend(true);
WaitForThreads();
EXPECT_TRUE(media_channel1_->ready_to_send());
- // rtcp channel becomes not ready to send will be propagated to mediachannel
- network_thread_->Invoke<void>(RTC_FROM_HERE, [this] {
- channel1_->SetTransportChannelReadyToSend(true, false);
- });
+ channel1_->OnTransportReadyToSend(false);
WaitForThreads();
EXPECT_FALSE(media_channel1_->ready_to_send());
-
- network_thread_->Invoke<void>(RTC_FROM_HERE, [this] {
- channel1_->SetTransportChannelReadyToSend(true, true);
- });
- WaitForThreads();
- EXPECT_TRUE(media_channel1_->ready_to_send());
}
- void TestOnReadyToSendWithRtcpMux() {
+ void TestOnTransportReadyToSendWithRtcpMux() {
CreateChannels(0, 0);
typename T::Content content;
CreateContent(0, kPcmuCodec, kH264Codec, &content);
@@ -1908,9 +1876,10 @@
WaitForThreads();
EXPECT_TRUE(media_channel1_->ready_to_send());
- network_thread_->Invoke<void>(RTC_FROM_HERE, [this] {
- channel1_->SetTransportChannelReadyToSend(false, false);
- });
+ // TODO(zstein): Find a way to test this without making
+ // OnTransportReadyToSend public.
+ network_thread_->Invoke<void>(
+ RTC_FROM_HERE, [this] { channel1_->OnTransportReadyToSend(false); });
WaitForThreads();
EXPECT_FALSE(media_channel1_->ready_to_send());
}
@@ -2390,12 +2359,12 @@
Base::TestSrtpError(kAudioPts[0]);
}
-TEST_F(VoiceChannelSingleThreadTest, TestOnReadyToSend) {
- Base::TestOnReadyToSend();
+TEST_F(VoiceChannelSingleThreadTest, TestOnTransportReadyToSend) {
+ Base::TestOnTransportReadyToSend();
}
-TEST_F(VoiceChannelSingleThreadTest, TestOnReadyToSendWithRtcpMux) {
- Base::TestOnReadyToSendWithRtcpMux();
+TEST_F(VoiceChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
+ Base::TestOnTransportReadyToSendWithRtcpMux();
}
// Test that we can scale the output volume properly for 1:1 calls.
@@ -2711,12 +2680,12 @@
Base::TestSrtpError(kAudioPts[0]);
}
-TEST_F(VoiceChannelDoubleThreadTest, TestOnReadyToSend) {
- Base::TestOnReadyToSend();
+TEST_F(VoiceChannelDoubleThreadTest, TestOnTransportReadyToSend) {
+ Base::TestOnTransportReadyToSend();
}
-TEST_F(VoiceChannelDoubleThreadTest, TestOnReadyToSendWithRtcpMux) {
- Base::TestOnReadyToSendWithRtcpMux();
+TEST_F(VoiceChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
+ Base::TestOnTransportReadyToSendWithRtcpMux();
}
// Test that we can scale the output volume properly for 1:1 calls.
@@ -3024,12 +2993,12 @@
Base::TestSrtpError(kVideoPts[0]);
}
-TEST_F(VideoChannelSingleThreadTest, TestOnReadyToSend) {
- Base::TestOnReadyToSend();
+TEST_F(VideoChannelSingleThreadTest, TestOnTransportReadyToSend) {
+ Base::TestOnTransportReadyToSend();
}
-TEST_F(VideoChannelSingleThreadTest, TestOnReadyToSendWithRtcpMux) {
- Base::TestOnReadyToSendWithRtcpMux();
+TEST_F(VideoChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
+ Base::TestOnTransportReadyToSendWithRtcpMux();
}
TEST_F(VideoChannelSingleThreadTest, DefaultMaxBitrateIsUnlimited) {
@@ -3259,12 +3228,12 @@
Base::TestSrtpError(kVideoPts[0]);
}
-TEST_F(VideoChannelDoubleThreadTest, TestOnReadyToSend) {
- Base::TestOnReadyToSend();
+TEST_F(VideoChannelDoubleThreadTest, TestOnTransportReadyToSend) {
+ Base::TestOnTransportReadyToSend();
}
-TEST_F(VideoChannelDoubleThreadTest, TestOnReadyToSendWithRtcpMux) {
- Base::TestOnReadyToSendWithRtcpMux();
+TEST_F(VideoChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
+ Base::TestOnTransportReadyToSendWithRtcpMux();
}
TEST_F(VideoChannelDoubleThreadTest, DefaultMaxBitrateIsUnlimited) {
@@ -3411,12 +3380,12 @@
Base::TestCallTeardownRtcpMux();
}
-TEST_F(RtpDataChannelSingleThreadTest, TestOnReadyToSend) {
- Base::TestOnReadyToSend();
+TEST_F(RtpDataChannelSingleThreadTest, TestOnTransportReadyToSend) {
+ Base::TestOnTransportReadyToSend();
}
-TEST_F(RtpDataChannelSingleThreadTest, TestOnReadyToSendWithRtcpMux) {
- Base::TestOnReadyToSendWithRtcpMux();
+TEST_F(RtpDataChannelSingleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
+ Base::TestOnTransportReadyToSendWithRtcpMux();
}
TEST_F(RtpDataChannelSingleThreadTest, SendRtpToRtp) {
@@ -3543,12 +3512,12 @@
Base::TestCallTeardownRtcpMux();
}
-TEST_F(RtpDataChannelDoubleThreadTest, TestOnReadyToSend) {
- Base::TestOnReadyToSend();
+TEST_F(RtpDataChannelDoubleThreadTest, TestOnTransportReadyToSend) {
+ Base::TestOnTransportReadyToSend();
}
-TEST_F(RtpDataChannelDoubleThreadTest, TestOnReadyToSendWithRtcpMux) {
- Base::TestOnReadyToSendWithRtcpMux();
+TEST_F(RtpDataChannelDoubleThreadTest, TestOnTransportReadyToSendWithRtcpMux) {
+ Base::TestOnTransportReadyToSendWithRtcpMux();
}
TEST_F(RtpDataChannelDoubleThreadTest, SendRtpToRtp) {
diff --git a/webrtc/pc/rtptransport.cc b/webrtc/pc/rtptransport.cc
index 76bc639..2ee27e0 100644
--- a/webrtc/pc/rtptransport.cc
+++ b/webrtc/pc/rtptransport.cc
@@ -11,18 +11,80 @@
#include "webrtc/pc/rtptransport.h"
#include "webrtc/base/checks.h"
+#include "webrtc/base/copyonwritebuffer.h"
#include "webrtc/p2p/base/packettransportinterface.h"
namespace webrtc {
-void RtpTransport::set_rtp_packet_transport(rtc::PacketTransportInternal* rtp) {
- rtp_packet_transport_ = rtp;
+void RtpTransport::SetRtcpMuxEnabled(bool enable) {
+ rtcp_mux_enabled_ = enable;
+ MaybeSignalReadyToSend();
}
-void RtpTransport::set_rtcp_packet_transport(
- rtc::PacketTransportInternal* rtcp) {
- RTC_DCHECK(!rtcp_mux_required_);
- rtcp_packet_transport_ = rtcp;
+void RtpTransport::SetRtpPacketTransport(
+ rtc::PacketTransportInternal* new_packet_transport) {
+ if (new_packet_transport == rtp_packet_transport_) {
+ return;
+ }
+ if (rtp_packet_transport_) {
+ rtp_packet_transport_->SignalReadyToSend.disconnect(this);
+ }
+ if (new_packet_transport) {
+ new_packet_transport->SignalReadyToSend.connect(
+ this, &RtpTransport::OnReadyToSend);
+ }
+ rtp_packet_transport_ = new_packet_transport;
+
+ // Assumes the transport is ready to send if it is writable. If we are wrong,
+ // ready to send will be updated the next time we try to send.
+ SetReadyToSend(false,
+ rtp_packet_transport_ && rtp_packet_transport_->writable());
+}
+
+void RtpTransport::SetRtcpPacketTransport(
+ rtc::PacketTransportInternal* new_packet_transport) {
+ if (new_packet_transport == rtcp_packet_transport_) {
+ return;
+ }
+ if (rtcp_packet_transport_) {
+ rtcp_packet_transport_->SignalReadyToSend.disconnect(this);
+ }
+ if (new_packet_transport) {
+ new_packet_transport->SignalReadyToSend.connect(
+ this, &RtpTransport::OnReadyToSend);
+ }
+ rtcp_packet_transport_ = new_packet_transport;
+
+ // Assumes the transport is ready to send if it is writable. If we are wrong,
+ // ready to send will be updated the next time we try to send.
+ SetReadyToSend(true,
+ rtcp_packet_transport_ && rtcp_packet_transport_->writable());
+}
+
+bool RtpTransport::IsWritable(bool rtcp) const {
+ rtc::PacketTransportInternal* transport = rtcp && !rtcp_mux_enabled_
+ ? rtcp_packet_transport_
+ : rtp_packet_transport_;
+ return transport && transport->writable();
+}
+
+bool RtpTransport::SendPacket(bool rtcp,
+ const rtc::CopyOnWriteBuffer* packet,
+ const rtc::PacketOptions& options,
+ int flags) {
+ rtc::PacketTransportInternal* transport = rtcp && !rtcp_mux_enabled_
+ ? rtcp_packet_transport_
+ : rtp_packet_transport_;
+ int ret = transport->SendPacket(packet->data<char>(), packet->size(), options,
+ flags);
+ if (ret != static_cast<int>(packet->size())) {
+ if (transport->GetError() == ENOTCONN) {
+ LOG(LS_WARNING) << "Got ENOTCONN from transport.";
+ SetReadyToSend(rtcp, false);
+ }
+ return false;
+ }
+ return true;
}
PacketTransportInterface* RtpTransport::GetRtpPacketTransport() const {
@@ -57,4 +119,27 @@
return nullptr;
}
+void RtpTransport::OnReadyToSend(rtc::PacketTransportInternal* transport) {
+ SetReadyToSend(transport == rtcp_packet_transport_, true);
+}
+
+void RtpTransport::SetReadyToSend(bool rtcp, bool ready) {
+ if (rtcp) {
+ rtcp_ready_to_send_ = ready;
+ } else {
+ rtp_ready_to_send_ = ready;
+ }
+
+ MaybeSignalReadyToSend();
+}
+
+void RtpTransport::MaybeSignalReadyToSend() {
+ bool ready_to_send =
+ rtp_ready_to_send_ && (rtcp_ready_to_send_ || rtcp_mux_enabled_);
+ if (ready_to_send != ready_to_send_) {
+ ready_to_send_ = ready_to_send;
+ SignalReadyToSend(ready_to_send);
+ }
+}
+
} // namespace webrtc
diff --git a/webrtc/pc/rtptransport.h b/webrtc/pc/rtptransport.h
index f5ffe3f..f9bee1b 100644
--- a/webrtc/pc/rtptransport.h
+++ b/webrtc/pc/rtptransport.h
@@ -12,34 +12,38 @@
#define WEBRTC_PC_RTPTRANSPORT_H_
#include "webrtc/api/ortc/rtptransportinterface.h"
+#include "webrtc/base/sigslot.h"
namespace rtc {
+class CopyOnWriteBuffer;
+struct PacketOptions;
class PacketTransportInternal;
} // namespace rtc
namespace webrtc {
-class RtpTransport : public RtpTransportInterface {
+class RtpTransport : public RtpTransportInterface, public sigslot::has_slots<> {
public:
RtpTransport(const RtpTransport&) = delete;
RtpTransport& operator=(const RtpTransport&) = delete;
- explicit RtpTransport(bool rtcp_mux_required)
- : rtcp_mux_required_(rtcp_mux_required) {}
+ explicit RtpTransport(bool rtcp_mux_enabled)
+ : rtcp_mux_enabled_(rtcp_mux_enabled) {}
- bool rtcp_mux_required() const { return rtcp_mux_required_; }
+ bool rtcp_mux_enabled() const { return rtcp_mux_enabled_; }
+ void SetRtcpMuxEnabled(bool enable);
rtc::PacketTransportInternal* rtp_packet_transport() const {
return rtp_packet_transport_;
}
- void set_rtp_packet_transport(rtc::PacketTransportInternal* rtp);
+ void SetRtpPacketTransport(rtc::PacketTransportInternal* rtp);
rtc::PacketTransportInternal* rtcp_packet_transport() const {
return rtcp_packet_transport_;
}
- void set_rtcp_packet_transport(rtc::PacketTransportInternal* rtcp);
+ void SetRtcpPacketTransport(rtc::PacketTransportInternal* rtcp);
PacketTransportInterface* GetRtpPacketTransport() const override;
PacketTransportInterface* GetRtcpPacketTransport() const override;
@@ -48,18 +52,40 @@
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<bool> SignalReadyToSend;
+
+ bool IsWritable(bool rtcp) const;
+
+ bool SendPacket(bool rtcp,
+ const rtc::CopyOnWriteBuffer* packet,
+ const rtc::PacketOptions& options,
+ int flags);
+
protected:
// TODO(zstein): Remove this when we remove RtpTransportAdapter.
RtpTransportAdapter* GetInternal() override;
private:
- // True if RTCP-multiplexing is required. rtcp_packet_transport_ should
- // always be null in this case.
- const bool rtcp_mux_required_;
+ void OnReadyToSend(rtc::PacketTransportInternal* transport);
+
+ // Updates "ready to send" for an individual channel and fires
+ // SignalReadyToSend.
+ void SetReadyToSend(bool rtcp, bool ready);
+
+ void MaybeSignalReadyToSend();
+
+ bool rtcp_mux_enabled_;
rtc::PacketTransportInternal* rtp_packet_transport_ = nullptr;
rtc::PacketTransportInternal* rtcp_packet_transport_ = nullptr;
+ bool ready_to_send_ = false;
+ bool rtp_ready_to_send_ = false;
+ bool rtcp_ready_to_send_ = false;
+
RtcpParameters rtcp_parameters_;
};
diff --git a/webrtc/pc/rtptransport_unittest.cc b/webrtc/pc/rtptransport_unittest.cc
new file mode 100644
index 0000000..ba49251
--- /dev/null
+++ b/webrtc/pc/rtptransport_unittest.cc
@@ -0,0 +1,150 @@
+/*
+ * 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 <string>
+
+#include "webrtc/base/gunit.h"
+#include "webrtc/p2p/base/fakepackettransport.h"
+#include "webrtc/pc/rtptransport.h"
+
+namespace webrtc {
+
+class RtpTransportTest : public testing::Test {};
+
+constexpr bool kMuxDisabled = false;
+constexpr bool kMuxEnabled = true;
+
+TEST_F(RtpTransportTest, SetRtcpParametersCantDisableRtcpMux) {
+ RtpTransport transport(kMuxDisabled);
+ RtcpParameters params;
+ transport.SetRtcpParameters(params);
+ params.mux = false;
+ EXPECT_FALSE(transport.SetRtcpParameters(params).ok());
+}
+
+TEST_F(RtpTransportTest, SetRtcpParametersEmptyCnameUsesExisting) {
+ static const char kName[] = "name";
+ RtpTransport transport(kMuxDisabled);
+ RtcpParameters params_with_name;
+ params_with_name.cname = kName;
+ transport.SetRtcpParameters(params_with_name);
+ EXPECT_EQ(transport.GetRtcpParameters().cname, kName);
+
+ RtcpParameters params_without_name;
+ transport.SetRtcpParameters(params_without_name);
+ EXPECT_EQ(transport.GetRtcpParameters().cname, kName);
+}
+
+class SignalObserver : public sigslot::has_slots<> {
+ public:
+ explicit SignalObserver(RtpTransport* transport) {
+ transport->SignalReadyToSend.connect(this, &SignalObserver::OnReadyToSend);
+ }
+ void OnReadyToSend(bool ready) { ready_ = ready; }
+ bool ready_ = false;
+};
+
+TEST_F(RtpTransportTest, SettingRtcpAndRtpSignalsReady) {
+ RtpTransport transport(kMuxDisabled);
+ SignalObserver observer(&transport);
+ rtc::FakePacketTransport fake_rtcp("fake_rtcp");
+ fake_rtcp.SetWritable(true);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetWritable(true);
+
+ transport.SetRtcpPacketTransport(&fake_rtcp); // rtcp ready
+ EXPECT_FALSE(observer.ready_);
+ transport.SetRtpPacketTransport(&fake_rtp); // rtp ready
+ EXPECT_TRUE(observer.ready_);
+}
+
+TEST_F(RtpTransportTest, SettingRtpAndRtcpSignalsReady) {
+ RtpTransport transport(kMuxDisabled);
+ SignalObserver observer(&transport);
+ rtc::FakePacketTransport fake_rtcp("fake_rtcp");
+ fake_rtcp.SetWritable(true);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetWritable(true);
+
+ transport.SetRtpPacketTransport(&fake_rtp); // rtp ready
+ EXPECT_FALSE(observer.ready_);
+ transport.SetRtcpPacketTransport(&fake_rtcp); // rtcp ready
+ EXPECT_TRUE(observer.ready_);
+}
+
+TEST_F(RtpTransportTest, SettingRtpWithRtcpMuxEnabledSignalsReady) {
+ RtpTransport transport(kMuxEnabled);
+ SignalObserver observer(&transport);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetWritable(true);
+
+ transport.SetRtpPacketTransport(&fake_rtp); // rtp ready
+ EXPECT_TRUE(observer.ready_);
+}
+
+TEST_F(RtpTransportTest, DisablingRtcpMuxSignalsNotReady) {
+ RtpTransport transport(kMuxEnabled);
+ SignalObserver observer(&transport);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetWritable(true);
+
+ transport.SetRtpPacketTransport(&fake_rtp); // rtp ready
+ EXPECT_TRUE(observer.ready_);
+
+ transport.SetRtcpMuxEnabled(false);
+ EXPECT_FALSE(observer.ready_);
+}
+
+TEST_F(RtpTransportTest, EnablingRtcpMuxSignalsReady) {
+ RtpTransport transport(kMuxDisabled);
+ SignalObserver observer(&transport);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetWritable(true);
+
+ transport.SetRtpPacketTransport(&fake_rtp); // rtp ready
+ EXPECT_FALSE(observer.ready_);
+
+ transport.SetRtcpMuxEnabled(true);
+ EXPECT_TRUE(observer.ready_);
+}
+
+class SignalCounter : public sigslot::has_slots<> {
+ public:
+ explicit SignalCounter(RtpTransport* transport) {
+ transport->SignalReadyToSend.connect(this, &SignalCounter::OnReadyToSend);
+ }
+ void OnReadyToSend(bool ready) { ++count_; }
+ int count_ = 0;
+};
+
+TEST_F(RtpTransportTest, ChangingReadyToSendStateOnlySignalsWhenChanged) {
+ RtpTransport transport(kMuxEnabled);
+ SignalCounter observer(&transport);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetWritable(true);
+
+ // State changes, so we should signal.
+ transport.SetRtpPacketTransport(&fake_rtp);
+ EXPECT_EQ(observer.count_, 1);
+
+ // State does not change, so we should not signal.
+ transport.SetRtpPacketTransport(&fake_rtp);
+ EXPECT_EQ(observer.count_, 1);
+
+ // State does not change, so we should not signal.
+ transport.SetRtcpMuxEnabled(true);
+ EXPECT_EQ(observer.count_, 1);
+
+ // State changes, so we should signal.
+ transport.SetRtcpMuxEnabled(false);
+ EXPECT_EQ(observer.count_, 2);
+}
+
+} // namespace webrtc