// 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 "base/memory/scoped_ptr.h" #include "base/test/simple_test_tick_clock.h" #include "media/cast/cast_environment.h" #include "media/cast/net/cast_transport_defines.h" #include "media/cast/net/rtcp/rtcp_utility.h" #include "media/cast/net/rtcp/test_rtcp_packet_builder.h" #include "media/cast/test/fake_single_thread_task_runner.h" #include "testing/gtest/include/gtest/gtest.h" namespace media { namespace cast { static const uint32 kSenderSsrc = 0x10203; static const uint32 kSourceSsrc = 0x40506; static const uint32 kUnknownSsrc = 0xDEAD; static const base::TimeDelta kTargetDelay = base::TimeDelta::FromMilliseconds(100); class RtcpParserTest : public ::testing::Test { protected: RtcpParserTest() : testing_clock_(new base::SimpleTestTickClock()), task_runner_(new test::FakeSingleThreadTaskRunner( testing_clock_.get())) { } bool HasAnything(const RtcpParser& parser) { return parser.has_sender_report() || parser.has_last_report() || parser.has_receiver_log() || parser.has_cast_message() || parser.has_receiver_reference_time_report(); } void ExpectSenderInfo(const RtcpParser& parser) { EXPECT_TRUE(parser.has_sender_report()); EXPECT_EQ(kNtpHigh, parser.sender_report().ntp_seconds); EXPECT_EQ(kNtpLow, parser.sender_report().ntp_fraction); EXPECT_EQ(kRtpTimestamp, parser.sender_report().rtp_timestamp); EXPECT_EQ(kSendPacketCount, parser.sender_report().send_packet_count); EXPECT_EQ(kSendOctetCount, parser.sender_report().send_octet_count); } void ExpectLastReport(const RtcpParser& parser) { EXPECT_TRUE(parser.has_last_report()); EXPECT_EQ(kLastSr, parser.last_report()); EXPECT_EQ(kDelayLastSr, parser.delay_since_last_report()); } void ExpectReceiverReference(const RtcpParser& parser) { EXPECT_TRUE(parser.has_receiver_reference_time_report()); EXPECT_EQ(kSenderSsrc, parser.receiver_reference_time_report().remote_ssrc); EXPECT_EQ(kNtpHigh, parser.receiver_reference_time_report().ntp_seconds); EXPECT_EQ(kNtpLow, parser.receiver_reference_time_report().ntp_fraction); } void ExpectCastFeedback(const RtcpParser& parser) { EXPECT_TRUE(parser.has_cast_message()); EXPECT_EQ(kSenderSsrc, parser.cast_message().media_ssrc); EXPECT_EQ(kAckFrameId, parser.cast_message().ack_frame_id); MissingFramesAndPacketsMap::const_iterator frame_it = parser.cast_message().missing_frames_and_packets.begin(); EXPECT_TRUE( frame_it != parser.cast_message().missing_frames_and_packets.end()); EXPECT_EQ(kLostFrameId, frame_it->first); EXPECT_EQ(frame_it->second.size(), 1UL); EXPECT_EQ(*frame_it->second.begin(), kRtcpCastAllPacketsLost); ++frame_it; EXPECT_TRUE( frame_it != parser.cast_message().missing_frames_and_packets.end()); EXPECT_EQ(kFrameIdWithLostPackets, frame_it->first); EXPECT_EQ(3UL, frame_it->second.size()); PacketIdSet::const_iterator packet_it = frame_it->second.begin(); EXPECT_EQ(kLostPacketId1, *packet_it); ++packet_it; EXPECT_EQ(kLostPacketId2, *packet_it); ++packet_it; EXPECT_EQ(kLostPacketId3, *packet_it); ++frame_it; EXPECT_TRUE( frame_it == parser.cast_message().missing_frames_and_packets.end()); } void ExpectReceiverLog(const RtcpParser& parser, const RtcpReceiverLogMessage& expected_receiver_log) { EXPECT_TRUE(parser.has_receiver_log()); EXPECT_EQ(expected_receiver_log.size(), parser.receiver_log().size()); RtcpReceiverLogMessage::const_iterator expected_it = expected_receiver_log.begin(); RtcpReceiverLogMessage::const_iterator incoming_it = parser.receiver_log().begin(); for (; incoming_it != parser.receiver_log().end(); ++incoming_it, ++expected_it) { EXPECT_EQ(expected_it->rtp_timestamp_, incoming_it->rtp_timestamp_); EXPECT_EQ(expected_it->event_log_messages_.size(), incoming_it->event_log_messages_.size()); RtcpReceiverEventLogMessages::const_iterator event_incoming_it = incoming_it->event_log_messages_.begin(); RtcpReceiverEventLogMessages::const_iterator event_expected_it = expected_it->event_log_messages_.begin(); for (; event_incoming_it != incoming_it->event_log_messages_.end(); ++event_incoming_it, ++event_expected_it) { EXPECT_EQ(event_expected_it->type, event_incoming_it->type); EXPECT_EQ(event_expected_it->event_timestamp, event_incoming_it->event_timestamp); if (event_expected_it->type == PACKET_RECEIVED) { EXPECT_EQ(event_expected_it->packet_id, event_incoming_it->packet_id); } else { EXPECT_EQ(event_expected_it->delay_delta, event_incoming_it->delay_delta); } } } } scoped_ptr testing_clock_; scoped_refptr task_runner_; DISALLOW_COPY_AND_ASSIGN(RtcpParserTest); }; TEST_F(RtcpParserTest, BrokenPacketIsIgnored) { const char bad_packet[] = {0, 0, 0, 0}; RtcpParser parser(kSourceSsrc, kSenderSsrc); base::BigEndianReader reader(bad_packet, sizeof(bad_packet)); EXPECT_FALSE(parser.Parse(&reader)); } TEST_F(RtcpParserTest, UnknownBlockIgnored) { // Only unknown data, nothing happens. TestRtcpPacketBuilder p; p.AddUnknownBlock(); RtcpParser parser1(kSourceSsrc, 0); EXPECT_TRUE(parser1.Parse(p.Reader())); EXPECT_FALSE(HasAnything(parser1)); // Add valid sender report *after* unknown data - should work fine. p.AddSr(kSenderSsrc, 0); RtcpParser parser2(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser2.Parse(p.Reader())); ExpectSenderInfo(parser2); } TEST_F(RtcpParserTest, InjectSenderReportPacket) { TestRtcpPacketBuilder p; p.AddSr(kSenderSsrc, 0); // Expected to be ignored since the sender ssrc does not match our // remote ssrc. RtcpParser parser1(kSourceSsrc, 0); EXPECT_TRUE(parser1.Parse(p.Reader())); EXPECT_FALSE(HasAnything(parser1)); // Expected to be pass through since the sender ssrc match our remote ssrc. RtcpParser parser2(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser2.Parse(p.Reader())); ExpectSenderInfo(parser2); } TEST_F(RtcpParserTest, InjectReceiveReportPacket) { TestRtcpPacketBuilder p1; p1.AddRr(kSenderSsrc, 1); p1.AddRb(kUnknownSsrc); // Expected to be ignored since the source ssrc does not match our // local ssrc. RtcpParser parser1(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser1.Parse(p1.Reader())); EXPECT_FALSE(HasAnything(parser1)); TestRtcpPacketBuilder p2; p2.AddRr(kSenderSsrc, 1); p2.AddRb(kSourceSsrc); // Expected to be pass through since the sender ssrc match our local ssrc. RtcpParser parser2(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser2.Parse(p2.Reader())); ExpectLastReport(parser2); } TEST_F(RtcpParserTest, InjectSenderReportWithReportBlockPacket) { TestRtcpPacketBuilder p1; p1.AddSr(kSenderSsrc, 1); p1.AddRb(kUnknownSsrc); // Sender report expected to be ignored since the sender ssrc does not match // our remote ssrc. // Report block expected to be ignored since the source ssrc does not match // our local ssrc. RtcpParser parser1(kSourceSsrc, 0); EXPECT_TRUE(parser1.Parse(p1.Reader())); EXPECT_FALSE(HasAnything(parser1)); // Sender report expected to be pass through since the sender ssrc match our // remote ssrc. // Report block expected to be ignored since the source ssrc does not match // our local ssrc. RtcpParser parser2(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser2.Parse(p1.Reader())); ExpectSenderInfo(parser2); EXPECT_FALSE(parser2.has_last_report()); // Sender report expected to be ignored since the sender ssrc does not match // our remote ssrc. // Report block expected to be ignored too since it's a part of the // sender report. TestRtcpPacketBuilder p2; p2.AddSr(kSenderSsrc, 1); p2.AddRb(kSourceSsrc); RtcpParser parser3(kSourceSsrc, 0); EXPECT_TRUE(parser3.Parse(p2.Reader())); EXPECT_FALSE(parser3.has_last_report()); // Sender report expected to be pass through since the sender ssrc match our // remote ssrc. // Report block expected to be pass through since the sender ssrc match // our local ssrc. RtcpParser parser4(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser4.Parse(p2.Reader())); ExpectSenderInfo(parser4); ExpectLastReport(parser4); } TEST_F(RtcpParserTest, InjectSenderReportPacketWithDlrr) { TestRtcpPacketBuilder p; p.AddSr(kSenderSsrc, 0); p.AddXrHeader(kSenderSsrc); p.AddXrUnknownBlock(); p.AddXrExtendedDlrrBlock(kSenderSsrc); p.AddXrUnknownBlock(); // Expected to be ignored since the source ssrc does not match our // local ssrc. RtcpParser parser1(kSourceSsrc, 0); EXPECT_TRUE(parser1.Parse(p.Reader())); EXPECT_FALSE(HasAnything(parser1)); // Expected to be pass through since the sender ssrc match our local ssrc. RtcpParser parser2(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser2.Parse(p.Reader())); ExpectSenderInfo(parser2); // DLRRs are ignored. EXPECT_FALSE(parser2.has_last_report()); } TEST_F(RtcpParserTest, InjectReceiverReportPacketWithRrtr) { TestRtcpPacketBuilder p1; p1.AddRr(kSenderSsrc, 1); p1.AddRb(kUnknownSsrc); p1.AddXrHeader(kSenderSsrc); p1.AddXrRrtrBlock(); // Expected to be ignored since the source ssrc does not match our // local ssrc. RtcpParser parser1(kSourceSsrc, 0); EXPECT_TRUE(parser1.Parse(p1.Reader())); EXPECT_FALSE(HasAnything(parser1)); TestRtcpPacketBuilder p2; p2.AddRr(kSenderSsrc, 1); p2.AddRb(kSourceSsrc); p2.AddXrHeader(kSenderSsrc); p2.AddXrRrtrBlock(); // Expected to be pass through since the sender ssrc match our local ssrc. RtcpParser parser2(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser2.Parse(p2.Reader())); ExpectLastReport(parser2); ExpectReceiverReference(parser2); } TEST_F(RtcpParserTest, InjectReceiverReportPacketWithIntraFrameRequest) { TestRtcpPacketBuilder p1; p1.AddRr(kSenderSsrc, 1); p1.AddRb(kUnknownSsrc); // Expected to be ignored since the source ssrc does not match our // local ssrc. RtcpParser parser1(kSourceSsrc, 0); EXPECT_TRUE(parser1.Parse(p1.Reader())); EXPECT_FALSE(HasAnything(parser1)); TestRtcpPacketBuilder p2; p2.AddRr(kSenderSsrc, 1); p2.AddRb(kSourceSsrc); RtcpParser parser2(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser2.Parse(p2.Reader())); ExpectLastReport(parser2); } TEST_F(RtcpParserTest, InjectReceiverReportPacketWithCastFeedback) { TestRtcpPacketBuilder p1; p1.AddRr(kSenderSsrc, 1); p1.AddRb(kUnknownSsrc); p1.AddCast(kSenderSsrc, kUnknownSsrc, kTargetDelay); // Expected to be ignored since the source ssrc does not match our // local ssrc. RtcpParser parser1(kSourceSsrc, 0); EXPECT_TRUE(parser1.Parse(p1.Reader())); EXPECT_FALSE(HasAnything(parser1)); TestRtcpPacketBuilder p2; p2.AddRr(kSenderSsrc, 1); p2.AddRb(kSourceSsrc); p2.AddCast(kSenderSsrc, kSourceSsrc, kTargetDelay); // Expected to be pass through since the sender ssrc match our local ssrc. RtcpParser parser2(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser2.Parse(p2.Reader())); ExpectLastReport(parser2); ExpectCastFeedback(parser2); } TEST_F(RtcpParserTest, InjectReceiverReportWithReceiverLogVerificationBase) { static const uint32 kTimeBaseMs = 12345678; static const uint32 kTimeDelayMs = 10; static const uint32 kDelayDeltaMs = 123; base::SimpleTestTickClock testing_clock; testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs)); RtcpReceiverLogMessage receiver_log; RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp); RtcpReceiverEventLogMessage event_log; event_log.type = FRAME_ACK_SENT; event_log.event_timestamp = testing_clock.NowTicks(); event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs); frame_log.event_log_messages_.push_back(event_log); testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs)); event_log.type = PACKET_RECEIVED; event_log.event_timestamp = testing_clock.NowTicks(); event_log.packet_id = kLostPacketId1; frame_log.event_log_messages_.push_back(event_log); event_log.type = PACKET_RECEIVED; event_log.event_timestamp = testing_clock.NowTicks(); event_log.packet_id = kLostPacketId2; frame_log.event_log_messages_.push_back(event_log); receiver_log.push_back(frame_log); TestRtcpPacketBuilder p; p.AddRr(kSenderSsrc, 1); p.AddRb(kSourceSsrc); p.AddReceiverLog(kSenderSsrc); p.AddReceiverFrameLog(kRtpTimestamp, 3, kTimeBaseMs); p.AddReceiverEventLog(kDelayDeltaMs, FRAME_ACK_SENT, 0); p.AddReceiverEventLog(kLostPacketId1, PACKET_RECEIVED, kTimeDelayMs); p.AddReceiverEventLog(kLostPacketId2, PACKET_RECEIVED, kTimeDelayMs); RtcpParser parser(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser.Parse(p.Reader())); ExpectReceiverLog(parser, receiver_log); } TEST_F(RtcpParserTest, InjectReceiverReportWithReceiverLogVerificationMulti) { static const uint32 kTimeBaseMs = 12345678; static const uint32 kTimeDelayMs = 10; static const int kDelayDeltaMs = 123; // To be varied for every frame. base::SimpleTestTickClock testing_clock; testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs)); RtcpReceiverLogMessage receiver_log; for (int j = 0; j < 100; ++j) { RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp); RtcpReceiverEventLogMessage event_log; event_log.type = FRAME_ACK_SENT; event_log.event_timestamp = testing_clock.NowTicks(); event_log.delay_delta = base::TimeDelta::FromMilliseconds((j - 50) * kDelayDeltaMs); frame_log.event_log_messages_.push_back(event_log); receiver_log.push_back(frame_log); testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs)); } TestRtcpPacketBuilder p; p.AddRr(kSenderSsrc, 1); p.AddRb(kSourceSsrc); p.AddReceiverLog(kSenderSsrc); for (int i = 0; i < 100; ++i) { p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs); const int delay = (i - 50) * kDelayDeltaMs; p.AddReceiverEventLog(static_cast(delay), FRAME_ACK_SENT, 0); } RtcpParser parser(kSourceSsrc, kSenderSsrc); EXPECT_TRUE(parser.Parse(p.Reader())); ExpectReceiverLog(parser, receiver_log); } } // namespace cast } // namespace media