
Since RTCP packets are delivered to both senders and receivers that correspond the receivers currently log that NACKed packets are missing, since they have no direct connection to the sending side or the RTP packet history. Also preventing triggering on SR requests and PLI/FIR. BUG= R=asapersson@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/45249004 Cr-Commit-Position: refs/heads/master@{#9071}
1039 lines
36 KiB
C++
1039 lines
36 KiB
C++
/*
|
|
* 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_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_(
|
|
RemoteBitrateEstimatorFactory().Create(
|
|
&remote_bitrate_observer_,
|
|
&system_clock_,
|
|
kMimdControl,
|
|
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);
|
|
rtcp::RawPacket p = sr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = sr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = rr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = rr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = rr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
|
|
rtcp::RawPacket p1 = rr1.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p1.buffer(), p1.buffer_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);
|
|
|
|
rtcp::RawPacket p2 = rr2.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p2.buffer(), p2.buffer_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);
|
|
|
|
rtcp::RawPacket p1 = rr1.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p1.buffer(), p1.buffer_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);
|
|
rtcp::RawPacket p2 = rr2.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p2.buffer(), p2.buffer_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);
|
|
rtcp::RawPacket p = rr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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;
|
|
rtcp::RawPacket p = ij.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_length()));
|
|
EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags);
|
|
}
|
|
|
|
TEST_F(RtcpReceiverTest, InjectIjWithOneItem) {
|
|
rtcp::Ij ij;
|
|
ij.WithJitterItem(0x11111111);
|
|
|
|
rtcp::RawPacket p = ij.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
|
|
rtcp::RawPacket p = app.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
|
|
rtcp::RawPacket p = app.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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");
|
|
|
|
rtcp::RawPacket p = sdes.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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");
|
|
|
|
rtcp::RawPacket p = sdes.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p2 = bye.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p2.buffer(), p2.buffer_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);
|
|
|
|
rtcp::RawPacket p1 = rr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p1.buffer(), p1.buffer_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);
|
|
rtcp::RawPacket p2 = bye.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p2.buffer(), p2.buffer_length()));
|
|
received_blocks.clear();
|
|
rtcp_receiver_->StatisticsReceived(&received_blocks);
|
|
EXPECT_TRUE(received_blocks.empty());
|
|
|
|
// Inject packet.
|
|
EXPECT_EQ(0, InjectRtcpPacket(p1.buffer(), p1.buffer_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);
|
|
rtcp::RawPacket p = pli.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = pli.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = fir.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = fir.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_length()));
|
|
EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags);
|
|
}
|
|
|
|
TEST_F(RtcpReceiverTest, InjectSliPacket) {
|
|
rtcp::Sli sli;
|
|
sli.WithPictureId(40);
|
|
rtcp::RawPacket p = sli.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
// Modify the DLRR block to have an unsupported block type, from 5 to 6.
|
|
uint8_t* buffer = const_cast<uint8_t*>(p.buffer());
|
|
EXPECT_EQ(5, buffer[20]);
|
|
buffer[20] = 6;
|
|
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = xr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p1 = rr1.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p1.buffer(), p1.buffer_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.buffer_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);
|
|
rtcp::RawPacket p2 = rr2.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p2.buffer(), p2.buffer_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.buffer_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);
|
|
rtcp::RawPacket p = sr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = sr.Build();
|
|
|
|
std::set<uint32_t> ssrcs;
|
|
ssrcs.insert(kMediaFlowSsrc);
|
|
rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs);
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = sr.Build();
|
|
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p = sr.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p.buffer(), p.buffer_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);
|
|
rtcp::RawPacket p1 = rr1.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p1.buffer(), p1.buffer_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);
|
|
rtcp::RawPacket p2 = rr2.Build();
|
|
EXPECT_EQ(0, InjectRtcpPacket(p2.buffer(), p2.buffer_length()));
|
|
EXPECT_TRUE(callback.Matches(kSourceSsrc, kSequenceNumber, kFractionLoss,
|
|
kCumulativeLoss, kJitter));
|
|
}
|
|
|
|
} // Anonymous namespace
|
|
|
|
} // namespace webrtc
|