Move RTP/RTCP demuxing logic from BaseChannel to RtpTransport.
BUG=webrtc:7013
Review-Url: https://codereview.webrtc.org/2890263003
Cr-Commit-Position: refs/heads/master@{#18391}
diff --git a/webrtc/media/base/rtputils.cc b/webrtc/media/base/rtputils.cc
index ada2b59..1f81d62 100644
--- a/webrtc/media/base/rtputils.cc
+++ b/webrtc/media/base/rtputils.cc
@@ -279,6 +279,15 @@
return payload_type >= 0 && payload_type <= 127;
}
+bool IsValidRtpRtcpPacketSize(bool rtcp, size_t size) {
+ return (rtcp ? size >= kMinRtcpPacketLen : size >= kMinRtpPacketLen) &&
+ size <= kMaxRtpPacketLen;
+}
+
+const char* RtpRtcpStringLiteral(bool rtcp) {
+ return rtcp ? "RTCP" : "RTP";
+}
+
bool ValidateRtpHeader(const uint8_t* rtp,
size_t length,
size_t* header_length) {
diff --git a/webrtc/media/base/rtputils.h b/webrtc/media/base/rtputils.h
index 1a71057..f7aa85c 100644
--- a/webrtc/media/base/rtputils.h
+++ b/webrtc/media/base/rtputils.h
@@ -58,6 +58,14 @@
// True if |payload type| is 0-127.
bool IsValidRtpPayloadType(int payload_type);
+// True if |size| is appropriate for the indicated packet type.
+bool IsValidRtpRtcpPacketSize(bool rtcp, size_t size);
+
+// TODO(zstein): Consider using an enum instead of a bool to differentiate
+// between RTP and RTCP.
+// Returns "RTCP" or "RTP" according to |rtcp|.
+const char* RtpRtcpStringLiteral(bool rtcp);
+
// Verifies that a packet has a valid RTP header.
bool ValidateRtpHeader(const uint8_t* rtp,
size_t length,
diff --git a/webrtc/pc/channel.cc b/webrtc/pc/channel.cc
index f5428a4..a08d7ae 100644
--- a/webrtc/pc/channel.cc
+++ b/webrtc/pc/channel.cc
@@ -105,15 +105,9 @@
DataMediaChannel::Error error;
};
-static const char* PacketType(bool rtcp) {
- return (!rtcp) ? "RTP" : "RTCP";
-}
-
static bool ValidPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet) {
// Check the packet size. We could check the header too if needed.
- return (packet &&
- packet->size() >= (!rtcp ? kMinRtpPacketLen : kMinRtcpPacketLen) &&
- packet->size() <= kMaxRtpPacketLen);
+ return packet && IsValidRtpRtcpPacketSize(rtcp, packet->size());
}
static bool IsReceiveContentDirection(MediaContentDirection direction) {
@@ -179,6 +173,11 @@
#endif
rtp_transport_.SignalReadyToSend.connect(
this, &BaseChannel::OnTransportReadyToSend);
+ // TODO(zstein): RtpTransport::SignalPacketReceived will probably be replaced
+ // with a callback interface later so that the demuxer can select which
+ // channel to signal.
+ rtp_transport_.SignalPacketReceived.connect(this,
+ &BaseChannel::OnPacketReceived);
LOG(LS_INFO) << "Created channel for " << content_name;
}
@@ -214,6 +213,9 @@
DisconnectFromPacketTransport(rtp_transport_.rtcp_packet_transport());
}
+ rtp_transport_.SetRtpPacketTransport(nullptr);
+ rtp_transport_.SetRtcpPacketTransport(nullptr);
+
// Clear pending read packets/messages.
network_thread_->Clear(&invoker_);
network_thread_->Clear(this);
@@ -397,7 +399,6 @@
// TODO(zstein): de-dup with ConnectToPacketTransport
transport->SignalWritableState.connect(this, &BaseChannel::OnWritableState);
- transport->SignalReadPacket.connect(this, &BaseChannel::OnPacketRead);
transport->SignalDtlsState.connect(this, &BaseChannel::OnDtlsState);
transport->SignalSentPacket.connect(this, &BaseChannel::SignalSentPacket_n);
transport->ice_transport()->SignalSelectedCandidatePairChanged.connect(
@@ -411,7 +412,6 @@
false);
transport->SignalWritableState.disconnect(this);
- transport->SignalReadPacket.disconnect(this);
transport->SignalDtlsState.disconnect(this);
transport->SignalSentPacket.disconnect(this);
transport->ice_transport()->SignalSelectedCandidatePairChanged.disconnect(
@@ -422,7 +422,6 @@
rtc::PacketTransportInternal* transport) {
RTC_DCHECK_RUN_ON(network_thread_);
transport->SignalWritableState.connect(this, &BaseChannel::OnWritableState);
- transport->SignalReadPacket.connect(this, &BaseChannel::OnPacketRead);
transport->SignalSentPacket.connect(this, &BaseChannel::SignalSentPacket_n);
}
@@ -430,7 +429,6 @@
rtc::PacketTransportInternal* transport) {
RTC_DCHECK_RUN_ON(network_thread_);
transport->SignalWritableState.disconnect(this);
- transport->SignalReadPacket.disconnect(this);
transport->SignalSentPacket.disconnect(this);
}
@@ -576,22 +574,6 @@
UpdateWritableState_n();
}
-void BaseChannel::OnPacketRead(rtc::PacketTransportInternal* transport,
- const char* data,
- size_t len,
- const rtc::PacketTime& packet_time,
- int flags) {
- TRACE_EVENT0("webrtc", "BaseChannel::OnPacketRead");
- // OnPacketRead gets called from P2PSocket; now pass data to MediaEngine
- RTC_DCHECK(network_thread_->IsCurrent());
-
- // When using RTCP multiplexing we might get RTCP packets on the RTP
- // transport. We feed RTP traffic into the demuxer to determine if it is RTCP.
- bool rtcp = PacketIsRtcp(transport, data, len);
- rtc::CopyOnWriteBuffer packet(data, len);
- HandlePacket(rtcp, &packet, packet_time);
-}
-
void BaseChannel::OnDtlsState(DtlsTransportInternal* transport,
DtlsTransportState state) {
if (!ShouldSetupDtlsSrtp_n()) {
@@ -641,13 +623,6 @@
Bind(&MediaChannel::OnReadyToSend, media_channel_, ready));
}
-bool BaseChannel::PacketIsRtcp(const rtc::PacketTransportInternal* transport,
- const char* data,
- size_t len) {
- return (transport == rtp_transport_.rtcp_packet_transport() ||
- rtcp_mux_filter_.DemuxRtcp(data, static_cast<int>(len)));
-}
-
bool BaseChannel::SendPacket(bool rtcp,
rtc::CopyOnWriteBuffer* packet,
const rtc::PacketOptions& options) {
@@ -680,7 +655,7 @@
// Protect ourselves against crazy data.
if (!ValidPacket(rtcp, packet)) {
LOG(LS_ERROR) << "Dropping outgoing " << content_name_ << " "
- << PacketType(rtcp)
+ << RtpRtcpStringLiteral(rtcp)
<< " packet: wrong size=" << packet->size();
return false;
}
@@ -772,31 +747,13 @@
return rtp_transport_.SendPacket(rtcp, packet, updated_options, flags);
}
-bool BaseChannel::WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet) {
- // Protect ourselves against crazy data.
- if (!ValidPacket(rtcp, packet)) {
- LOG(LS_ERROR) << "Dropping incoming " << content_name_ << " "
- << PacketType(rtcp)
- << " packet: wrong size=" << packet->size();
- return false;
- }
- if (rtcp) {
- // Permit all (seemingly valid) RTCP packets.
- return true;
- }
- // Check whether we handle this payload.
- return bundle_filter_.DemuxPacket(packet->data(), packet->size());
+bool BaseChannel::HandlesPayloadType(int packet_type) const {
+ return rtp_transport_.HandlesPayloadType(packet_type);
}
-void BaseChannel::HandlePacket(bool rtcp, rtc::CopyOnWriteBuffer* packet,
- const rtc::PacketTime& packet_time) {
- RTC_DCHECK(network_thread_->IsCurrent());
- if (!WantsPacket(rtcp, packet)) {
- return;
- }
-
- // We are only interested in the first rtp packet because that
- // indicates the media has started flowing.
+void BaseChannel::OnPacketReceived(bool rtcp,
+ rtc::CopyOnWriteBuffer& packet,
+ const rtc::PacketTime& packet_time) {
if (!has_received_packet_ && !rtcp) {
has_received_packet_ = true;
signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FIRSTPACKETRECEIVED);
@@ -805,8 +762,8 @@
// Unprotect the packet, if needed.
if (srtp_filter_.IsActive()) {
TRACE_EVENT0("webrtc", "SRTP Decode");
- char* data = packet->data<char>();
- int len = static_cast<int>(packet->size());
+ char* data = packet.data<char>();
+ int len = static_cast<int>(packet.size());
bool res;
if (!rtcp) {
res = srtp_filter_.UnprotectRtp(data, len, &len);
@@ -816,8 +773,8 @@
GetRtpSeqNum(data, len, &seq_num);
GetRtpSsrc(data, len, &ssrc);
LOG(LS_ERROR) << "Failed to unprotect " << content_name_
- << " RTP packet: size=" << len
- << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
+ << " RTP packet: size=" << len << ", seqnum=" << seq_num
+ << ", SSRC=" << ssrc;
return;
}
} else {
@@ -831,7 +788,7 @@
}
}
- packet->SetSize(len);
+ packet.SetSize(len);
} else if (srtp_required_) {
// Our session description indicates that SRTP is required, but we got a
// packet before our SRTP filter is active. This means either that
@@ -844,20 +801,21 @@
// before sending media, to prevent weird failure modes, so it's fine
// for us to just eat packets here. This is all sidestepped if RTCP mux
// is used anyway.
- LOG(LS_WARNING) << "Can't process incoming " << PacketType(rtcp)
+ LOG(LS_WARNING) << "Can't process incoming " << RtpRtcpStringLiteral(rtcp)
<< " packet when SRTP is inactive and crypto is required";
return;
}
invoker_.AsyncInvoke<void>(
RTC_FROM_HERE, worker_thread_,
- Bind(&BaseChannel::OnPacketReceived, this, rtcp, *packet, packet_time));
+ Bind(&BaseChannel::ProcessPacket, this, rtcp, packet, packet_time));
}
-void BaseChannel::OnPacketReceived(bool rtcp,
- const rtc::CopyOnWriteBuffer& packet,
- const rtc::PacketTime& packet_time) {
+void BaseChannel::ProcessPacket(bool rtcp,
+ const rtc::CopyOnWriteBuffer& packet,
+ const rtc::PacketTime& packet_time) {
RTC_DCHECK(worker_thread_->IsCurrent());
+
// Need to copy variable because OnRtcpReceived/OnPacketReceived
// requires non-const pointer to buffer. This doesn't memcpy the actual data.
rtc::CopyOnWriteBuffer data(packet);
@@ -987,7 +945,7 @@
}
LOG(LS_INFO) << "Installing keys from DTLS-SRTP on " << content_name() << " "
- << PacketType(rtcp);
+ << RtpRtcpStringLiteral(rtcp);
int key_len;
int salt_len;
@@ -1448,6 +1406,10 @@
}
}
+void BaseChannel::AddHandledPayloadType(int payload_type) {
+ rtp_transport_.AddHandledPayloadType(payload_type);
+}
+
void BaseChannel::FlushRtcpMessages_n() {
// Flush all remaining RTCP messages. This should only be called in
// destructor.
@@ -1659,15 +1621,13 @@
media_channel()->GetActiveStreams(actives);
}
-void VoiceChannel::OnPacketRead(rtc::PacketTransportInternal* transport,
- const char* data,
- size_t len,
- const rtc::PacketTime& packet_time,
- int flags) {
- BaseChannel::OnPacketRead(transport, data, len, packet_time, flags);
+void VoiceChannel::OnPacketReceived(bool rtcp,
+ rtc::CopyOnWriteBuffer& packet,
+ const rtc::PacketTime& packet_time) {
+ BaseChannel::OnPacketReceived(rtcp, packet, packet_time);
// Set a flag when we've received an RTP packet. If we're waiting for early
// media, this will disable the timeout.
- if (!received_media_ && !PacketIsRtcp(transport, data, len)) {
+ if (!received_media_ && !rtcp) {
received_media_ = true;
}
}
@@ -1766,7 +1726,7 @@
return false;
}
for (const AudioCodec& codec : audio->codecs()) {
- bundle_filter()->AddPayloadType(codec.id);
+ AddHandledPayloadType(codec.id);
}
last_recv_params_ = recv_params;
@@ -2039,7 +1999,7 @@
return false;
}
for (const VideoCodec& codec : video->codecs()) {
- bundle_filter()->AddPayloadType(codec.id);
+ AddHandledPayloadType(codec.id);
}
last_recv_params_ = recv_params;
@@ -2234,7 +2194,7 @@
return false;
}
for (const DataCodec& codec : data->codecs()) {
- bundle_filter()->AddPayloadType(codec.id);
+ AddHandledPayloadType(codec.id);
}
last_recv_params_ = recv_params;
diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h
index 48259e5..0abdaf2 100644
--- a/webrtc/pc/channel.h
+++ b/webrtc/pc/channel.h
@@ -36,7 +36,6 @@
#include "webrtc/p2p/base/transportcontroller.h"
#include "webrtc/p2p/client/socketmonitor.h"
#include "webrtc/pc/audiomonitor.h"
-#include "webrtc/pc/bundlefilter.h"
#include "webrtc/pc/mediamonitor.h"
#include "webrtc/pc/mediasession.h"
#include "webrtc/pc/rtcpmuxfilter.h"
@@ -149,8 +148,6 @@
// For ConnectionStatsGetter, used by ConnectionMonitor
bool GetConnectionStats(ConnectionInfos* infos) override;
- BundleFilter* bundle_filter() { return &bundle_filter_; }
-
const std::vector<StreamParams>& local_streams() const {
return local_streams_;
}
@@ -198,6 +195,11 @@
// This function returns true if we require SRTP for call setup.
bool srtp_required_for_testing() const { return srtp_required_; }
+ // Public for testing.
+ // TODO(zstein): Remove this once channels register themselves with
+ // an RtpTransport in a more explicit way.
+ bool HandlesPayloadType(int payload_type) const;
+
protected:
virtual MediaChannel* media_channel() const { return media_channel_; }
@@ -248,11 +250,6 @@
// From TransportChannel
void OnWritableState(rtc::PacketTransportInternal* transport);
- virtual void OnPacketRead(rtc::PacketTransportInternal* transport,
- const char* data,
- size_t len,
- const rtc::PacketTime& packet_time,
- int flags);
void OnDtlsState(DtlsTransportInternal* transport, DtlsTransportState state);
@@ -272,9 +269,13 @@
bool WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet);
void HandlePacket(bool rtcp, rtc::CopyOnWriteBuffer* packet,
const rtc::PacketTime& packet_time);
- void OnPacketReceived(bool rtcp,
- const rtc::CopyOnWriteBuffer& packet,
- const rtc::PacketTime& packet_time);
+ // TODO(zstein): packet can be const once the RtpTransport handles protection.
+ virtual void OnPacketReceived(bool rtcp,
+ rtc::CopyOnWriteBuffer& packet,
+ const rtc::PacketTime& packet_time);
+ void ProcessPacket(bool rtcp,
+ const rtc::CopyOnWriteBuffer& packet,
+ const rtc::PacketTime& packet_time);
void EnableMedia_w();
void DisableMedia_w();
@@ -357,6 +358,8 @@
return worker_thread_->Invoke<bool>(posted_from, functor);
}
+ void AddHandledPayloadType(int payload_type);
+
private:
bool InitNetwork_n(DtlsTransportInternal* rtp_dtls_transport,
DtlsTransportInternal* rtcp_dtls_transport,
@@ -394,7 +397,6 @@
std::vector<std::pair<rtc::Socket::Option, int> > rtcp_socket_options_;
SrtpFilter srtp_filter_;
RtcpMuxFilter rtcp_mux_filter_;
- BundleFilter bundle_filter_;
bool writable_ = false;
bool was_ever_writable_ = false;
bool has_received_packet_ = false;
@@ -496,11 +498,9 @@
private:
// overrides from BaseChannel
- void OnPacketRead(rtc::PacketTransportInternal* transport,
- const char* data,
- size_t len,
- const rtc::PacketTime& packet_time,
- int flags) override;
+ void OnPacketReceived(bool rtcp,
+ rtc::CopyOnWriteBuffer& packet,
+ const rtc::PacketTime& packet_time) override;
void UpdateMediaSendRecvState_w() override;
const ContentInfo* GetFirstContent(const SessionDescription* sdesc) override;
bool SetLocalContent_w(const MediaContentDescription* content,
diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc
index 6c4aa0f..a351e17 100644
--- a/webrtc/pc/channel_unittest.cc
+++ b/webrtc/pc/channel_unittest.cc
@@ -1560,10 +1560,10 @@
EXPECT_TRUE(SendAccept());
EXPECT_EQ(rtcp_mux, !channel1_->NeedsRtcpTransport());
EXPECT_EQ(rtcp_mux, !channel2_->NeedsRtcpTransport());
- EXPECT_TRUE(channel1_->bundle_filter()->FindPayloadType(pl_type1));
- EXPECT_TRUE(channel2_->bundle_filter()->FindPayloadType(pl_type1));
- EXPECT_FALSE(channel1_->bundle_filter()->FindPayloadType(pl_type2));
- EXPECT_FALSE(channel2_->bundle_filter()->FindPayloadType(pl_type2));
+ EXPECT_TRUE(channel1_->HandlesPayloadType(pl_type1));
+ EXPECT_TRUE(channel2_->HandlesPayloadType(pl_type1));
+ EXPECT_FALSE(channel1_->HandlesPayloadType(pl_type2));
+ EXPECT_FALSE(channel2_->HandlesPayloadType(pl_type2));
// Both channels can receive pl_type1 only.
SendCustomRtp1(kSsrc1, ++sequence_number1_1, pl_type1);
diff --git a/webrtc/pc/rtcpmuxfilter.cc b/webrtc/pc/rtcpmuxfilter.cc
index 715e1e7..f3ae468 100644
--- a/webrtc/pc/rtcpmuxfilter.cc
+++ b/webrtc/pc/rtcpmuxfilter.cc
@@ -108,26 +108,6 @@
return true;
}
-// Check the RTP payload type. If 63 < payload type < 96, it's RTCP.
-// For additional details, see http://tools.ietf.org/html/rfc5761.
-bool IsRtcp(const char* data, int len) {
- if (len < 2) {
- return false;
- }
- char pt = data[1] & 0x7F;
- return (63 < pt) && (pt < 96);
-}
-
-bool RtcpMuxFilter::DemuxRtcp(const char* data, int len) {
- // If we're muxing RTP/RTCP, we must inspect each packet delivered
- // and determine whether it is RTP or RTCP. We do so by looking at
- // the RTP payload type (see IsRtcp). Note that if we offer RTCP
- // mux, we may receive muxed RTCP before we receive the answer, so
- // we operate in that state too.
- bool offered_mux = ((state_ == ST_SENTOFFER) && offer_enable_);
- return (IsActive() || offered_mux) && IsRtcp(data, len);
-}
-
bool RtcpMuxFilter::ExpectOffer(bool offer_enable, ContentSource source) {
return ((state_ == ST_INIT) ||
(state_ == ST_ACTIVE && offer_enable == offer_enable_) ||
diff --git a/webrtc/pc/rtcpmuxfilter.h b/webrtc/pc/rtcpmuxfilter.h
index bdd8a35..95a9d5f 100644
--- a/webrtc/pc/rtcpmuxfilter.h
+++ b/webrtc/pc/rtcpmuxfilter.h
@@ -45,9 +45,6 @@
// Specifies whether the answer indicates the use of RTCP mux.
bool SetAnswer(bool answer_enable, ContentSource src);
- // Determines whether the specified packet is RTCP.
- bool DemuxRtcp(const char* data, int len);
-
private:
bool ExpectOffer(bool offer_enable, ContentSource source);
bool ExpectAnswer(ContentSource source);
diff --git a/webrtc/pc/rtcpmuxfilter_unittest.cc b/webrtc/pc/rtcpmuxfilter_unittest.cc
index b0ba88a..807103a 100644
--- a/webrtc/pc/rtcpmuxfilter_unittest.cc
+++ b/webrtc/pc/rtcpmuxfilter_unittest.cc
@@ -12,72 +12,6 @@
#include "webrtc/media/base/testutils.h"
#include "webrtc/pc/rtcpmuxfilter.h"
-TEST(RtcpMuxFilterTest, DemuxRtcpSender) {
- cricket::RtcpMuxFilter filter;
- const char data[] = { 0, 73, 0, 0 };
- const int len = 4;
-
- // Init state - refuse to demux
- EXPECT_FALSE(filter.DemuxRtcp(data, len));
- // After sent offer, demux should be enabled
- filter.SetOffer(true, cricket::CS_LOCAL);
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
- // Remote accepted, demux should be enabled
- filter.SetAnswer(true, cricket::CS_REMOTE);
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
-}
-
-TEST(RtcpMuxFilterTest, DemuxRtcpReceiver) {
- cricket::RtcpMuxFilter filter;
- const char data[] = { 0, 73, 0, 0 };
- const int len = 4;
-
- // Init state - refuse to demux
- EXPECT_FALSE(filter.DemuxRtcp(data, len));
- // After received offer, demux should not be enabled
- filter.SetOffer(true, cricket::CS_REMOTE);
- EXPECT_FALSE(filter.DemuxRtcp(data, len));
- // We accept, demux is now enabled
- filter.SetAnswer(true, cricket::CS_LOCAL);
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
-}
-
-TEST(RtcpMuxFilterTest, DemuxRtcpSenderProvisionalAnswer) {
- cricket::RtcpMuxFilter filter;
- const char data[] = { 0, 73, 0, 0 };
- const int len = 4;
-
- filter.SetOffer(true, cricket::CS_REMOTE);
- // Received provisional answer without mux enabled.
- filter.SetProvisionalAnswer(false, cricket::CS_LOCAL);
- EXPECT_FALSE(filter.DemuxRtcp(data, len));
- // Received provisional answer with mux enabled.
- filter.SetProvisionalAnswer(true, cricket::CS_LOCAL);
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
- // Remote accepted, demux should be enabled.
- filter.SetAnswer(true, cricket::CS_LOCAL);
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
-}
-
-TEST(RtcpMuxFilterTest, DemuxRtcpReceiverProvisionalAnswer) {
- cricket::RtcpMuxFilter filter;
- const char data[] = { 0, 73, 0, 0 };
- const int len = 4;
-
- filter.SetOffer(true, cricket::CS_LOCAL);
- // Received provisional answer without mux enabled.
- filter.SetProvisionalAnswer(false, cricket::CS_REMOTE);
- // After sent offer, demux should be enabled until we have received a
- // final answer.
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
- // Received provisional answer with mux enabled.
- filter.SetProvisionalAnswer(true, cricket::CS_REMOTE);
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
- // Remote accepted, demux should be enabled.
- filter.SetAnswer(true, cricket::CS_REMOTE);
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
-}
-
TEST(RtcpMuxFilterTest, IsActiveSender) {
cricket::RtcpMuxFilter filter;
// Init state - not active
@@ -222,12 +156,9 @@
// Test that we can SetActive and then can't deactivate.
TEST(RtcpMuxFilterTest, SetActiveCantDeactivate) {
cricket::RtcpMuxFilter filter;
- const char data[] = { 0, 73, 0, 0 };
- const int len = 4;
filter.SetActive();
EXPECT_TRUE(filter.IsActive());
- EXPECT_TRUE(filter.DemuxRtcp(data, len));
EXPECT_FALSE(filter.SetOffer(false, cricket::CS_LOCAL));
EXPECT_TRUE(filter.IsActive());
diff --git a/webrtc/pc/rtptransport.cc b/webrtc/pc/rtptransport.cc
index 2ee27e0..2981675 100644
--- a/webrtc/pc/rtptransport.cc
+++ b/webrtc/pc/rtptransport.cc
@@ -12,6 +12,8 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/copyonwritebuffer.h"
+#include "webrtc/base/trace_event.h"
+#include "webrtc/media/base/rtputils.h"
#include "webrtc/p2p/base/packettransportinterface.h"
namespace webrtc {
@@ -28,10 +30,13 @@
}
if (rtp_packet_transport_) {
rtp_packet_transport_->SignalReadyToSend.disconnect(this);
+ rtp_packet_transport_->SignalReadPacket.disconnect(this);
}
if (new_packet_transport) {
new_packet_transport->SignalReadyToSend.connect(
this, &RtpTransport::OnReadyToSend);
+ new_packet_transport->SignalReadPacket.connect(this,
+ &RtpTransport::OnReadPacket);
}
rtp_packet_transport_ = new_packet_transport;
@@ -48,10 +53,13 @@
}
if (rtcp_packet_transport_) {
rtcp_packet_transport_->SignalReadyToSend.disconnect(this);
+ rtcp_packet_transport_->SignalReadPacket.disconnect(this);
}
if (new_packet_transport) {
new_packet_transport->SignalReadyToSend.connect(
this, &RtpTransport::OnReadyToSend);
+ new_packet_transport->SignalReadPacket.connect(this,
+ &RtpTransport::OnReadPacket);
}
rtcp_packet_transport_ = new_packet_transport;
@@ -87,6 +95,18 @@
return true;
}
+bool RtpTransport::HandlesPacket(const uint8_t* data, size_t len) {
+ return bundle_filter_.DemuxPacket(data, len);
+}
+
+bool RtpTransport::HandlesPayloadType(int payload_type) const {
+ return bundle_filter_.FindPayloadType(payload_type);
+}
+
+void RtpTransport::AddHandledPayloadType(int payload_type) {
+ bundle_filter_.AddPayloadType(payload_type);
+}
+
PacketTransportInterface* RtpTransport::GetRtpPacketTransport() const {
return rtp_packet_transport_;
}
@@ -142,4 +162,51 @@
}
}
+// Check the RTP payload type. If 63 < payload type < 96, it's RTCP.
+// For additional details, see http://tools.ietf.org/html/rfc5761.
+bool IsRtcp(const char* data, int len) {
+ if (len < 2) {
+ return false;
+ }
+ char pt = data[1] & 0x7F;
+ return (63 < pt) && (pt < 96);
+}
+
+void RtpTransport::OnReadPacket(rtc::PacketTransportInternal* transport,
+ const char* data,
+ size_t len,
+ const rtc::PacketTime& packet_time,
+ int flags) {
+ TRACE_EVENT0("webrtc", "RtpTransport::OnReadPacket");
+
+ // When using RTCP multiplexing we might get RTCP packets on the RTP
+ // transport. We check the RTP payload type to determine if it is RTCP.
+ bool rtcp = transport == rtcp_packet_transport() ||
+ IsRtcp(data, static_cast<int>(len));
+ rtc::CopyOnWriteBuffer packet(data, len);
+
+ if (!WantsPacket(rtcp, &packet)) {
+ return;
+ }
+
+ // This mutates |packet| if it is protected.
+ SignalPacketReceived(rtcp, packet, packet_time);
+}
+
+bool RtpTransport::WantsPacket(bool rtcp,
+ const rtc::CopyOnWriteBuffer* packet) {
+ // Protect ourselves against crazy data.
+ if (!packet || !cricket::IsValidRtpRtcpPacketSize(rtcp, packet->size())) {
+ LOG(LS_ERROR) << "Dropping incoming " << cricket::RtpRtcpStringLiteral(rtcp)
+ << " packet: wrong size=" << packet->size();
+ return false;
+ }
+ if (rtcp) {
+ // Permit all (seemingly valid) RTCP packets.
+ return true;
+ }
+ // Check whether we handle this payload.
+ return HandlesPacket(packet->data(), packet->size());
+}
+
} // namespace webrtc
diff --git a/webrtc/pc/rtptransport.h b/webrtc/pc/rtptransport.h
index f9bee1b..1224b44 100644
--- a/webrtc/pc/rtptransport.h
+++ b/webrtc/pc/rtptransport.h
@@ -13,11 +13,13 @@
#include "webrtc/api/ortc/rtptransportinterface.h"
#include "webrtc/base/sigslot.h"
+#include "webrtc/pc/bundlefilter.h"
namespace rtc {
class CopyOnWriteBuffer;
struct PacketOptions;
+struct PacketTime;
class PacketTransportInternal;
} // namespace rtc
@@ -64,11 +66,23 @@
const rtc::PacketOptions& options,
int flags);
+ bool HandlesPayloadType(int payload_type) const;
+
+ 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<bool, rtc::CopyOnWriteBuffer&, const rtc::PacketTime&>
+ SignalPacketReceived;
+
protected:
// TODO(zstein): Remove this when we remove RtpTransportAdapter.
RtpTransportAdapter* GetInternal() override;
private:
+ bool HandlesPacket(const uint8_t* data, size_t len);
+
void OnReadyToSend(rtc::PacketTransportInternal* transport);
// Updates "ready to send" for an individual channel and fires
@@ -77,6 +91,14 @@
void MaybeSignalReadyToSend();
+ void OnReadPacket(rtc::PacketTransportInternal* transport,
+ const char* data,
+ size_t len,
+ const rtc::PacketTime& packet_time,
+ int flags);
+
+ bool WantsPacket(bool rtcp, const rtc::CopyOnWriteBuffer* packet);
+
bool rtcp_mux_enabled_;
rtc::PacketTransportInternal* rtp_packet_transport_ = nullptr;
@@ -87,6 +109,8 @@
bool rtcp_ready_to_send_ = false;
RtcpParameters rtcp_parameters_;
+
+ cricket::BundleFilter bundle_filter_;
};
} // namespace webrtc
diff --git a/webrtc/pc/rtptransport_unittest.cc b/webrtc/pc/rtptransport_unittest.cc
index ba49251..df84d47 100644
--- a/webrtc/pc/rtptransport_unittest.cc
+++ b/webrtc/pc/rtptransport_unittest.cc
@@ -16,12 +16,10 @@
namespace webrtc {
-class RtpTransportTest : public testing::Test {};
-
constexpr bool kMuxDisabled = false;
constexpr bool kMuxEnabled = true;
-TEST_F(RtpTransportTest, SetRtcpParametersCantDisableRtcpMux) {
+TEST(RtpTransportTest, SetRtcpParametersCantDisableRtcpMux) {
RtpTransport transport(kMuxDisabled);
RtcpParameters params;
transport.SetRtcpParameters(params);
@@ -29,7 +27,7 @@
EXPECT_FALSE(transport.SetRtcpParameters(params).ok());
}
-TEST_F(RtpTransportTest, SetRtcpParametersEmptyCnameUsesExisting) {
+TEST(RtpTransportTest, SetRtcpParametersEmptyCnameUsesExisting) {
static const char kName[] = "name";
RtpTransport transport(kMuxDisabled);
RtcpParameters params_with_name;
@@ -47,11 +45,14 @@
explicit SignalObserver(RtpTransport* transport) {
transport->SignalReadyToSend.connect(this, &SignalObserver::OnReadyToSend);
}
+ bool ready() const { return ready_; }
void OnReadyToSend(bool ready) { ready_ = ready; }
+
+ private:
bool ready_ = false;
};
-TEST_F(RtpTransportTest, SettingRtcpAndRtpSignalsReady) {
+TEST(RtpTransportTest, SettingRtcpAndRtpSignalsReady) {
RtpTransport transport(kMuxDisabled);
SignalObserver observer(&transport);
rtc::FakePacketTransport fake_rtcp("fake_rtcp");
@@ -60,12 +61,12 @@
fake_rtp.SetWritable(true);
transport.SetRtcpPacketTransport(&fake_rtcp); // rtcp ready
- EXPECT_FALSE(observer.ready_);
+ EXPECT_FALSE(observer.ready());
transport.SetRtpPacketTransport(&fake_rtp); // rtp ready
- EXPECT_TRUE(observer.ready_);
+ EXPECT_TRUE(observer.ready());
}
-TEST_F(RtpTransportTest, SettingRtpAndRtcpSignalsReady) {
+TEST(RtpTransportTest, SettingRtpAndRtcpSignalsReady) {
RtpTransport transport(kMuxDisabled);
SignalObserver observer(&transport);
rtc::FakePacketTransport fake_rtcp("fake_rtcp");
@@ -74,45 +75,45 @@
fake_rtp.SetWritable(true);
transport.SetRtpPacketTransport(&fake_rtp); // rtp ready
- EXPECT_FALSE(observer.ready_);
+ EXPECT_FALSE(observer.ready());
transport.SetRtcpPacketTransport(&fake_rtcp); // rtcp ready
- EXPECT_TRUE(observer.ready_);
+ EXPECT_TRUE(observer.ready());
}
-TEST_F(RtpTransportTest, SettingRtpWithRtcpMuxEnabledSignalsReady) {
+TEST(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_);
+ EXPECT_TRUE(observer.ready());
}
-TEST_F(RtpTransportTest, DisablingRtcpMuxSignalsNotReady) {
+TEST(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_);
+ EXPECT_TRUE(observer.ready());
transport.SetRtcpMuxEnabled(false);
- EXPECT_FALSE(observer.ready_);
+ EXPECT_FALSE(observer.ready());
}
-TEST_F(RtpTransportTest, EnablingRtcpMuxSignalsReady) {
+TEST(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_);
+ EXPECT_FALSE(observer.ready());
transport.SetRtcpMuxEnabled(true);
- EXPECT_TRUE(observer.ready_);
+ EXPECT_TRUE(observer.ready());
}
class SignalCounter : public sigslot::has_slots<> {
@@ -120,11 +121,14 @@
explicit SignalCounter(RtpTransport* transport) {
transport->SignalReadyToSend.connect(this, &SignalCounter::OnReadyToSend);
}
+ int count() const { return count_; }
void OnReadyToSend(bool ready) { ++count_; }
+
+ private:
int count_ = 0;
};
-TEST_F(RtpTransportTest, ChangingReadyToSendStateOnlySignalsWhenChanged) {
+TEST(RtpTransportTest, ChangingReadyToSendStateOnlySignalsWhenChanged) {
RtpTransport transport(kMuxEnabled);
SignalCounter observer(&transport);
rtc::FakePacketTransport fake_rtp("fake_rtp");
@@ -132,19 +136,101 @@
// State changes, so we should signal.
transport.SetRtpPacketTransport(&fake_rtp);
- EXPECT_EQ(observer.count_, 1);
+ EXPECT_EQ(observer.count(), 1);
// State does not change, so we should not signal.
transport.SetRtpPacketTransport(&fake_rtp);
- EXPECT_EQ(observer.count_, 1);
+ EXPECT_EQ(observer.count(), 1);
// State does not change, so we should not signal.
transport.SetRtcpMuxEnabled(true);
- EXPECT_EQ(observer.count_, 1);
+ EXPECT_EQ(observer.count(), 1);
// State changes, so we should signal.
transport.SetRtcpMuxEnabled(false);
- EXPECT_EQ(observer.count_, 2);
+ 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) {
+ RtpTransport transport(kMuxDisabled);
+ SignalPacketReceivedCounter observer(&transport);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetDestination(&fake_rtp, true);
+ transport.SetRtpPacketTransport(&fake_rtp);
+
+ // An rtcp packet.
+ const char data[] = {0, 73, 0, 0};
+ const int len = 4;
+ const rtc::PacketOptions options;
+ const int flags = 0;
+ fake_rtp.SendPacket(data, len, options, flags);
+ EXPECT_EQ(0, observer.rtp_count());
+ EXPECT_EQ(1, observer.rtcp_count());
+}
+
+static const unsigned char kRtpData[] = {0x80, 0x11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0};
+static const int kRtpLen = 12;
+
+// Test that SignalPacketReceived fires with rtcp=false when a RTP packet with a
+// handled payload type is received.
+TEST(RtpTransportTest, SignalHandledRtpPayloadType) {
+ RtpTransport transport(kMuxDisabled);
+ SignalPacketReceivedCounter observer(&transport);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetDestination(&fake_rtp, true);
+ transport.SetRtpPacketTransport(&fake_rtp);
+ transport.AddHandledPayloadType(0x11);
+
+ // An rtp packet.
+ const rtc::PacketOptions options;
+ const int flags = 0;
+ rtc::Buffer rtp_data(kRtpData, kRtpLen);
+ fake_rtp.SendPacket(rtp_data.data<char>(), kRtpLen, options, flags);
+ EXPECT_EQ(1, observer.rtp_count());
+ EXPECT_EQ(0, observer.rtcp_count());
+}
+
+// Test that SignalPacketReceived does not fire when a RTP packet with an
+// unhandled payload type is received.
+TEST(RtpTransportTest, DontSignalUnhandledRtpPayloadType) {
+ RtpTransport transport(kMuxDisabled);
+ SignalPacketReceivedCounter observer(&transport);
+ rtc::FakePacketTransport fake_rtp("fake_rtp");
+ fake_rtp.SetDestination(&fake_rtp, true);
+ transport.SetRtpPacketTransport(&fake_rtp);
+
+ const rtc::PacketOptions options;
+ const int flags = 0;
+ rtc::Buffer rtp_data(kRtpData, kRtpLen);
+ fake_rtp.SendPacket(rtp_data.data<char>(), kRtpLen, options, flags);
+ EXPECT_EQ(0, observer.rtp_count());
+ EXPECT_EQ(0, observer.rtcp_count());
}
} // namespace webrtc