blob: 0b0c7d3ab8917b283260e5fb96526f8f5aa67b81 [file] [log] [blame]
// Copyright 2013 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 "base/memory/scoped_ptr.h"
#include "base/test/simple_test_tick_clock.h"
#include "media/cast/cast_defines.h"
#include "media/cast/cast_environment.h"
#include "media/cast/rtcp/receiver_rtcp_event_subscriber.h"
#include "media/cast/rtcp/rtcp_sender.h"
#include "media/cast/rtcp/rtcp_utility.h"
#include "media/cast/rtcp/test_rtcp_packet_builder.h"
#include "media/cast/test/fake_single_thread_task_runner.h"
#include "media/cast/transport/cast_transport_defines.h"
#include "media/cast/transport/pacing/paced_sender.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media {
namespace cast {
namespace {
static const uint32 kSendingSsrc = 0x12345678;
static const uint32 kMediaSsrc = 0x87654321;
static const int16 kDefaultDelay = 100;
static const std::string kCName("test@10.1.1.1");
transport::RtcpReportBlock GetReportBlock() {
transport::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 TestRtcpTransport : public transport::PacedPacketSender {
public:
TestRtcpTransport() : packet_count_(0) {}
virtual bool SendRtcpPacket(uint32 ssrc,
transport::PacketRef packet) OVERRIDE {
EXPECT_EQ(expected_packet_.size(), packet->data.size());
EXPECT_EQ(0, memcmp(expected_packet_.data(),
packet->data.data(),
packet->data.size()));
packet_count_++;
return true;
}
virtual bool SendPackets(
const transport::SendPacketVector& packets) OVERRIDE {
return false;
}
virtual bool ResendPackets(
const transport::SendPacketVector& packets,
base::TimeDelta dedupe_window) OVERRIDE {
return false;
}
virtual void CancelSendingPacket(
const transport::PacketKey& packet_key) OVERRIDE {
}
void SetExpectedRtcpPacket(scoped_ptr<Packet> packet) {
expected_packet_.swap(*packet);
}
int packet_count() const { return packet_count_; }
private:
Packet expected_packet_;
int packet_count_;
DISALLOW_COPY_AND_ASSIGN(TestRtcpTransport);
};
class RtcpSenderTest : public ::testing::Test {
protected:
RtcpSenderTest()
: testing_clock_(new base::SimpleTestTickClock()),
task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)),
cast_environment_(new CastEnvironment(
scoped_ptr<base::TickClock>(testing_clock_).Pass(),
task_runner_,
task_runner_,
task_runner_)),
rtcp_sender_(new RtcpSender(cast_environment_,
&test_transport_,
kSendingSsrc,
kCName)) {}
base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment.
TestRtcpTransport test_transport_;
scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
scoped_refptr<CastEnvironment> cast_environment_;
scoped_ptr<RtcpSender> rtcp_sender_;
DISALLOW_COPY_AND_ASSIGN(RtcpSenderTest);
};
TEST_F(RtcpSenderTest, RtcpReceiverReport) {
// Empty receiver report + c_name.
TestRtcpPacketBuilder p1;
p1.AddRr(kSendingSsrc, 0);
p1.AddSdesCname(kSendingSsrc, kCName);
test_transport_.SetExpectedRtcpPacket(p1.GetPacket());
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr, NULL, NULL, NULL, NULL, kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
// Receiver report with report block + c_name.
TestRtcpPacketBuilder p2;
p2.AddRr(kSendingSsrc, 1);
p2.AddRb(kMediaSsrc);
p2.AddSdesCname(kSendingSsrc, kCName);
test_transport_.SetExpectedRtcpPacket(p2.GetPacket().Pass());
transport::RtcpReportBlock report_block = GetReportBlock();
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr, &report_block, NULL, NULL, NULL, kDefaultDelay);
EXPECT_EQ(2, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtr) {
// Receiver report with report block + c_name.
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddXrHeader(kSendingSsrc);
p.AddXrRrtrBlock();
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
transport::RtcpReportBlock report_block = GetReportBlock();
RtcpReceiverReferenceTimeReport rrtr;
rrtr.ntp_seconds = kNtpHigh;
rrtr.ntp_fraction = kNtpLow;
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpRrtr,
&report_block,
&rrtr,
NULL,
NULL,
kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithCast) {
// Receiver report with report block + c_name.
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay);
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
transport::RtcpReportBlock report_block = GetReportBlock();
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id_ = kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets_[kLostFrameId] = missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
missing_packets;
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpCast,
&report_block,
NULL,
&cast_message,
NULL,
kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtraAndCastMessage) {
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddXrHeader(kSendingSsrc);
p.AddXrRrtrBlock();
p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay);
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
transport::RtcpReportBlock report_block = GetReportBlock();
RtcpReceiverReferenceTimeReport rrtr;
rrtr.ntp_seconds = kNtpHigh;
rrtr.ntp_fraction = kNtpLow;
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id_ = kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets_[kLostFrameId] = missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
missing_packets;
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast,
&report_block,
&rrtr,
&cast_message,
NULL,
kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) {
static const uint32 kTimeBaseMs = 12345678;
static const uint32 kTimeDelayMs = 10;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddXrHeader(kSendingSsrc);
p.AddXrRrtrBlock();
p.AddCast(kSendingSsrc, kMediaSsrc, kDefaultDelay);
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
transport::RtcpReportBlock report_block = GetReportBlock();
RtcpReceiverReferenceTimeReport rrtr;
rrtr.ntp_seconds = kNtpHigh;
rrtr.ntp_fraction = kNtpLow;
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id_ = kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets_[kLostFrameId] = missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
missing_packets;
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast |
transport::kRtcpReceiverLog,
&report_block,
&rrtr,
&cast_message,
&rtcp_events,
kDefaultDelay);
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
p.AddReceiverFrameLog(kRtpTimestamp, 2, kTimeBaseMs);
p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0);
p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs);
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
FrameEvent frame_event;
frame_event.rtp_timestamp = kRtpTimestamp;
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::TimeDelta::FromMilliseconds(kTimeDelayMs));
PacketEvent packet_event;
packet_event.rtp_timestamp = kRtpTimestamp;
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.GetRtcpEventsAndReset(&rtcp_events);
EXPECT_EQ(2u, rtcp_events.size());
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpRrtr | transport::kRtcpCast |
transport::kRtcpReceiverLog,
&report_block,
&rrtr,
&cast_message,
&rtcp_events,
kDefaultDelay);
EXPECT_EQ(2, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithOversizedFrameLog) {
static const uint32 kTimeBaseMs = 12345678;
static const uint32 kTimeDelayMs = 10;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
transport::RtcpReportBlock report_block = GetReportBlock();
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
int remaining_bytes = kMaxReceiverLogBytes;
remaining_bytes -= kRtcpCastLogHeaderSize;
remaining_bytes -= kRtcpReceiverFrameLogSize;
int num_events = remaining_bytes / kRtcpReceiverEventLogSize;
EXPECT_LE(num_events, static_cast<int>(kRtcpMaxReceiverLogMessages));
// Only the last |num_events| events are sent due to receiver log size cap.
p.AddReceiverFrameLog(
kRtpTimestamp + 2345,
num_events,
kTimeBaseMs + (kRtcpMaxReceiverLogMessages - num_events) * kTimeDelayMs);
for (int i = 0; i < num_events; i++) {
p.AddReceiverEventLog(
kLostPacketId1, PACKET_RECEIVED,
static_cast<uint16>(kTimeDelayMs * i));
}
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
FrameEvent frame_event;
frame_event.rtp_timestamp = kRtpTimestamp;
frame_event.type = FRAME_ACK_SENT;
frame_event.media_type = VIDEO_EVENT;
frame_event.timestamp = testing_clock.NowTicks();
event_subscriber.OnReceiveFrameEvent(frame_event);
for (size_t i = 0; i < kRtcpMaxReceiverLogMessages; ++i) {
PacketEvent packet_event;
packet_event.rtp_timestamp = kRtpTimestamp + 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::TimeDelta::FromMilliseconds(kTimeDelayMs));
}
ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
event_subscriber.GetRtcpEventsAndReset(&rtcp_events);
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
&rtcp_events,
kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithTooManyLogFrames) {
static const uint32 kTimeBaseMs = 12345678;
static const uint32 kTimeDelayMs = 10;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
transport::RtcpReportBlock report_block = GetReportBlock();
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
int remaining_bytes = kMaxReceiverLogBytes;
remaining_bytes -= kRtcpCastLogHeaderSize;
int num_events =
remaining_bytes / (kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize);
// The last |num_events| events are sent due to receiver log size cap.
for (size_t i = kRtcpMaxReceiverLogMessages - num_events;
i < kRtcpMaxReceiverLogMessages;
++i) {
p.AddReceiverFrameLog(kRtpTimestamp + i, 1, kTimeBaseMs + i * kTimeDelayMs);
p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0);
}
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
for (size_t i = 0; i < kRtcpMaxReceiverLogMessages; ++i) {
FrameEvent frame_event;
frame_event.rtp_timestamp = kRtpTimestamp + static_cast<int>(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::TimeDelta::FromMilliseconds(kTimeDelayMs));
}
ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
event_subscriber.GetRtcpEventsAndReset(&rtcp_events);
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
&rtcp_events,
kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithOldLogFrames) {
static const uint32 kTimeBaseMs = 12345678;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
transport::RtcpReportBlock report_block = GetReportBlock();
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(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(kRtpTimestamp, 10, kTimeBaseMs + kTimeBetweenEventsMs);
for (int i = 0; i < 10; ++i) {
p.AddReceiverEventLog(0, FRAME_ACK_SENT, i * kTimeBetweenEventsMs);
}
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
for (int i = 0; i < 11; ++i) {
FrameEvent frame_event;
frame_event.rtp_timestamp = kRtpTimestamp;
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::TimeDelta::FromMilliseconds(kTimeBetweenEventsMs));
}
ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
event_subscriber.GetRtcpEventsAndReset(&rtcp_events);
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
&rtcp_events,
kDefaultDelay);
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportRedundancy) {
uint32 time_base_ms = 12345678;
int kTimeBetweenEventsMs = 10;
transport::RtcpReportBlock report_block = GetReportBlock();
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(time_base_ms));
ReceiverRtcpEventSubscriber event_subscriber(500, VIDEO_EVENT);
size_t packet_count = kReceiveLogMessageHistorySize + 10;
for (size_t i = 0; i < packet_count; i++) {
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddReceiverLog(kSendingSsrc);
if (i >= kSecondRedundancyOffset) {
p.AddReceiverFrameLog(
kRtpTimestamp,
1,
time_base_ms - kSecondRedundancyOffset * kTimeBetweenEventsMs);
p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0);
}
if (i >= kFirstRedundancyOffset) {
p.AddReceiverFrameLog(
kRtpTimestamp,
1,
time_base_ms - kFirstRedundancyOffset * kTimeBetweenEventsMs);
p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0);
}
p.AddReceiverFrameLog(kRtpTimestamp, 1, time_base_ms);
p.AddReceiverEventLog(0, FRAME_ACK_SENT, 0);
test_transport_.SetExpectedRtcpPacket(p.GetPacket().Pass());
FrameEvent frame_event;
frame_event.rtp_timestamp = kRtpTimestamp;
frame_event.type = FRAME_ACK_SENT;
frame_event.media_type = VIDEO_EVENT;
frame_event.timestamp = testing_clock.NowTicks();
event_subscriber.OnReceiveFrameEvent(frame_event);
ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
event_subscriber.GetRtcpEventsAndReset(&rtcp_events);
rtcp_sender_->SendRtcpFromRtpReceiver(
transport::kRtcpRr | transport::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
&rtcp_events,
kDefaultDelay);
testing_clock.Advance(
base::TimeDelta::FromMilliseconds(kTimeBetweenEventsMs));
time_base_ms += kTimeBetweenEventsMs;
}
EXPECT_EQ(static_cast<int>(packet_count), test_transport_.packet_count());
}
} // namespace cast
} // namespace media