blob: a75410c6a2af3dd0f5d4f5483fa8d7db43aaae00 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/cast/net/rtcp/rtcp_builder.h"
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include "base/macros.h"
#include "base/test/simple_test_tick_clock.h"
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_defines.h"
#include "media/cast/net/pacing/paced_sender.h"
#include "media/cast/net/rtcp/receiver_rtcp_event_subscriber.h"
#include "media/cast/net/rtcp/rtcp_utility.h"
#include "media/cast/net/rtcp/test_rtcp_packet_builder.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media {
namespace cast {
namespace {
static const uint32_t kSendingSsrc = 0x12345678;
static const uint32_t kMediaSsrc = 0x87654321;
static const base::TimeDelta kDefaultDelay = base::Milliseconds(100);
RtcpReportBlock GetReportBlock() {
RtcpReportBlock report_block;
// Initialize remote_ssrc to a "clearly illegal" value.
report_block.remote_ssrc = 0xDEAD;
report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender.
report_block.fraction_lost = kLoss >> 24;
report_block.cumulative_lost = kLoss; // 24 bits valid.
report_block.extended_high_sequence_number = kExtendedMax;
report_block.jitter = kTestJitter;
report_block.last_sr = kLastSr;
report_block.delay_since_last_sr = kDelayLastSr;
return report_block;
}
} // namespace
class RtcpBuilderTest : public ::testing::Test {
protected:
RtcpBuilderTest()
: rtcp_builder_(new RtcpBuilder(kSendingSsrc)) {}
void ExpectPacketEQ(std::unique_ptr<Packet> golden_packet, PacketRef packet) {
int diffs = 0;
EXPECT_EQ(golden_packet->size(), packet->data.size());
if (golden_packet->size() == packet->data.size()) {
for (size_t x = 0; x < golden_packet->size(); x++) {
EXPECT_EQ((*golden_packet)[x], packet->data[x]) <<
"x = " << x << " / " << golden_packet->size();
if ((*golden_packet)[x] != packet->data[x]) {
if (++diffs > 5)
break;
}
}
}
}
static RtpTimeTicks test_rtp_timestamp() {
return RtpTimeTicks().Expand(kRtpTimestamp);
}
PacketRef BuildRtcpFromReceiver(
const RtcpReportBlock* report_block,
const RtcpReceiverReferenceTimeReport* rrtr,
const RtcpCastMessage* cast_message,
const RtcpPliMessage* pli_message,
const ReceiverRtcpEventSubscriber::RtcpEvents* rtcp_events,
base::TimeDelta target_delay) {
DCHECK(rtcp_builder_);
rtcp_builder_->Start();
if (report_block)
rtcp_builder_->AddRR(report_block);
if (rrtr)
rtcp_builder_->AddRrtr(*rrtr);
if (cast_message)
rtcp_builder_->AddCast(*cast_message, target_delay);
if (pli_message)
rtcp_builder_->AddPli(*pli_message);
if (rtcp_events)
rtcp_builder_->AddReceiverLog(*rtcp_events);
return rtcp_builder_->Finish();
}
std::unique_ptr<RtcpBuilder> rtcp_builder_;
DISALLOW_COPY_AND_ASSIGN(RtcpBuilderTest);
};
TEST_F(RtcpBuilderTest, RtcpReceiverReport) {
// Receiver report with report block.
TestRtcpPacketBuilder p2;
p2.AddRr(kSendingSsrc, 1);
p2.AddRb(kMediaSsrc);
RtcpReportBlock report_block = GetReportBlock();
ExpectPacketEQ(p2.GetPacket(),
BuildRtcpFromReceiver(&report_block, nullptr, nullptr, nullptr,
nullptr, kDefaultDelay));
}
TEST_F(RtcpBuilderTest, RtcpReceiverReportWithRrtr) {
// Receiver report with report block.
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddXrHeader(kSendingSsrc);
p.AddXrRrtrBlock();
RtcpReportBlock report_block = GetReportBlock();
RtcpReceiverReferenceTimeReport rrtr;
rrtr.ntp_seconds = kNtpHigh;
rrtr.ntp_fraction = kNtpLow;
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, &rrtr, nullptr, nullptr,
nullptr, kDefaultDelay));
}
TEST_F(RtcpBuilderTest, RtcpReceiverReportWithCast) {
// Receiver report with report block.
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay);
RtcpReportBlock report_block = GetReportBlock();
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id = FrameId::first() + kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets[FrameId::first() + kLostFrameId] =
missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message
.missing_frames_and_packets[FrameId::first() + kFrameIdWithLostPackets] =
missing_packets;
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, nullptr, &cast_message,
nullptr, nullptr, kDefaultDelay));
}
TEST_F(RtcpBuilderTest, RtcpReceiverReportWithRrtraAndCastMessage) {
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddXrHeader(kSendingSsrc);
p.AddXrRrtrBlock();
p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay);
RtcpReportBlock report_block = GetReportBlock();
RtcpReceiverReferenceTimeReport rrtr;
rrtr.ntp_seconds = kNtpHigh;
rrtr.ntp_fraction = kNtpLow;
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id = FrameId::first() + kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets[FrameId::first() + kLostFrameId] =
missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message
.missing_frames_and_packets[FrameId::first() + kFrameIdWithLostPackets] =
missing_packets;
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, &rrtr, &cast_message,
nullptr, nullptr, kDefaultDelay));
}
TEST_F(RtcpBuilderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) {
static const uint32_t kTimeBaseMs = 12345678;
static const uint32_t kTimeDelayMs = 10;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddXrHeader(kSendingSsrc);
p.AddXrRrtrBlock();
p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay);
RtcpReportBlock report_block = GetReportBlock();
RtcpReceiverReferenceTimeReport rrtr;
rrtr.ntp_seconds = kNtpHigh;
rrtr.ntp_fraction = kNtpLow;
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id = FrameId::first() + kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets[FrameId::first() + kLostFrameId] =
missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message
.missing_frames_and_packets[FrameId::first() + kFrameIdWithLostPackets] =
missing_packets;
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
ReceiverRtcpEventSubscriber::RtcpEvents rtcp_events;
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, &rrtr, &cast_message,
nullptr, &rtcp_events, kDefaultDelay));
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::Milliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
p.AddReceiverFrameLog(test_rtp_timestamp().lower_32_bits(), 2, kTimeBaseMs);
p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0);
p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs);
FrameEvent frame_event;
frame_event.rtp_timestamp = test_rtp_timestamp();
frame_event.type = FRAME_ACK_SENT;
frame_event.media_type = VIDEO_EVENT;
frame_event.timestamp = testing_clock.NowTicks();
event_subscriber.OnReceiveFrameEvent(frame_event);
testing_clock.Advance(base::Milliseconds(kTimeDelayMs));
PacketEvent packet_event;
packet_event.rtp_timestamp = test_rtp_timestamp();
packet_event.type = PACKET_RECEIVED;
packet_event.media_type = VIDEO_EVENT;
packet_event.timestamp = testing_clock.NowTicks();
packet_event.packet_id = kLostPacketId1;
event_subscriber.OnReceivePacketEvent(packet_event);
event_subscriber.GetRtcpEventsWithRedundancy(&rtcp_events);
EXPECT_EQ(2u, rtcp_events.size());
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, &rrtr, &cast_message,
nullptr, &rtcp_events, kDefaultDelay));
}
TEST_F(RtcpBuilderTest, RtcpReceiverReportWithOversizedFrameLog) {
static const uint32_t kTimeBaseMs = 12345678;
static const uint32_t kTimeDelayMs = 10;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
RtcpReportBlock report_block = GetReportBlock();
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::Milliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
int num_events = kMaxEventsPerRTCP;
EXPECT_LE(num_events, static_cast<int>(kRtcpMaxReceiverLogMessages));
p.AddReceiverFrameLog(
(test_rtp_timestamp() + RtpTimeDelta::FromTicks(2345)).lower_32_bits(),
num_events,
kTimeBaseMs);
for (int i = 0; i < num_events; i++) {
p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED,
static_cast<uint16_t>(kTimeDelayMs * i));
}
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
for (size_t i = 0; i < kRtcpMaxReceiverLogMessages; ++i) {
PacketEvent packet_event;
packet_event.rtp_timestamp =
test_rtp_timestamp() + RtpTimeDelta::FromTicks(2345);
packet_event.type = PACKET_RECEIVED;
packet_event.media_type = VIDEO_EVENT;
packet_event.timestamp = testing_clock.NowTicks();
packet_event.packet_id = kLostPacketId1;
event_subscriber.OnReceivePacketEvent(packet_event);
testing_clock.Advance(base::Milliseconds(kTimeDelayMs));
}
ReceiverRtcpEventSubscriber::RtcpEvents rtcp_events;
event_subscriber.GetRtcpEventsWithRedundancy(&rtcp_events);
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, nullptr, nullptr, nullptr,
&rtcp_events, kDefaultDelay));
}
TEST_F(RtcpBuilderTest, RtcpReceiverReportWithTooManyLogFrames) {
static const uint32_t kTimeBaseMs = 12345678;
static const uint32_t kTimeDelayMs = 10;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
RtcpReportBlock report_block = GetReportBlock();
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::Milliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
int num_events = kMaxEventsPerRTCP;
for (int i = 0; i < num_events; i++) {
p.AddReceiverFrameLog(
(test_rtp_timestamp() + RtpTimeDelta::FromTicks(i)).lower_32_bits(),
1, kTimeBaseMs + i * kTimeDelayMs);
p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0);
}
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
for (size_t i = 0; i < kRtcpMaxReceiverLogMessages; ++i) {
FrameEvent frame_event;
frame_event.rtp_timestamp =
test_rtp_timestamp() + RtpTimeDelta::FromTicks(i);
frame_event.type = FRAME_ACK_SENT;
frame_event.media_type = VIDEO_EVENT;
frame_event.timestamp = testing_clock.NowTicks();
event_subscriber.OnReceiveFrameEvent(frame_event);
testing_clock.Advance(base::Milliseconds(kTimeDelayMs));
}
ReceiverRtcpEventSubscriber::RtcpEvents rtcp_events;
event_subscriber.GetRtcpEventsWithRedundancy(&rtcp_events);
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, nullptr, nullptr, nullptr,
&rtcp_events, kDefaultDelay));
}
TEST_F(RtcpBuilderTest, RtcpReceiverReportWithOldLogFrames) {
static const uint32_t kTimeBaseMs = 12345678;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
RtcpReportBlock report_block = GetReportBlock();
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::Milliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
// Log 11 events for a single frame, each |kTimeBetweenEventsMs| apart.
// Only last 10 events will be sent because the first event is more than
// 4095 milliseconds away from latest event.
const int kTimeBetweenEventsMs = 410;
p.AddReceiverFrameLog(test_rtp_timestamp().lower_32_bits(), 10,
kTimeBaseMs + kTimeBetweenEventsMs);
for (int i = 0; i < 10; ++i) {
p.AddReceiverEventLog(0, FRAME_ACK_SENT, i * kTimeBetweenEventsMs);
}
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
for (int i = 0; i < 11; ++i) {
FrameEvent frame_event;
frame_event.rtp_timestamp = test_rtp_timestamp();
frame_event.type = FRAME_ACK_SENT;
frame_event.media_type = VIDEO_EVENT;
frame_event.timestamp = testing_clock.NowTicks();
event_subscriber.OnReceiveFrameEvent(frame_event);
testing_clock.Advance(base::Milliseconds(kTimeBetweenEventsMs));
}
ReceiverRtcpEventSubscriber::RtcpEvents rtcp_events;
event_subscriber.GetRtcpEventsWithRedundancy(&rtcp_events);
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, nullptr, nullptr, nullptr,
&rtcp_events, kDefaultDelay));
}
TEST_F(RtcpBuilderTest, RtcpReceiverReportRedundancy) {
uint32_t time_base_ms = 12345678;
int kTimeBetweenEventsMs = 10;
RtcpReportBlock report_block = GetReportBlock();
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::Milliseconds(time_base_ms));
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
size_t packet_count = kNumResends * kResendDelay + 10;
for (size_t i = 0; i < packet_count; i++) {
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddReceiverLog(kSendingSsrc);
int num_events = (i + kResendDelay) / kResendDelay;
num_events = std::min<int>(num_events, kNumResends);
p.AddReceiverFrameLog(test_rtp_timestamp().lower_32_bits(), num_events,
time_base_ms - (num_events - 1) * kResendDelay *
kTimeBetweenEventsMs);
for (int event = 0; event < num_events; event++) {
p.AddReceiverEventLog(0, FRAME_ACK_SENT,
base::checked_cast<uint16_t>(event * kResendDelay *
kTimeBetweenEventsMs));
}
FrameEvent frame_event;
frame_event.rtp_timestamp = test_rtp_timestamp();
frame_event.type = FRAME_ACK_SENT;
frame_event.media_type = VIDEO_EVENT;
frame_event.timestamp = testing_clock.NowTicks();
event_subscriber.OnReceiveFrameEvent(frame_event);
ReceiverRtcpEventSubscriber::RtcpEvents rtcp_events;
event_subscriber.GetRtcpEventsWithRedundancy(&rtcp_events);
ExpectPacketEQ(p.GetPacket(),
BuildRtcpFromReceiver(&report_block, nullptr, nullptr,
nullptr, &rtcp_events, kDefaultDelay));
testing_clock.Advance(base::Milliseconds(kTimeBetweenEventsMs));
time_base_ms += kTimeBetweenEventsMs;
}
}
TEST_F(RtcpBuilderTest, RtcpSenderReport) {
RtcpSenderInfo sender_info;
sender_info.ntp_seconds = kNtpHigh;
sender_info.ntp_fraction = kNtpLow;
sender_info.rtp_timestamp = test_rtp_timestamp();
sender_info.send_packet_count = kSendPacketCount;
sender_info.send_octet_count = kSendOctetCount;
// Sender report.
TestRtcpPacketBuilder p;
p.AddSr(kSendingSsrc, 0);
ExpectPacketEQ(p.GetPacket(),
rtcp_builder_->BuildRtcpFromSender(sender_info));
}
} // namespace cast
} // namespace media