From 3fb8f7bbb0c5e074d0744c57905c5f49bb7d8304 Mon Sep 17 00:00:00 2001 From: "solenberg@webrtc.org" Date: Mon, 24 Mar 2014 20:28:11 +0000 Subject: [PATCH] Implement ViE forwarding to RBE of packets for BWE coming in through the ViENetwork::ReceivedBWEPacket API. BUG= R=mflodman@webrtc.org Review URL: https://webrtc-codereview.appspot.com/10429004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5765 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/video_engine/include/vie_rtp_rtcp.h | 5 - .../auto_test/automated/vie_network_test.cc | 214 ++++++++++++++++++ .../test/auto_test/vie_auto_test.gypi | 1 + webrtc/video_engine/vie_channel.cc | 4 + webrtc/video_engine/vie_channel.h | 3 + webrtc/video_engine/vie_network_impl.cc | 3 +- webrtc/video_engine/vie_receiver.cc | 24 +- webrtc/video_engine/vie_receiver.h | 3 + webrtc/video_engine/vie_rtp_rtcp_impl.cc | 1 - 9 files changed, 247 insertions(+), 11 deletions(-) create mode 100644 webrtc/video_engine/test/auto_test/automated/vie_network_test.cc diff --git a/webrtc/video_engine/include/vie_rtp_rtcp.h b/webrtc/video_engine/include/vie_rtp_rtcp.h index e4ef74a039..b7db7ec0ea 100644 --- a/webrtc/video_engine/include/vie_rtp_rtcp.h +++ b/webrtc/video_engine/include/vie_rtp_rtcp.h @@ -49,11 +49,6 @@ enum StreamType { kViEStreamTypeRtx = 1 // Retransmission media stream }; -enum BandwidthEstimationMode { - kViEMultiStreamEstimation, - kViESingleStreamEstimation -}; - // This class declares an abstract interface for a user defined observer. It is // up to the VideoEngine user to implement a derived class which implements the // observer class. The observer is registered using RegisterRTPObserver() and diff --git a/webrtc/video_engine/test/auto_test/automated/vie_network_test.cc b/webrtc/video_engine/test/auto_test/automated/vie_network_test.cc new file mode 100644 index 0000000000..3a595084c2 --- /dev/null +++ b/webrtc/video_engine/test/auto_test/automated/vie_network_test.cc @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2014 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 + +#include "gflags/gflags.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" +#include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h" +#include "webrtc/video_engine/test/libvietest/include/tb_interfaces.h" +#include "webrtc/system_wrappers/interface/sleep.h" +#include "webrtc/system_wrappers/interface/tick_util.h" + +namespace { + +class RtcpCollectorTransport : public webrtc::Transport { + public: + RtcpCollectorTransport() : packets_() {} + virtual ~RtcpCollectorTransport() {} + + virtual int SendPacket(int /*channel*/, const void* /*data*/, int /*len*/) { + EXPECT_TRUE(false); + return 0; + } + virtual int SendRTCPPacket(int channel, const void* data, int len) { + const uint8_t* buf = static_cast(data); + webrtc::ModuleRTPUtility::RTPHeaderParser parser(buf, len); + if (parser.RTCP()) { + Packet p; + p.channel = channel; + p.length = len; + if (parser.ParseRtcp(&p.header)) { + if (p.header.payloadType == 201) { + buf += 20; + len -= 20; + } else { + return 0; + } + if (TryParseREMB(buf, len, &p)) { + packets_.push_back(p); + } + } + } + return 0; + } + + bool FindREMBFor(uint32_t ssrc, double min_rate) const { + for (std::vector::const_iterator it = packets_.begin(); + it != packets_.end(); ++it) { + if (it->remb_bitrate >= min_rate && it->remb_ssrc.end() != + std::find(it->remb_ssrc.begin(), it->remb_ssrc.end(), ssrc)) { + return true; + } + } + return false; + } + + private: + struct Packet { + Packet() : channel(-1), length(0), header(), remb_bitrate(0), remb_ssrc() {} + int channel; + int length; + webrtc::RTPHeader header; + double remb_bitrate; + std::vector remb_ssrc; + }; + + bool TryParseREMB(const uint8_t* buf, int length, Packet* p) { + if (length < 8) { + return false; + } + if (buf[0] != 'R' || buf[1] != 'E' || buf[2] != 'M' || buf[3] != 'B') { + return false; + } + uint8_t ssrcs = buf[4]; + uint8_t exp = buf[5] >> 2; + uint32_t mantissa = ((buf[5] & 0x03) << 16) + (buf[6] << 8) + buf[7]; + double bitrate = mantissa * static_cast(1 << exp); + p->remb_bitrate = bitrate; + + if (length < (8 + 4 * ssrcs)) { + return false; + } + buf += 8; + for (uint8_t i = 0; i < ssrcs; ++i) { + uint32_t ssrc = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; + p->remb_ssrc.push_back(ssrc); + buf += 4; + } + return true; + } + + std::vector packets_; +}; + +class ViENetworkTest : public testing::Test { + protected: + ViENetworkTest() : vie_("ViENetworkTest"), channel_(-1), transport() {} + virtual ~ViENetworkTest() {} + + virtual void SetUp() { + EXPECT_EQ(0, vie_.base->CreateChannel(channel_)); + EXPECT_EQ(0, vie_.rtp_rtcp->SetRembStatus(channel_, false, true)); + EXPECT_EQ(0, vie_.network->RegisterSendTransport(channel_, transport)); + } + + virtual void TearDown() { + unsigned int bandwidth = 0; + EXPECT_EQ(0, vie_.rtp_rtcp->GetEstimatedReceiveBandwidth(channel_, + &bandwidth)); + EXPECT_EQ(bandwidth, 0u); + EXPECT_EQ(0, vie_.network->DeregisterSendTransport(channel_)); + } + + void ReceiveASTPacketsForBWE() { + for (int i = 0; i < kPacketCount; ++i) { + int64_t time = webrtc::TickTime::MillisecondTimestamp(); + webrtc::RTPHeader header; + header.ssrc = kSsrc1; + header.timestamp = i * 45000; + header.extension.hasAbsoluteSendTime = true; + header.extension.absoluteSendTime = i << (18 - 6); + EXPECT_EQ(0, vie_.network->ReceivedBWEPacket(channel_, time, kPacketSize, + header)); + webrtc::SleepMs(kIntervalMs); + } + } + + enum { + kSsrc1 = 667, + kSsrc2 = 668, + kPacketCount = 100, + kPacketSize = 1000, + kIntervalMs = 22 + }; + TbInterfaces vie_; + int channel_; + RtcpCollectorTransport transport; +}; + +TEST_F(ViENetworkTest, ReceiveBWEPacket_NoExtension) { + for (int i = 0; i < kPacketCount; ++i) { + int64_t time = webrtc::TickTime::MillisecondTimestamp(); + webrtc::RTPHeader header; + header.ssrc = kSsrc1; + header.timestamp = i * 45000; + EXPECT_EQ(0, vie_.network->ReceivedBWEPacket(channel_, time, kPacketSize, + header)); + webrtc::SleepMs(kIntervalMs); + } + EXPECT_FALSE(transport.FindREMBFor(kSsrc1, 0.0)); +} + +TEST_F(ViENetworkTest, ReceiveBWEPacket_TOF) { + EXPECT_EQ(0, vie_.rtp_rtcp->SetReceiveTimestampOffsetStatus(channel_, true, + 1)); + for (int i = 0; i < kPacketCount; ++i) { + int64_t time = webrtc::TickTime::MillisecondTimestamp(); + webrtc::RTPHeader header; + header.ssrc = kSsrc1; + header.timestamp = i * 45000; + header.extension.hasTransmissionTimeOffset = true; + header.extension.transmissionTimeOffset = 17; + EXPECT_EQ(0, vie_.network->ReceivedBWEPacket(channel_, time, kPacketSize, + header)); + webrtc::SleepMs(kIntervalMs); + } + EXPECT_FALSE(transport.FindREMBFor(kSsrc1, 0.0)); +} + +TEST_F(ViENetworkTest, ReceiveBWEPacket_AST) { + EXPECT_EQ(0, vie_.rtp_rtcp->SetReceiveAbsoluteSendTimeStatus(channel_, true, + 1)); + ReceiveASTPacketsForBWE(); + EXPECT_TRUE(transport.FindREMBFor(kSsrc1, 100000.0)); +} + +TEST_F(ViENetworkTest, ReceiveBWEPacket_ASTx2) { + EXPECT_EQ(0, vie_.rtp_rtcp->SetReceiveAbsoluteSendTimeStatus(channel_, true, + 1)); + for (int i = 0; i < kPacketCount; ++i) { + int64_t time = webrtc::TickTime::MillisecondTimestamp(); + webrtc::RTPHeader header; + header.ssrc = kSsrc1; + header.timestamp = i * 45000; + header.extension.hasAbsoluteSendTime = true; + header.extension.absoluteSendTime = i << (18 - 6); + EXPECT_EQ(0, vie_.network->ReceivedBWEPacket(channel_, time, kPacketSize, + header)); + header.ssrc = kSsrc2; + header.timestamp += 171717; + EXPECT_EQ(0, vie_.network->ReceivedBWEPacket(channel_, time, kPacketSize, + header)); + webrtc::SleepMs(kIntervalMs); + } + EXPECT_TRUE(transport.FindREMBFor(kSsrc1, 200000.0)); + EXPECT_TRUE(transport.FindREMBFor(kSsrc2, 200000.0)); +} + +TEST_F(ViENetworkTest, ReceiveBWEPacket_AST_DisabledReceive) { + EXPECT_EQ(0, vie_.rtp_rtcp->SetReceiveAbsoluteSendTimeStatus(channel_, false, + 1)); + ReceiveASTPacketsForBWE(); + EXPECT_FALSE(transport.FindREMBFor(kSsrc1, 0.0)); +} + +} // namespace diff --git a/webrtc/video_engine/test/auto_test/vie_auto_test.gypi b/webrtc/video_engine/test/auto_test/vie_auto_test.gypi index fddb5a51a6..7ceef0fa88 100644 --- a/webrtc/video_engine/test/auto_test/vie_auto_test.gypi +++ b/webrtc/video_engine/test/auto_test/vie_auto_test.gypi @@ -41,6 +41,7 @@ 'automated/two_windows_fixture.cc', 'automated/vie_api_integration_test.cc', 'automated/vie_extended_integration_test.cc', + 'automated/vie_network_test.cc', 'automated/vie_standard_integration_test.cc', 'automated/vie_video_verification_test.cc', diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index 64d28f8881..17573af082 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -2067,4 +2067,8 @@ void ViEChannel::RegisterSendFrameCountObserver( } } +void ViEChannel::ReceivedBWEPacket(int64_t arrival_time_ms, + int payload_size, const RTPHeader& header) { + vie_receiver_.ReceivedBWEPacket(arrival_time_ms, payload_size, header); +} } // namespace webrtc diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h index 99911035a3..3233dbff96 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -351,6 +351,9 @@ class ViEChannel void RegisterSendFrameCountObserver(FrameCountObserver* observer); + void ReceivedBWEPacket(int64_t arrival_time_ms, int payload_size, + const RTPHeader& header); + protected: static bool ChannelDecodeThreadFunction(void* obj); bool ChannelDecodeProcess(); diff --git a/webrtc/video_engine/vie_network_impl.cc b/webrtc/video_engine/vie_network_impl.cc index f4ea25fe9c..8c3e1eb0e9 100644 --- a/webrtc/video_engine/vie_network_impl.cc +++ b/webrtc/video_engine/vie_network_impl.cc @@ -214,8 +214,7 @@ int ViENetworkImpl::ReceivedBWEPacket(const int video_channel, return -1; } - // TODO(solenberg): Implement! - // vie_channel->OnReceivedAudioPacket(arrival_time_ms, payload_size, header); + vie_channel->ReceivedBWEPacket(arrival_time_ms, payload_size, header); return 0; } } // namespace webrtc diff --git a/webrtc/video_engine/vie_receiver.cc b/webrtc/video_engine/vie_receiver.cc index 555b602178..87b06288b4 100644 --- a/webrtc/video_engine/vie_receiver.cc +++ b/webrtc/video_engine/vie_receiver.cc @@ -47,7 +47,8 @@ ViEReceiver::ViEReceiver(const int32_t channel_id, remote_bitrate_estimator_(remote_bitrate_estimator), rtp_dump_(NULL), receiving_(false), - restored_packet_in_use_(false) { + restored_packet_in_use_(false), + receiving_ast_enabled_(false) { assert(remote_bitrate_estimator); } @@ -140,9 +141,15 @@ bool ViEReceiver::SetReceiveTimestampOffsetStatus(bool enable, int id) { bool ViEReceiver::SetReceiveAbsoluteSendTimeStatus(bool enable, int id) { if (enable) { - return rtp_header_parser_->RegisterRtpHeaderExtension( - kRtpExtensionAbsoluteSendTime, id); + if (rtp_header_parser_->RegisterRtpHeaderExtension( + kRtpExtensionAbsoluteSendTime, id)) { + receiving_ast_enabled_ = true; + return true; + } else { + return false; + } } else { + receiving_ast_enabled_ = false; return rtp_header_parser_->DeregisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime); } @@ -183,6 +190,17 @@ bool ViEReceiver::OnRecoveredPacket(const uint8_t* rtp_packet, return ReceivePacket(rtp_packet, rtp_packet_length, header, false); } +void ViEReceiver::ReceivedBWEPacket( + int64_t arrival_time_ms, int payload_size, const RTPHeader& header) { + // Only forward if the incoming packet *and* the channel are both configured + // to receive absolute sender time. RTP time stamps may have different rates + // for audio and video and shouldn't be mixed. + if (header.extension.hasAbsoluteSendTime && receiving_ast_enabled_) { + remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size, + header); + } +} + int ViEReceiver::InsertRTPPacket(const uint8_t* rtp_packet, int rtp_packet_length, const PacketTime& packet_time) { diff --git a/webrtc/video_engine/vie_receiver.h b/webrtc/video_engine/vie_receiver.h index 611db40faa..b987c99cac 100644 --- a/webrtc/video_engine/vie_receiver.h +++ b/webrtc/video_engine/vie_receiver.h @@ -87,6 +87,8 @@ class ViEReceiver : public RtpData { ReceiveStatistics* GetReceiveStatistics() const; + void ReceivedBWEPacket(int64_t arrival_time_ms, int payload_size, + const RTPHeader& header); private: int InsertRTPPacket(const uint8_t* rtp_packet, int rtp_packet_length, const PacketTime& packet_time); @@ -119,6 +121,7 @@ class ViEReceiver : public RtpData { bool receiving_; uint8_t restored_packet_[kViEMaxMtu]; bool restored_packet_in_use_; + bool receiving_ast_enabled_; }; } // namespace webrt diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc index 6717e84db8..cd8a46a6b8 100644 --- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc +++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc @@ -1389,5 +1389,4 @@ int ViERTP_RTCPImpl::DeregisterSendFrameCountObserver( vie_channel->RegisterSendFrameCountObserver(NULL); return 0; } - } // namespace webrtc