|  | /* | 
|  | *  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/remote_bitrate_estimator_single_stream.h" | 
|  | #include "webrtc/modules/rtp_rtcp/source/rtcp_packet.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. | 
|  |  | 
|  | // 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; | 
|  | } | 
|  | int SendPacket(int /*ch*/, const void* /*data*/, size_t /*len*/) override { | 
|  | ADD_FAILURE();  // FAIL() gives a compile error. | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Injects an RTCP packet into the receiver. | 
|  | int SendRTCPPacket(int /* ch */, | 
|  | const void* packet, | 
|  | size_t packet_len) override { | 
|  | ADD_FAILURE(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int OnReceivedPayloadData(const uint8_t* payloadData, | 
|  | const size_t payloadSize, | 
|  | const WebRtcRTPHeader* rtpHeader) override { | 
|  | ADD_FAILURE(); | 
|  | return 0; | 
|  | } | 
|  | RTCPReceiver* rtcp_receiver_; | 
|  | }; | 
|  |  | 
|  | class RtcpReceiverTest : public ::testing::Test { | 
|  | protected: | 
|  | static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000; | 
|  |  | 
|  | RtcpReceiverTest() | 
|  | : over_use_detector_options_(), | 
|  | system_clock_(1335900000), | 
|  | remote_bitrate_observer_(), | 
|  | remote_bitrate_estimator_(new RemoteBitrateEstimatorSingleStream( | 
|  | &remote_bitrate_observer_, | 
|  | &system_clock_, | 
|  | kRemoteBitrateEstimatorMinBitrateBps)) { | 
|  | 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_, false, NULL, NULL, | 
|  | NULL, 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_.applicationLength = | 
|  | rtcpPacketInformation.applicationLength; | 
|  | 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_; | 
|  | rtc::scoped_ptr<RemoteBitrateEstimator> 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; | 
|  | rtcp::SenderReport sr; | 
|  | sr.From(kSenderSsrc); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->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, InjectSrPacketFromExpectedPeer) { | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | rtcp_receiver_->SetRemoteSSRC(kSenderSsrc); | 
|  | rtcp::SenderReport sr; | 
|  | sr.From(kSenderSsrc); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kSenderSsrc, rtcp_packet_info_.remoteSSRC); | 
|  | EXPECT_EQ(kRtcpSr, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectRrPacket) { | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | rtcp::ReceiverReport rr; | 
|  | rr.From(kSenderSsrc); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(rr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kSenderSsrc, rtcp_packet_info_.remoteSSRC); | 
|  | EXPECT_EQ(kRtcpRr, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | ASSERT_EQ(0u, rtcp_packet_info_.report_blocks.size()); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectRrPacketWithReportBlockNotToUsIgnored) { | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::ReportBlock rb; | 
|  | rb.To(kSourceSsrc + 1); | 
|  | rtcp::ReceiverReport rr; | 
|  | rr.From(kSenderSsrc); | 
|  | rr.WithReportBlock(rb); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(rr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kSenderSsrc, rtcp_packet_info_.remoteSSRC); | 
|  | EXPECT_EQ(kRtcpRr, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | ASSERT_EQ(0u, rtcp_packet_info_.report_blocks.size()); | 
|  |  | 
|  | std::vector<RTCPReportBlock> received_blocks; | 
|  | rtcp_receiver_->StatisticsReceived(&received_blocks); | 
|  | EXPECT_TRUE(received_blocks.empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectRrPacketWithOneReportBlock) { | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::ReportBlock rb; | 
|  | rb.To(kSourceSsrc); | 
|  | rtcp::ReceiverReport rr; | 
|  | rr.From(kSenderSsrc); | 
|  | rr.WithReportBlock(rb); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(rr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kSenderSsrc, rtcp_packet_info_.remoteSSRC); | 
|  | EXPECT_EQ(kRtcpRr, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | ASSERT_EQ(1u, rtcp_packet_info_.report_blocks.size()); | 
|  |  | 
|  | std::vector<RTCPReportBlock> received_blocks; | 
|  | rtcp_receiver_->StatisticsReceived(&received_blocks); | 
|  | EXPECT_EQ(1u, received_blocks.size()); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectRrPacketWithTwoReportBlocks) { | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | const uint32_t kSourceSsrcs[] = {0x40506, 0x50607}; | 
|  | const uint16_t kSequenceNumbers[] = {10, 12423}; | 
|  | const uint32_t kCumLost[] = {13, 555}; | 
|  | const uint8_t kFracLost[] = {20, 11}; | 
|  | const int kNumSsrcs = sizeof(kSourceSsrcs) / sizeof(kSourceSsrcs[0]); | 
|  |  | 
|  | std::set<uint32_t> ssrcs(kSourceSsrcs, kSourceSsrcs + kNumSsrcs); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrcs[0], ssrcs); | 
|  |  | 
|  | rtcp::ReportBlock rb1; | 
|  | rb1.To(kSourceSsrcs[0]); | 
|  | rb1.WithExtHighestSeqNum(kSequenceNumbers[0]); | 
|  | rb1.WithFractionLost(10); | 
|  | rb1.WithCumulativeLost(5); | 
|  |  | 
|  | rtcp::ReportBlock rb2; | 
|  | rb2.To(kSourceSsrcs[1]); | 
|  | rb2.WithExtHighestSeqNum(kSequenceNumbers[1]); | 
|  |  | 
|  | rtcp::ReceiverReport rr1; | 
|  | rr1.From(kSenderSsrc); | 
|  | rr1.WithReportBlock(rb1); | 
|  | rr1.WithReportBlock(rb2); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p1(rr1.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p1->Buffer(), p1->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); | 
|  |  | 
|  | rtcp::ReportBlock rb3; | 
|  | rb3.To(kSourceSsrcs[0]); | 
|  | rb3.WithExtHighestSeqNum(kSequenceNumbers[0]); | 
|  | rb3.WithFractionLost(kFracLost[0]); | 
|  | rb3.WithCumulativeLost(kCumLost[0]); | 
|  |  | 
|  | rtcp::ReportBlock rb4; | 
|  | rb4.To(kSourceSsrcs[1]); | 
|  | rb4.WithExtHighestSeqNum(kSequenceNumbers[1]); | 
|  | rb4.WithFractionLost(kFracLost[1]); | 
|  | rb4.WithCumulativeLost(kCumLost[1]); | 
|  |  | 
|  | rtcp::ReceiverReport rr2; | 
|  | rr2.From(kSenderSsrc); | 
|  | rr2.WithReportBlock(rb3); | 
|  | rr2.WithReportBlock(rb4); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p2(rr2.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p2->Buffer(), p2->Length())); | 
|  | ASSERT_EQ(2u, rtcp_packet_info_.report_blocks.size()); | 
|  | EXPECT_EQ(kFracLost[0], rtcp_packet_info_.report_blocks.front().fractionLost); | 
|  | EXPECT_EQ(kFracLost[1], rtcp_packet_info_.report_blocks.back().fractionLost); | 
|  |  | 
|  | std::vector<RTCPReportBlock> received_blocks; | 
|  | rtcp_receiver_->StatisticsReceived(&received_blocks); | 
|  | EXPECT_EQ(2u, received_blocks.size()); | 
|  | for (size_t i = 0; i < received_blocks.size(); ++i) { | 
|  | EXPECT_EQ(kSenderSsrc, received_blocks[i].remoteSSRC); | 
|  | EXPECT_EQ(kSourceSsrcs[i], received_blocks[i].sourceSSRC); | 
|  | EXPECT_EQ(kFracLost[i], received_blocks[i].fractionLost); | 
|  | EXPECT_EQ(kCumLost[i], received_blocks[i].cumulativeLost); | 
|  | EXPECT_EQ(kSequenceNumbers[i], received_blocks[i].extendedHighSeqNum); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectRrPacketsFromTwoRemoteSsrcs) { | 
|  | const uint32_t kSenderSsrc1 = 0x10203; | 
|  | const uint32_t kSenderSsrc2 = 0x20304; | 
|  | const uint32_t kSourceSsrcs[] = {0x40506, 0x50607}; | 
|  | const uint16_t kSequenceNumbers[] = {10, 12423}; | 
|  | const uint32_t kCumLost[] = {13, 555}; | 
|  | const uint8_t kFracLost[] = {20, 11}; | 
|  | const int kNumSsrcs = sizeof(kSourceSsrcs) / sizeof(kSourceSsrcs[0]); | 
|  |  | 
|  | std::set<uint32_t> ssrcs(kSourceSsrcs, kSourceSsrcs + kNumSsrcs); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrcs[0], ssrcs); | 
|  |  | 
|  | rtcp::ReportBlock rb1; | 
|  | rb1.To(kSourceSsrcs[0]); | 
|  | rb1.WithExtHighestSeqNum(kSequenceNumbers[0]); | 
|  | rb1.WithFractionLost(kFracLost[0]); | 
|  | rb1.WithCumulativeLost(kCumLost[0]); | 
|  | rtcp::ReceiverReport rr1; | 
|  | rr1.From(kSenderSsrc1); | 
|  | rr1.WithReportBlock(rb1); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p1(rr1.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p1->Buffer(), p1->Length())); | 
|  | ASSERT_EQ(1u, rtcp_packet_info_.report_blocks.size()); | 
|  | EXPECT_EQ(kFracLost[0], rtcp_packet_info_.report_blocks.front().fractionLost); | 
|  |  | 
|  | std::vector<RTCPReportBlock> received_blocks; | 
|  | rtcp_receiver_->StatisticsReceived(&received_blocks); | 
|  | EXPECT_EQ(1u, received_blocks.size()); | 
|  | EXPECT_EQ(kSenderSsrc1, received_blocks[0].remoteSSRC); | 
|  | EXPECT_EQ(kSourceSsrcs[0], received_blocks[0].sourceSSRC); | 
|  | EXPECT_EQ(kFracLost[0], received_blocks[0].fractionLost); | 
|  | EXPECT_EQ(kCumLost[0], received_blocks[0].cumulativeLost); | 
|  | EXPECT_EQ(kSequenceNumbers[0], received_blocks[0].extendedHighSeqNum); | 
|  |  | 
|  | rtcp::ReportBlock rb2; | 
|  | rb2.To(kSourceSsrcs[0]); | 
|  | rb2.WithExtHighestSeqNum(kSequenceNumbers[1]); | 
|  | rb2.WithFractionLost(kFracLost[1]); | 
|  | rb2.WithCumulativeLost(kCumLost[1]); | 
|  | rtcp::ReceiverReport rr2; | 
|  | rr2.From(kSenderSsrc2); | 
|  | rr2.WithReportBlock(rb2); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p2(rr2.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p2->Buffer(), p2->Length())); | 
|  | ASSERT_EQ(1u, rtcp_packet_info_.report_blocks.size()); | 
|  | EXPECT_EQ(kFracLost[1], rtcp_packet_info_.report_blocks.front().fractionLost); | 
|  |  | 
|  | received_blocks.clear(); | 
|  | rtcp_receiver_->StatisticsReceived(&received_blocks); | 
|  | ASSERT_EQ(2u, received_blocks.size()); | 
|  | EXPECT_EQ(kSenderSsrc1, received_blocks[0].remoteSSRC); | 
|  | EXPECT_EQ(kSenderSsrc2, received_blocks[1].remoteSSRC); | 
|  | for (size_t i = 0; i < received_blocks.size(); ++i) { | 
|  | EXPECT_EQ(kSourceSsrcs[0], received_blocks[i].sourceSSRC); | 
|  | EXPECT_EQ(kFracLost[i], received_blocks[i].fractionLost); | 
|  | EXPECT_EQ(kCumLost[i], received_blocks[i].cumulativeLost); | 
|  | EXPECT_EQ(kSequenceNumbers[i], received_blocks[i].extendedHighSeqNum); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, GetRtt) { | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | // No report block received. | 
|  | EXPECT_EQ(-1, rtcp_receiver_->RTT(kSenderSsrc, NULL, NULL, NULL, NULL)); | 
|  |  | 
|  | rtcp::ReportBlock rb; | 
|  | rb.To(kSourceSsrc); | 
|  | rtcp::ReceiverReport rr; | 
|  | rr.From(kSenderSsrc); | 
|  | rr.WithReportBlock(rb); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(rr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kSenderSsrc, rtcp_packet_info_.remoteSSRC); | 
|  | EXPECT_EQ(kRtcpRr, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | EXPECT_EQ(1u, rtcp_packet_info_.report_blocks.size()); | 
|  | EXPECT_EQ(0, rtcp_receiver_->RTT(kSenderSsrc, NULL, NULL, NULL, NULL)); | 
|  |  | 
|  | // Report block not received. | 
|  | EXPECT_EQ(-1, rtcp_receiver_->RTT(kSenderSsrc + 1, NULL, NULL, NULL, NULL)); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectIjWithNoItem) { | 
|  | rtcp::Ij ij; | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(ij.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectIjWithOneItem) { | 
|  | rtcp::Ij ij; | 
|  | ij.WithJitterItem(0x11111111); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(ij.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kRtcpTransmissionTimeOffset, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | EXPECT_EQ(0x11111111U, rtcp_packet_info_.interArrivalJitter); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectAppWithNoData) { | 
|  | rtcp::App app; | 
|  | app.WithSubType(30); | 
|  | uint32_t name = 'n' << 24; | 
|  | name += 'a' << 16; | 
|  | name += 'm' << 8; | 
|  | name += 'e'; | 
|  | app.WithName(name); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(app.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kRtcpApp, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | EXPECT_EQ(30, rtcp_packet_info_.applicationSubType); | 
|  | EXPECT_EQ(name, rtcp_packet_info_.applicationName); | 
|  | EXPECT_EQ(0, rtcp_packet_info_.applicationLength); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectAppWithData) { | 
|  | rtcp::App app; | 
|  | app.WithSubType(30); | 
|  | uint32_t name = 'n' << 24; | 
|  | name += 'a' << 16; | 
|  | name += 'm' << 8; | 
|  | name += 'e'; | 
|  | app.WithName(name); | 
|  | const char kData[] = {'t', 'e', 's', 't', 'd', 'a', 't', 'a'}; | 
|  | const size_t kDataLength = sizeof(kData) / sizeof(kData[0]); | 
|  | app.WithData((const uint8_t*)kData, kDataLength); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(app.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kRtcpApp, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | EXPECT_EQ(30, rtcp_packet_info_.applicationSubType); | 
|  | EXPECT_EQ(name, rtcp_packet_info_.applicationName); | 
|  | EXPECT_EQ(kDataLength, rtcp_packet_info_.applicationLength); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectSdesWithOneChunk) { | 
|  | const uint32_t kSenderSsrc = 0x123456; | 
|  | rtcp::Sdes sdes; | 
|  | sdes.WithCName(kSenderSsrc, "alice@host"); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sdes.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | char cName[RTCP_CNAME_SIZE]; | 
|  | EXPECT_EQ(0, rtcp_receiver_->CNAME(kSenderSsrc, cName)); | 
|  | EXPECT_EQ(0, strncmp(cName, "alice@host", RTCP_CNAME_SIZE)); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectByePacket_RemovesCname) { | 
|  | const uint32_t kSenderSsrc = 0x123456; | 
|  | rtcp::Sdes sdes; | 
|  | sdes.WithCName(kSenderSsrc, "alice@host"); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sdes.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | char cName[RTCP_CNAME_SIZE]; | 
|  | EXPECT_EQ(0, rtcp_receiver_->CNAME(kSenderSsrc, cName)); | 
|  |  | 
|  | // Verify that BYE removes the CNAME. | 
|  | rtcp::Bye bye; | 
|  | bye.From(kSenderSsrc); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p2(bye.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p2->Buffer(), p2->Length())); | 
|  | EXPECT_EQ(-1, rtcp_receiver_->CNAME(kSenderSsrc, cName)); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectByePacket_RemovesReportBlocks) { | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | const uint32_t kSourceSsrcs[] = {0x40506, 0x50607}; | 
|  | const int kNumSsrcs = sizeof(kSourceSsrcs) / sizeof(kSourceSsrcs[0]); | 
|  |  | 
|  | std::set<uint32_t> ssrcs(kSourceSsrcs, kSourceSsrcs + kNumSsrcs); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrcs[0], ssrcs); | 
|  |  | 
|  | rtcp::ReportBlock rb1; | 
|  | rb1.To(kSourceSsrcs[0]); | 
|  | rtcp::ReportBlock rb2; | 
|  | rb2.To(kSourceSsrcs[1]); | 
|  | rtcp::ReceiverReport rr; | 
|  | rr.From(kSenderSsrc); | 
|  | rr.WithReportBlock(rb1); | 
|  | rr.WithReportBlock(rb2); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p1(rr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p1->Buffer(), p1->Length())); | 
|  | ASSERT_EQ(2u, rtcp_packet_info_.report_blocks.size()); | 
|  | std::vector<RTCPReportBlock> received_blocks; | 
|  | rtcp_receiver_->StatisticsReceived(&received_blocks); | 
|  | EXPECT_EQ(2u, received_blocks.size()); | 
|  |  | 
|  | // Verify that BYE removes the report blocks. | 
|  | rtcp::Bye bye; | 
|  | bye.From(kSenderSsrc); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p2(bye.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p2->Buffer(), p2->Length())); | 
|  | received_blocks.clear(); | 
|  | rtcp_receiver_->StatisticsReceived(&received_blocks); | 
|  | EXPECT_TRUE(received_blocks.empty()); | 
|  |  | 
|  | // Inject packet. | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p1->Buffer(), p1->Length())); | 
|  | ASSERT_EQ(2u, rtcp_packet_info_.report_blocks.size()); | 
|  | received_blocks.clear(); | 
|  | rtcp_receiver_->StatisticsReceived(&received_blocks); | 
|  | EXPECT_EQ(2u, received_blocks.size()); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectPliPacket) { | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Pli pli; | 
|  | pli.To(kSourceSsrc); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(pli.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kRtcpPli, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, PliPacketNotToUsIgnored) { | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Pli pli; | 
|  | pli.To(kSourceSsrc + 1); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(pli.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectFirPacket) { | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Fir fir; | 
|  | fir.To(kSourceSsrc); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(fir.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kRtcpFir, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, FirPacketNotToUsIgnored) { | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Fir fir; | 
|  | fir.To(kSourceSsrc + 1); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(fir.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectSliPacket) { | 
|  | rtcp::Sli sli; | 
|  | sli.WithPictureId(40); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sli.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kRtcpSli, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | EXPECT_EQ(40, rtcp_packet_info_.sliPictureId); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, XrPacketWithZeroReportBlocksIgnored) { | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectXrVoipPacket) { | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | const uint8_t kLossRate = 123; | 
|  | rtcp::VoipMetric voip_metric; | 
|  | voip_metric.To(kSourceSsrc); | 
|  | voip_metric.LossRate(kLossRate); | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | xr.WithVoipMetric(&voip_metric); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->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, XrVoipPacketNotToUsIgnored) { | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::VoipMetric voip_metric; | 
|  | voip_metric.To(kSourceSsrc + 1); | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | xr.WithVoipMetric(&voip_metric); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, InjectXrReceiverReferenceTimePacket) { | 
|  | rtcp::Rrtr rrtr; | 
|  | rrtr.WithNtpSec(0x10203); | 
|  | rrtr.WithNtpFrac(0x40506); | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | xr.WithRrtr(&rrtr); | 
|  |  | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(kRtcpXrReceiverReferenceTime, | 
|  | rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, XrDlrrPacketNotToUsIgnored) { | 
|  | const uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Dlrr dlrr; | 
|  | dlrr.WithDlrrItem(kSourceSsrc + 1, 0x12345, 0x67890); | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | xr.WithDlrr(&dlrr); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->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<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Dlrr dlrr; | 
|  | dlrr.WithDlrrItem(kSourceSsrc, 0x12345, 0x67890); | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | xr.WithDlrr(&dlrr); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->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<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Dlrr dlrr; | 
|  | dlrr.WithDlrrItem(kSourceSsrc + 1, 0x12345, 0x67890); | 
|  | dlrr.WithDlrrItem(kSourceSsrc + 2, 0x12345, 0x67890); | 
|  | dlrr.WithDlrrItem(kSourceSsrc,     0x12345, 0x67890); | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | xr.WithDlrr(&dlrr); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->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 uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Rrtr rrtr; | 
|  | rtcp::Dlrr dlrr; | 
|  | dlrr.WithDlrrItem(kSourceSsrc, 0x12345, 0x67890); | 
|  | rtcp::VoipMetric metric; | 
|  | metric.To(kSourceSsrc); | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | xr.WithRrtr(&rrtr); | 
|  | xr.WithDlrr(&dlrr); | 
|  | xr.WithVoipMetric(&metric); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(static_cast<unsigned int>(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 uint32_t kSourceSsrc = 0x123456; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  | std::vector<uint32_t> remote_ssrcs; | 
|  | remote_ssrcs.push_back(kSourceSsrc); | 
|  |  | 
|  | rtcp::Rrtr rrtr; | 
|  | rtcp::Dlrr dlrr; | 
|  | dlrr.WithDlrrItem(kSourceSsrc, 0x12345, 0x67890); | 
|  | rtcp::VoipMetric metric; | 
|  | metric.To(kSourceSsrc); | 
|  | rtcp::Xr xr; | 
|  | xr.From(0x2345); | 
|  | xr.WithRrtr(&rrtr); | 
|  | xr.WithDlrr(&dlrr); | 
|  | xr.WithVoipMetric(&metric); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | // Modify the DLRR block to have an unsupported block type, from 5 to 6. | 
|  | uint8_t* buffer = const_cast<uint8_t*>(packet->Buffer()); | 
|  | EXPECT_EQ(5, buffer[20]); | 
|  | buffer[20] = 6; | 
|  |  | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(static_cast<unsigned int>(kRtcpXrReceiverReferenceTime + | 
|  | kRtcpXrVoipMetric), | 
|  | rtcp_packet_info_.rtcpPacketTypeFlags); | 
|  | EXPECT_FALSE(rtcp_packet_info_.xr_dlrr_item); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, TestXrRrRttInitiallyFalse) { | 
|  | int64_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); | 
|  |  | 
|  | rtcp::Rrtr rrtr; | 
|  | rrtr.WithNtpSec(kNtpSec); | 
|  | rrtr.WithNtpFrac(kNtpFrac); | 
|  | rtcp::Xr xr; | 
|  | xr.From(kSenderSsrc); | 
|  | xr.WithRrtr(&rrtr); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->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<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | const uint16_t kSequenceNumber = 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. | 
|  | rtcp::ReportBlock rb1; | 
|  | rb1.To(kSourceSsrc); | 
|  | rb1.WithExtHighestSeqNum(kSequenceNumber); | 
|  | rtcp::ReceiverReport rr1; | 
|  | rr1.From(kSenderSsrc); | 
|  | rr1.WithReportBlock(rb1); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p1(rr1.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p1->Buffer(), 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. | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p1->Buffer(), p1->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. | 
|  | rtcp::ReportBlock rb2; | 
|  | rb2.To(kSourceSsrc); | 
|  | rb2.WithExtHighestSeqNum(kSequenceNumber + 1); | 
|  | rtcp::ReceiverReport rr2; | 
|  | rr2.From(kSenderSsrc); | 
|  | rr2.WithReportBlock(rb2); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p2(rr2.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p2->Buffer(), 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); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p2->Buffer(), p2->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, TmmbrPacketAccepted) { | 
|  | const uint32_t kMediaFlowSsrc = 0x2040608; | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kMediaFlowSsrc);  // Matches "media source" above. | 
|  | rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Tmmbr tmmbr; | 
|  | tmmbr.From(kSenderSsrc); | 
|  | tmmbr.To(kMediaFlowSsrc); | 
|  | tmmbr.WithBitrateKbps(30); | 
|  |  | 
|  | rtcp::SenderReport sr; | 
|  | sr.From(kSenderSsrc); | 
|  | sr.Append(&tmmbr); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->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(kSenderSsrc, candidate_set.Ssrc(0)); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, TmmbrPacketNotForUsIgnored) { | 
|  | const uint32_t kMediaFlowSsrc = 0x2040608; | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  |  | 
|  | rtcp::Tmmbr tmmbr; | 
|  | tmmbr.From(kSenderSsrc); | 
|  | tmmbr.To(kMediaFlowSsrc + 1);  // This SSRC is not what we are sending. | 
|  | tmmbr.WithBitrateKbps(30); | 
|  |  | 
|  | rtcp::SenderReport sr; | 
|  | sr.From(kSenderSsrc); | 
|  | sr.Append(&tmmbr); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sr.Build()); | 
|  |  | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kMediaFlowSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(0, rtcp_receiver_->TMMBRReceived(0, 0, NULL)); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, TmmbrPacketZeroRateIgnored) { | 
|  | const uint32_t kMediaFlowSsrc = 0x2040608; | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kMediaFlowSsrc);  // Matches "media source" above. | 
|  | rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs); | 
|  |  | 
|  | rtcp::Tmmbr tmmbr; | 
|  | tmmbr.From(kSenderSsrc); | 
|  | tmmbr.To(kMediaFlowSsrc); | 
|  | tmmbr.WithBitrateKbps(0); | 
|  |  | 
|  | rtcp::SenderReport sr; | 
|  | sr.From(kSenderSsrc); | 
|  | sr.Append(&tmmbr); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sr.Build()); | 
|  |  | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); | 
|  | EXPECT_EQ(0, rtcp_receiver_->TMMBRReceived(0, 0, NULL)); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, TmmbrThreeConstraintsTimeOut) { | 
|  | const uint32_t kMediaFlowSsrc = 0x2040608; | 
|  | const uint32_t kSenderSsrc = 0x10203; | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kMediaFlowSsrc);  // Matches "media source" above. | 
|  | rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs); | 
|  |  | 
|  | // Inject 3 packets "from" kSenderSsrc, kSenderSsrc+1, kSenderSsrc+2. | 
|  | // The times of arrival are starttime + 0, starttime + 5 and starttime + 10. | 
|  | for (uint32_t ssrc = kSenderSsrc; ssrc < kSenderSsrc + 3; ++ssrc) { | 
|  | rtcp::Tmmbr tmmbr; | 
|  | tmmbr.From(ssrc); | 
|  | tmmbr.To(kMediaFlowSsrc); | 
|  | tmmbr.WithBitrateKbps(30); | 
|  |  | 
|  | rtcp::SenderReport sr; | 
|  | sr.From(ssrc); | 
|  | sr.Append(&tmmbr); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> packet(sr.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->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)); | 
|  | EXPECT_EQ(2, rtcp_receiver_->TMMBRReceived(3, 0, &candidate_set)); | 
|  | EXPECT_EQ(kSenderSsrc + 1, candidate_set.Ssrc(0)); | 
|  | } | 
|  |  | 
|  | TEST_F(RtcpReceiverTest, Callbacks) { | 
|  | class RtcpCallbackImpl : public RtcpStatisticsCallback { | 
|  | public: | 
|  | RtcpCallbackImpl() : RtcpStatisticsCallback(), ssrc_(0) {} | 
|  | virtual ~RtcpCallbackImpl() {} | 
|  |  | 
|  | void StatisticsUpdated(const RtcpStatistics& statistics, | 
|  | uint32_t ssrc) override { | 
|  | stats_ = statistics; | 
|  | ssrc_ = ssrc; | 
|  | } | 
|  |  | 
|  | void CNameChanged(const char* cname, uint32_t ssrc) override {} | 
|  |  | 
|  | 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 kFractionLoss = 3; | 
|  | const uint32_t kCumulativeLoss = 7; | 
|  | const uint32_t kJitter = 9; | 
|  | const uint16_t kSequenceNumber = 1234; | 
|  |  | 
|  | std::set<uint32_t> ssrcs; | 
|  | ssrcs.insert(kSourceSsrc); | 
|  | rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); | 
|  |  | 
|  | // First packet, all numbers should just propagate. | 
|  | rtcp::ReportBlock rb1; | 
|  | rb1.To(kSourceSsrc); | 
|  | rb1.WithExtHighestSeqNum(kSequenceNumber); | 
|  | rb1.WithFractionLost(kFractionLoss); | 
|  | rb1.WithCumulativeLost(kCumulativeLoss); | 
|  | rb1.WithJitter(kJitter); | 
|  |  | 
|  | rtcp::ReceiverReport rr1; | 
|  | rr1.From(kSenderSsrc); | 
|  | rr1.WithReportBlock(rb1); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p1(rr1.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p1->Buffer(), p1->Length())); | 
|  | EXPECT_TRUE(callback.Matches(kSourceSsrc, kSequenceNumber, kFractionLoss, | 
|  | kCumulativeLoss, kJitter)); | 
|  |  | 
|  | rtcp_receiver_->RegisterRtcpStatisticsCallback(NULL); | 
|  |  | 
|  | // Add arbitrary numbers, callback should not be called (retain old values). | 
|  | rtcp::ReportBlock rb2; | 
|  | rb2.To(kSourceSsrc); | 
|  | rb2.WithExtHighestSeqNum(kSequenceNumber + 1); | 
|  | rb2.WithFractionLost(42); | 
|  | rb2.WithCumulativeLost(137); | 
|  | rb2.WithJitter(4711); | 
|  |  | 
|  | rtcp::ReceiverReport rr2; | 
|  | rr2.From(kSenderSsrc); | 
|  | rr2.WithReportBlock(rb2); | 
|  | rtc::scoped_ptr<rtcp::RawPacket> p2(rr2.Build()); | 
|  | EXPECT_EQ(0, InjectRtcpPacket(p2->Buffer(), p2->Length())); | 
|  | EXPECT_TRUE(callback.Matches(kSourceSsrc, kSequenceNumber, kFractionLoss, | 
|  | kCumulativeLoss, kJitter)); | 
|  | } | 
|  |  | 
|  | }  // Anonymous namespace | 
|  |  | 
|  | }  // namespace webrtc |