/* * Copyright (c) 2012 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. */ /* * This file includes unit tests for the RTCPReceiver. */ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" // Note: This file has no directory. Lint warning must be ignored. #include "webrtc/common_types.h" #include "webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h" #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_receiver.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h" #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h" #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" namespace webrtc { namespace { // Anonymous namespace; hide utility functions and classes. // A very simple packet builder class for building RTCP packets. class PacketBuilder { public: static const int kMaxPacketSize = 1024; struct ReportBlock { ReportBlock(uint32_t ssrc, uint32_t extended_max, uint8_t fraction_loss, uint32_t cumulative_loss, uint32_t jitter) : ssrc(ssrc), extended_max(extended_max), fraction_loss(fraction_loss), cumulative_loss(cumulative_loss), jitter(jitter) {} uint32_t ssrc; uint32_t extended_max; uint8_t fraction_loss; uint32_t cumulative_loss; uint32_t jitter; }; PacketBuilder() : pos_(0), pos_of_len_(0) { } void Add8(uint8_t byte) { EXPECT_LT(pos_, kMaxPacketSize - 1); buffer_[pos_] = byte; ++pos_; } void Add16(uint16_t word) { Add8(word >> 8); Add8(word & 0xFF); } void Add32(uint32_t word) { Add8(word >> 24); Add8((word >> 16) & 0xFF); Add8((word >> 8) & 0xFF); Add8(word & 0xFF); } void Add64(uint32_t upper_half, uint32_t lower_half) { Add32(upper_half); Add32(lower_half); } // Set the 5-bit value in the 1st byte of the header // and the payload type. Set aside room for the length field, // and make provision for backpatching it. // Note: No way to set the padding bit. void AddRtcpHeader(int payload, int format_or_count) { PatchLengthField(); Add8(0x80 | (format_or_count & 0x1F)); Add8(payload); pos_of_len_ = pos_; Add16(0xDEAD); // Initialize length to "clearly illegal". } void AddTmmbrBandwidth(int mantissa, int exponent, int overhead) { // 6 bits exponent, 17 bits mantissa, 9 bits overhead. uint32_t word = 0; word |= (exponent << 26); word |= ((mantissa & 0x1FFFF) << 9); word |= (overhead & 0x1FF); Add32(word); } void AddSrPacket(uint32_t sender_ssrc) { AddRtcpHeader(200, 0); Add32(sender_ssrc); Add64(0x10203, 0x4050607); // NTP timestamp Add32(0x10203); // RTP timestamp Add32(0); // Sender's packet count Add32(0); // Sender's octet count } void AddRrPacket(uint32_t sender_ssrc, uint32_t rtp_ssrc, uint32_t extended_max, uint8_t fraction_loss, uint32_t cumulative_loss, uint32_t jitter) { ReportBlock report_block(rtp_ssrc, extended_max, fraction_loss, cumulative_loss, jitter); std::list report_block_vector(&report_block, &report_block + 1); AddRrPacketMultipleReportBlocks(sender_ssrc, report_block_vector); } void AddRrPacketMultipleReportBlocks( uint32_t sender_ssrc, const std::list& report_blocks) { AddRtcpHeader(201, report_blocks.size()); Add32(sender_ssrc); for (std::list::const_iterator it = report_blocks.begin(); it != report_blocks.end(); ++it) { AddReportBlock(it->ssrc, it->extended_max, it->fraction_loss, it->cumulative_loss, it->jitter); } } void AddReportBlock(uint32_t rtp_ssrc, uint32_t extended_max, uint8_t fraction_loss, uint32_t cumulative_loss, uint32_t jitter) { Add32(rtp_ssrc); Add32((fraction_loss << 24) + cumulative_loss); Add32(extended_max); Add32(jitter); Add32(0); // Last SR. Add32(0); // Delay since last SR. } void AddXrHeader(uint32_t sender_ssrc) { AddRtcpHeader(207, 0); Add32(sender_ssrc); } void AddXrReceiverReferenceTimeBlock(uint32_t ntp_sec, uint32_t ntp_frac) { Add8(4); // Block type. Add8(0); // Reserved. Add16(2); // Length. Add64(ntp_sec, ntp_frac); // NTP timestamp. } void AddXrDlrrBlock(std::vector& remote_ssrc) { ASSERT_LT(pos_ + 4 + static_cast(remote_ssrc.size())*4, kMaxPacketSize-1) << "Max buffer size reached."; Add8(5); // Block type. Add8(0); // Reserved. Add16(remote_ssrc.size() * 3); // Length. for (size_t i = 0; i < remote_ssrc.size(); ++i) { Add32(remote_ssrc.at(i)); // Receiver SSRC. Add32(0x10203); // Last RR. Add32(0x40506); // Delay since last RR. } } void AddXrUnknownBlock() { Add8(6); // Block type. Add8(0); // Reserved. Add16(9); // Length. Add32(0); // Receiver SSRC. Add64(0, 0); // Remaining fields (RFC 3611) are set to zero. Add64(0, 0); Add64(0, 0); Add64(0, 0); } void AddXrVoipBlock(uint32_t remote_ssrc, uint8_t loss) { Add8(7); // Block type. Add8(0); // Reserved. Add16(8); // Length. Add32(remote_ssrc); // Receiver SSRC. Add8(loss); // Loss rate. Add8(0); // Remaining statistics (RFC 3611) are set to zero. Add16(0); Add64(0, 0); Add64(0, 0); Add64(0, 0); } const uint8_t* packet() { PatchLengthField(); return buffer_; } unsigned int length() { return pos_; } private: void PatchLengthField() { if (pos_of_len_ > 0) { // Backpatch the packet length. The client must have taken // care of proper padding to 32-bit words. int this_packet_length = (pos_ - pos_of_len_ - 2); ASSERT_EQ(0, this_packet_length % 4) << "Packets must be a multiple of 32 bits long" << " pos " << pos_ << " pos_of_len " << pos_of_len_; buffer_[pos_of_len_] = this_packet_length >> 10; buffer_[pos_of_len_+1] = (this_packet_length >> 2) & 0xFF; pos_of_len_ = 0; } } int pos_; // Where the length field of the current packet is. // Note that 0 is not a legal value, so is used for "uninitialized". int pos_of_len_; uint8_t buffer_[kMaxPacketSize]; }; // This test transport verifies that no functions get called. class TestTransport : public Transport, public NullRtpData { public: explicit TestTransport() : rtcp_receiver_(NULL) { } void SetRTCPReceiver(RTCPReceiver* rtcp_receiver) { rtcp_receiver_ = rtcp_receiver; } virtual int SendPacket(int /*ch*/, const void* /*data*/, int /*len*/) { ADD_FAILURE(); // FAIL() gives a compile error. return -1; } // Injects an RTCP packet into the receiver. virtual int SendRTCPPacket(int /* ch */, const void *packet, int packet_len) { ADD_FAILURE(); return 0; } virtual int OnReceivedPayloadData(const uint8_t* payloadData, const uint16_t payloadSize, const WebRtcRTPHeader* rtpHeader) { ADD_FAILURE(); return 0; } RTCPReceiver* rtcp_receiver_; }; class RtcpReceiverTest : public ::testing::Test { protected: RtcpReceiverTest() : over_use_detector_options_(), system_clock_(1335900000), remote_bitrate_observer_(), remote_bitrate_estimator_( RemoteBitrateEstimatorFactory().Create( &remote_bitrate_observer_, &system_clock_)) { test_transport_ = new TestTransport(); RtpRtcp::Configuration configuration; configuration.id = 0; configuration.audio = false; configuration.clock = &system_clock_; configuration.outgoing_transport = test_transport_; configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get(); rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration); rtcp_receiver_ = new RTCPReceiver(0, &system_clock_, rtp_rtcp_impl_); test_transport_->SetRTCPReceiver(rtcp_receiver_); } ~RtcpReceiverTest() { delete rtcp_receiver_; delete rtp_rtcp_impl_; delete test_transport_; } // Injects an RTCP packet into the receiver. // Returns 0 for OK, non-0 for failure. int InjectRtcpPacket(const uint8_t* packet, uint16_t packet_len) { RTCPUtility::RTCPParserV2 rtcpParser(packet, packet_len, true); // Allow non-compound RTCP RTCPHelp::RTCPPacketInformation rtcpPacketInformation; EXPECT_EQ(0, rtcp_receiver_->IncomingRTCPPacket(rtcpPacketInformation, &rtcpParser)); rtcp_receiver_->TriggerCallbacksFromRTCPPacket(rtcpPacketInformation); // The NACK list is on purpose not copied below as it isn't needed by the // test. rtcp_packet_info_.rtcpPacketTypeFlags = rtcpPacketInformation.rtcpPacketTypeFlags; rtcp_packet_info_.remoteSSRC = rtcpPacketInformation.remoteSSRC; rtcp_packet_info_.applicationSubType = rtcpPacketInformation.applicationSubType; rtcp_packet_info_.applicationName = rtcpPacketInformation.applicationName; rtcp_packet_info_.report_blocks = rtcpPacketInformation.report_blocks; rtcp_packet_info_.rtt = rtcpPacketInformation.rtt; rtcp_packet_info_.interArrivalJitter = rtcpPacketInformation.interArrivalJitter; rtcp_packet_info_.sliPictureId = rtcpPacketInformation.sliPictureId; rtcp_packet_info_.rpsiPictureId = rtcpPacketInformation.rpsiPictureId; rtcp_packet_info_.receiverEstimatedMaxBitrate = rtcpPacketInformation.receiverEstimatedMaxBitrate; rtcp_packet_info_.ntp_secs = rtcpPacketInformation.ntp_secs; rtcp_packet_info_.ntp_frac = rtcpPacketInformation.ntp_frac; rtcp_packet_info_.rtp_timestamp = rtcpPacketInformation.rtp_timestamp; rtcp_packet_info_.xr_dlrr_item = rtcpPacketInformation.xr_dlrr_item; if (rtcpPacketInformation.VoIPMetric) { rtcp_packet_info_.AddVoIPMetric(rtcpPacketInformation.VoIPMetric); } return 0; } OverUseDetectorOptions over_use_detector_options_; SimulatedClock system_clock_; ModuleRtpRtcpImpl* rtp_rtcp_impl_; RTCPReceiver* rtcp_receiver_; TestTransport* test_transport_; RTCPHelp::RTCPPacketInformation rtcp_packet_info_; MockRemoteBitrateObserver remote_bitrate_observer_; scoped_ptr remote_bitrate_estimator_; }; TEST_F(RtcpReceiverTest, BrokenPacketIsIgnored) { const uint8_t bad_packet[] = {0, 0, 0, 0}; EXPECT_EQ(0, InjectRtcpPacket(bad_packet, sizeof(bad_packet))); EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); } TEST_F(RtcpReceiverTest, InjectSrPacket) { const uint32_t kSenderSsrc = 0x10203; PacketBuilder p; p.AddSrPacket(kSenderSsrc); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); // The parser will note the remote SSRC on a SR from other than his // expected peer, but will not flag that he's gotten a packet. EXPECT_EQ(kSenderSsrc, rtcp_packet_info_.remoteSSRC); EXPECT_EQ(0U, kRtcpSr & rtcp_packet_info_.rtcpPacketTypeFlags); } TEST_F(RtcpReceiverTest, XrPacketWithZeroReportBlocksIgnored) { PacketBuilder p; p.AddXrHeader(0x2345); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); } TEST_F(RtcpReceiverTest, InjectXrVoipPacket) { const uint32_t kSourceSsrc = 0x123456; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); const uint8_t kLossRate = 123; PacketBuilder p; p.AddXrHeader(0x2345); p.AddXrVoipBlock(kSourceSsrc, kLossRate); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); ASSERT_TRUE(rtcp_packet_info_.VoIPMetric != NULL); EXPECT_EQ(kLossRate, rtcp_packet_info_.VoIPMetric->lossRate); EXPECT_EQ(kRtcpXrVoipMetric, rtcp_packet_info_.rtcpPacketTypeFlags); } TEST_F(RtcpReceiverTest, InjectXrReceiverReferenceTimePacket) { PacketBuilder p; p.AddXrHeader(0x2345); p.AddXrReceiverReferenceTimeBlock(0x10203, 0x40506); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(kRtcpXrReceiverReferenceTime, rtcp_packet_info_.rtcpPacketTypeFlags); } TEST_F(RtcpReceiverTest, InjectXrDlrrPacketWithNoSubBlock) { const uint32_t kSourceSsrc = 0x123456; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); std::vector remote_ssrcs; PacketBuilder p; p.AddXrHeader(0x2345); p.AddXrDlrrBlock(remote_ssrcs); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); EXPECT_FALSE(rtcp_packet_info_.xr_dlrr_item); } TEST_F(RtcpReceiverTest, XrDlrrPacketNotToUsIgnored) { const uint32_t kSourceSsrc = 0x123456; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); std::vector remote_ssrcs; remote_ssrcs.push_back(kSourceSsrc+1); PacketBuilder p; p.AddXrHeader(0x2345); p.AddXrDlrrBlock(remote_ssrcs); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); EXPECT_FALSE(rtcp_packet_info_.xr_dlrr_item); } TEST_F(RtcpReceiverTest, InjectXrDlrrPacketWithSubBlock) { const uint32_t kSourceSsrc = 0x123456; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); std::vector remote_ssrcs; remote_ssrcs.push_back(kSourceSsrc); PacketBuilder p; p.AddXrHeader(0x2345); p.AddXrDlrrBlock(remote_ssrcs); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); // The parser should note the DLRR report block item, but not flag the packet // since the RTT is not estimated. EXPECT_TRUE(rtcp_packet_info_.xr_dlrr_item); } TEST_F(RtcpReceiverTest, InjectXrDlrrPacketWithMultipleSubBlocks) { const uint32_t kSourceSsrc = 0x123456; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); std::vector remote_ssrcs; remote_ssrcs.push_back(kSourceSsrc+2); remote_ssrcs.push_back(kSourceSsrc+1); remote_ssrcs.push_back(kSourceSsrc); PacketBuilder p; p.AddXrHeader(0x2345); p.AddXrDlrrBlock(remote_ssrcs); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); // The parser should note the DLRR report block item, but not flag the packet // since the RTT is not estimated. EXPECT_TRUE(rtcp_packet_info_.xr_dlrr_item); } TEST_F(RtcpReceiverTest, InjectXrPacketWithMultipleReportBlocks) { const uint8_t kLossRate = 123; const uint32_t kSourceSsrc = 0x123456; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); std::vector remote_ssrcs; remote_ssrcs.push_back(kSourceSsrc); PacketBuilder p; p.AddXrHeader(0x2345); p.AddXrDlrrBlock(remote_ssrcs); p.AddXrVoipBlock(kSourceSsrc, kLossRate); p.AddXrReceiverReferenceTimeBlock(0x10203, 0x40506); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(static_cast(kRtcpXrReceiverReferenceTime + kRtcpXrVoipMetric), rtcp_packet_info_.rtcpPacketTypeFlags); // The parser should note the DLRR report block item, but not flag the packet // since the RTT is not estimated. EXPECT_TRUE(rtcp_packet_info_.xr_dlrr_item); } TEST_F(RtcpReceiverTest, InjectXrPacketWithUnknownReportBlock) { const uint8_t kLossRate = 123; const uint32_t kSourceSsrc = 0x123456; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); std::vector remote_ssrcs; remote_ssrcs.push_back(kSourceSsrc); PacketBuilder p; p.AddXrHeader(0x2345); p.AddXrVoipBlock(kSourceSsrc, kLossRate); p.AddXrUnknownBlock(); p.AddXrReceiverReferenceTimeBlock(0x10203, 0x40506); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(static_cast(kRtcpXrReceiverReferenceTime + kRtcpXrVoipMetric), rtcp_packet_info_.rtcpPacketTypeFlags); } TEST(RtcpUtilityTest, MidNtp) { const uint32_t kNtpSec = 0x12345678; const uint32_t kNtpFrac = 0x23456789; const uint32_t kNtpMid = 0x56782345; EXPECT_EQ(kNtpMid, RTCPUtility::MidNtp(kNtpSec, kNtpFrac)); } TEST_F(RtcpReceiverTest, TestXrRrRttInitiallyFalse) { uint16_t rtt_ms; EXPECT_FALSE(rtcp_receiver_->GetAndResetXrRrRtt(&rtt_ms)); } TEST_F(RtcpReceiverTest, LastReceivedXrReferenceTimeInfoInitiallyFalse) { RtcpReceiveTimeInfo info; EXPECT_FALSE(rtcp_receiver_->LastReceivedXrReferenceTimeInfo(&info)); } TEST_F(RtcpReceiverTest, GetLastReceivedXrReferenceTimeInfo) { const uint32_t kSenderSsrc = 0x123456; const uint32_t kNtpSec = 0x10203; const uint32_t kNtpFrac = 0x40506; const uint32_t kNtpMid = RTCPUtility::MidNtp(kNtpSec, kNtpFrac); PacketBuilder p; p.AddXrHeader(kSenderSsrc); p.AddXrReceiverReferenceTimeBlock(kNtpSec, kNtpFrac); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(kRtcpXrReceiverReferenceTime, rtcp_packet_info_.rtcpPacketTypeFlags); RtcpReceiveTimeInfo info; EXPECT_TRUE(rtcp_receiver_->LastReceivedXrReferenceTimeInfo(&info)); EXPECT_EQ(kSenderSsrc, info.sourceSSRC); EXPECT_EQ(kNtpMid, info.lastRR); EXPECT_EQ(0U, info.delaySinceLastRR); system_clock_.AdvanceTimeMilliseconds(1000); EXPECT_TRUE(rtcp_receiver_->LastReceivedXrReferenceTimeInfo(&info)); EXPECT_EQ(65536U, info.delaySinceLastRR); } TEST_F(RtcpReceiverTest, ReceiveReportTimeout) { const uint32_t kSenderSsrc = 0x10203; const uint32_t kSourceSsrc = 0x40506; const int64_t kRtcpIntervalMs = 1000; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); uint32_t sequence_number = 1234; system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs); // No RR received, shouldn't trigger a timeout. EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs)); EXPECT_FALSE(rtcp_receiver_->RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); // Add a RR and advance the clock just enough to not trigger a timeout. PacketBuilder p1; p1.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0, 0); EXPECT_EQ(0, InjectRtcpPacket(p1.packet(), p1.length())); system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs - 1); EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs)); EXPECT_FALSE(rtcp_receiver_->RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); // Add a RR with the same extended max as the previous RR to trigger a // sequence number timeout, but not a RR timeout. PacketBuilder p2; p2.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0, 0); EXPECT_EQ(0, InjectRtcpPacket(p2.packet(), p2.length())); system_clock_.AdvanceTimeMilliseconds(2); EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs)); EXPECT_TRUE(rtcp_receiver_->RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); // Advance clock enough to trigger an RR timeout too. system_clock_.AdvanceTimeMilliseconds(3 * kRtcpIntervalMs); EXPECT_TRUE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs)); // We should only get one timeout even though we still haven't received a new // RR. EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs)); EXPECT_FALSE(rtcp_receiver_->RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); // Add a new RR with increase sequence number to reset timers. PacketBuilder p3; sequence_number++; p2.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0, 0); EXPECT_EQ(0, InjectRtcpPacket(p2.packet(), p2.length())); EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs)); EXPECT_FALSE(rtcp_receiver_->RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); // Verify we can get a timeout again once we've received new RR. system_clock_.AdvanceTimeMilliseconds(2 * kRtcpIntervalMs); PacketBuilder p4; p4.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, 0, 0, 0); EXPECT_EQ(0, InjectRtcpPacket(p4.packet(), p4.length())); system_clock_.AdvanceTimeMilliseconds(kRtcpIntervalMs + 1); EXPECT_FALSE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs)); EXPECT_TRUE(rtcp_receiver_->RtcpRrSequenceNumberTimeout(kRtcpIntervalMs)); system_clock_.AdvanceTimeMilliseconds(2 * kRtcpIntervalMs); EXPECT_TRUE(rtcp_receiver_->RtcpRrTimeout(kRtcpIntervalMs)); } TEST_F(RtcpReceiverTest, TmmbrReceivedWithNoIncomingPacket) { // This call is expected to fail because no data has arrived. EXPECT_EQ(-1, rtcp_receiver_->TMMBRReceived(0, 0, NULL)); } TEST_F(RtcpReceiverTest, TwoReportBlocks) { const uint32_t kSenderSsrc = 0x10203; const int kNumSsrcs = 2; const uint32_t kSourceSsrcs[kNumSsrcs] = {0x40506, 0x50607}; uint32_t sequence_numbers[kNumSsrcs] = {10, 12423}; std::set ssrcs(kSourceSsrcs, kSourceSsrcs + kNumSsrcs); rtcp_receiver_->SetSsrcs(kSourceSsrcs[0], ssrcs); PacketBuilder packet; std::list report_blocks; report_blocks.push_back(PacketBuilder::ReportBlock( kSourceSsrcs[0], sequence_numbers[0], 10, 5, 0)); report_blocks.push_back(PacketBuilder::ReportBlock( kSourceSsrcs[1], sequence_numbers[1], 0, 0, 0)); packet.AddRrPacketMultipleReportBlocks(kSenderSsrc, report_blocks); EXPECT_EQ(0, InjectRtcpPacket(packet.packet(), packet.length())); ASSERT_EQ(2u, rtcp_packet_info_.report_blocks.size()); EXPECT_EQ(10, rtcp_packet_info_.report_blocks.front().fractionLost); EXPECT_EQ(0, rtcp_packet_info_.report_blocks.back().fractionLost); PacketBuilder packet2; report_blocks.clear(); report_blocks.push_back(PacketBuilder::ReportBlock( kSourceSsrcs[0], sequence_numbers[0], 0, 0, 0)); report_blocks.push_back(PacketBuilder::ReportBlock( kSourceSsrcs[1], sequence_numbers[1], 20, 10, 0)); packet2.AddRrPacketMultipleReportBlocks(kSenderSsrc, report_blocks); EXPECT_EQ(0, InjectRtcpPacket(packet2.packet(), packet2.length())); ASSERT_EQ(2u, rtcp_packet_info_.report_blocks.size()); EXPECT_EQ(0, rtcp_packet_info_.report_blocks.front().fractionLost); EXPECT_EQ(20, rtcp_packet_info_.report_blocks.back().fractionLost); } TEST_F(RtcpReceiverTest, TmmbrPacketAccepted) { const uint32_t kMediaFlowSsrc = 0x2040608; const uint32_t kSenderSsrc = 0x10203; const uint32_t kMediaRecipientSsrc = 0x101; std::set ssrcs; ssrcs.insert(kMediaFlowSsrc); // Matches "media source" above. rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs); PacketBuilder p; p.AddSrPacket(kSenderSsrc); // TMMBR packet. p.AddRtcpHeader(205, 3); p.Add32(kSenderSsrc); p.Add32(kMediaRecipientSsrc); p.Add32(kMediaFlowSsrc); p.AddTmmbrBandwidth(30000, 0, 0); // 30 Kbits/sec bandwidth, no overhead. EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(1, rtcp_receiver_->TMMBRReceived(0, 0, NULL)); TMMBRSet candidate_set; candidate_set.VerifyAndAllocateSet(1); EXPECT_EQ(1, rtcp_receiver_->TMMBRReceived(1, 0, &candidate_set)); EXPECT_LT(0U, candidate_set.Tmmbr(0)); EXPECT_EQ(kMediaRecipientSsrc, candidate_set.Ssrc(0)); } TEST_F(RtcpReceiverTest, TmmbrPacketNotForUsIgnored) { const uint32_t kMediaFlowSsrc = 0x2040608; const uint32_t kSenderSsrc = 0x10203; const uint32_t kMediaRecipientSsrc = 0x101; const uint32_t kOtherMediaFlowSsrc = 0x9999; PacketBuilder p; p.AddSrPacket(kSenderSsrc); // TMMBR packet. p.AddRtcpHeader(205, 3); p.Add32(kSenderSsrc); p.Add32(kMediaRecipientSsrc); p.Add32(kOtherMediaFlowSsrc); // This SSRC is not what we're sending. p.AddTmmbrBandwidth(30000, 0, 0); std::set ssrcs; ssrcs.insert(kMediaFlowSsrc); rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs); EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(0, rtcp_receiver_->TMMBRReceived(0, 0, NULL)); } TEST_F(RtcpReceiverTest, TmmbrPacketZeroRateIgnored) { const uint32_t kMediaFlowSsrc = 0x2040608; const uint32_t kSenderSsrc = 0x10203; const uint32_t kMediaRecipientSsrc = 0x101; std::set ssrcs; ssrcs.insert(kMediaFlowSsrc); // Matches "media source" above. rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs); PacketBuilder p; p.AddSrPacket(kSenderSsrc); // TMMBR packet. p.AddRtcpHeader(205, 3); p.Add32(kSenderSsrc); p.Add32(kMediaRecipientSsrc); p.Add32(kMediaFlowSsrc); p.AddTmmbrBandwidth(0, 0, 0); // Rate zero. EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); EXPECT_EQ(0, rtcp_receiver_->TMMBRReceived(0, 0, NULL)); } TEST_F(RtcpReceiverTest, TmmbrThreeConstraintsTimeOut) { const uint32_t kMediaFlowSsrc = 0x2040608; const uint32_t kSenderSsrc = 0x10203; const uint32_t kMediaRecipientSsrc = 0x101; std::set ssrcs; ssrcs.insert(kMediaFlowSsrc); // Matches "media source" above. rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs); // Inject 3 packets "from" kMediaRecipientSsrc, Ssrc+1, Ssrc+2. // The times of arrival are starttime + 0, starttime + 5 and starttime + 10. for (uint32_t ssrc = kMediaRecipientSsrc; ssrc < kMediaRecipientSsrc+3; ++ssrc) { PacketBuilder p; p.AddSrPacket(kSenderSsrc); // TMMBR packet. p.AddRtcpHeader(205, 3); p.Add32(kSenderSsrc); p.Add32(ssrc); p.Add32(kMediaFlowSsrc); p.AddTmmbrBandwidth(30000, 0, 0); // 30 Kbits/sec bandwidth, no overhead. EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length())); // 5 seconds between each packet. system_clock_.AdvanceTimeMilliseconds(5000); } // It is now starttime+15. EXPECT_EQ(3, rtcp_receiver_->TMMBRReceived(0, 0, NULL)); TMMBRSet candidate_set; candidate_set.VerifyAndAllocateSet(3); EXPECT_EQ(3, rtcp_receiver_->TMMBRReceived(3, 0, &candidate_set)); EXPECT_LT(0U, candidate_set.Tmmbr(0)); // We expect the timeout to be 25 seconds. Advance the clock by 12 // seconds, timing out the first packet. system_clock_.AdvanceTimeMilliseconds(12000); // Odd behaviour: Just counting them does not trigger the timeout. EXPECT_EQ(3, rtcp_receiver_->TMMBRReceived(0, 0, NULL)); // Odd behaviour: There's only one left after timeout, not 2. EXPECT_EQ(1, rtcp_receiver_->TMMBRReceived(3, 0, &candidate_set)); EXPECT_EQ(kMediaRecipientSsrc + 2, candidate_set.Ssrc(0)); } TEST_F(RtcpReceiverTest, Callbacks) { class RtcpCallbackImpl : public RtcpStatisticsCallback { public: RtcpCallbackImpl() : RtcpStatisticsCallback(), ssrc_(0) {} virtual ~RtcpCallbackImpl() {} virtual void StatisticsUpdated(const RtcpStatistics& statistics, uint32_t ssrc) { stats_ = statistics; ssrc_ = ssrc; } bool Matches(uint32_t ssrc, uint32_t extended_max, uint8_t fraction_loss, uint32_t cumulative_loss, uint32_t jitter) { return ssrc_ == ssrc && stats_.fraction_lost == fraction_loss && stats_.cumulative_lost == cumulative_loss && stats_.extended_max_sequence_number == extended_max && stats_.jitter == jitter; } RtcpStatistics stats_; uint32_t ssrc_; } callback; rtcp_receiver_->RegisterRtcpStatisticsCallback(&callback); const uint32_t kSenderSsrc = 0x10203; const uint32_t kSourceSsrc = 0x123456; const uint8_t fraction_loss = 3; const uint32_t cumulative_loss = 7; const uint32_t jitter = 9; uint32_t sequence_number = 1234; std::set ssrcs; ssrcs.insert(kSourceSsrc); rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); // First packet, all numbers should just propagate PacketBuilder p1; p1.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number, fraction_loss, cumulative_loss, jitter); EXPECT_EQ(0, InjectRtcpPacket(p1.packet(), p1.length())); EXPECT_TRUE(callback.Matches(kSourceSsrc, sequence_number, fraction_loss, cumulative_loss, jitter)); rtcp_receiver_->RegisterRtcpStatisticsCallback(NULL); // Add arbitrary numbers, callback should not be called (retain old values) PacketBuilder p2; p2.AddRrPacket(kSenderSsrc, kSourceSsrc, sequence_number + 1, 42, 137, 4711); EXPECT_EQ(0, InjectRtcpPacket(p2.packet(), p2.length())); EXPECT_TRUE(callback.Matches(kSourceSsrc, sequence_number, fraction_loss, cumulative_loss, jitter)); } } // Anonymous namespace } // namespace webrtc