Chromium Code Reviews| Index: media/cast/framer/cast_message_builder_unittest.cc |
| diff --git a/media/cast/framer/cast_message_builder_unittest.cc b/media/cast/framer/cast_message_builder_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e6d13a33a3459557f4959a7fc24d084025f6db7b |
| --- /dev/null |
| +++ b/media/cast/framer/cast_message_builder_unittest.cc |
| @@ -0,0 +1,512 @@ |
| +// 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/test/simple_test_tick_clock.h" |
| +#include "media/cast/framer/cast_message_builder.h" |
| +#include "media/cast/rtcp/rtcp.h" |
| +#include "media/cast/rtp_common/rtp_defines.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace media { |
| +namespace cast { |
| + |
| +static const uint32 kSsrc = 0x1234; |
| +static const uint32 kShortTimeIncrementMs = 10; |
| +static const uint32 kLongTimeIncrementMs = 40; |
| +static const int64 kStartMillisecond = 123456789; |
| + |
| + |
| +class NackFeedbackVerification : public RtpPayloadFeedback { |
| + public: |
| + NackFeedbackVerification() |
| + : triggered_(false), |
| + missing_packets_(), |
| + last_frame_acked_(0) {} |
| + |
| + |
| + virtual void RequestKeyFrame() OVERRIDE { |
| + request_key_frame_ = true; |
| + } |
| + |
| + virtual void CastFeedback(const RtcpCastMessage& cast_feedback) OVERRIDE { |
| + EXPECT_EQ(kSsrc, cast_feedback.media_ssrc_); |
| + |
| + last_frame_acked_ = cast_feedback.ack_frame_id_; |
| + |
| + std::map<uint8, std::set<uint16> >::const_iterator frame_it = |
|
Alpha Left Google
2013/08/28 00:27:31
This looks bulky is there a typedef you can use?
pwestin
2013/08/28 16:40:44
Done.
|
| + cast_feedback.missing_frames_and_packets_.begin(); |
| + // Keep track of the number of missing packets per frame. |
| + missing_packets_.clear(); |
| + while (frame_it != cast_feedback.missing_frames_and_packets_.end()) { |
| + missing_packets_.insert(std::pair<uint8, int> |
|
Alpha Left Google
2013/08/28 00:27:31
you can just std::make_pair() which does the same
pwestin
2013/08/28 16:40:44
Done.
|
| + (frame_it->first, frame_it->second.size())); |
| + ++frame_it; |
| + } |
| + triggered_ = true; |
| + } |
| + |
| + int num_missing_packets(uint8 frame_id) { |
| + std::map<uint8, int>::iterator it; |
| + it = missing_packets_.find(frame_id); |
| + if (it == missing_packets_.end()) return 0; |
| + return it->second; |
| + } |
| + |
| + // Holds value for one call. |
| + bool triggered() { |
| + bool ret_val = triggered_; |
| + triggered_ = false; |
| + return ret_val; |
| + } |
| + |
| + bool request_key_frame() { |
| + bool ret_val = request_key_frame_; |
| + request_key_frame_ = false; |
| + return ret_val; |
| + } |
| + uint8 last_frame_acked() { return last_frame_acked_; } |
|
Alpha Left Google
2013/08/28 00:27:31
nit: one space after ().
pwestin
2013/08/28 16:40:44
Done.
|
| + |
| + private: |
| + bool triggered_; |
| + // Number of missing packets per frame. |
| + std::map<uint8, int> missing_packets_; |
|
Alpha Left Google
2013/08/28 00:27:31
Use a typedef here.
pwestin
2013/08/28 16:40:44
Done.
|
| + uint8 last_frame_acked_; |
| + bool request_key_frame_; |
| +}; |
| + |
| +class CastMessageBuilderTest : public ::testing::Test { |
| + protected: |
| + CastMessageBuilderTest() |
| + : feedback_(new NackFeedbackVerification()) { |
| + cast_msg_builder_ = new CastMessageBuilder(feedback_, |
| + &frame_id_map_, |
| + kSsrc, |
| + true, |
| + 0); |
| + rtp_header_.webrtc.header.ssrc = kSsrc; |
| + rtp_header_.is_key_frame = false; |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kStartMillisecond)); |
| + cast_msg_builder_->set_clock(&testing_clock_); |
| + } |
| + |
| + ~CastMessageBuilderTest() { } |
| + |
| + void SetFrameId(uint8 frame_id) { |
| + rtp_header_.frame_id = frame_id; |
| + } |
| + |
| + void SetPacketId(uint16 packet_id) { |
| + rtp_header_.packet_id = packet_id; |
| + } |
| + |
| + void SetMaxPacketId(uint16 max_packet_id) { |
| + rtp_header_.max_packet_id = max_packet_id; |
| + } |
| + |
| + void SetKeyFrame(bool is_key) { |
| + rtp_header_.is_key_frame = is_key; |
| + } |
| + |
| + void SetReferenceFrameId(uint8 reference_frame_id) { |
| + rtp_header_.is_reference = true; |
| + rtp_header_.reference_frame_id = reference_frame_id; |
| + } |
| + |
| + void InsertPacket() { |
| + bool complete = false; |
| + frame_id_map_.InsertPacket(rtp_header_, &complete); |
| + if (complete) { |
| + cast_msg_builder_->CompleteFrameReceived(rtp_header_.frame_id, |
| + rtp_header_.is_key_frame); |
| + } |
| + cast_msg_builder_->UpdateCastMessage(); |
| + } |
| + |
| + void SetDecoderSlowerThanMaxFrameRate(int max_unacked_frames) { |
| + delete cast_msg_builder_; |
| + cast_msg_builder_ = new CastMessageBuilder(feedback_, |
| + &frame_id_map_, |
| + kSsrc, |
| + false, |
| + max_unacked_frames); |
| + } |
| + |
| + CastMessageBuilder* cast_msg_builder_; |
|
Alpha Left Google
2013/08/28 00:27:31
Use scoped_ptr<>.
pwestin
2013/08/28 16:40:44
Done.
|
| + NackFeedbackVerification* feedback_; |
| + RtpCastHeader rtp_header_; |
| + FrameIdMap frame_id_map_; |
| + base::SimpleTestTickClock testing_clock_; |
| +}; |
| + |
| +TEST_F(CastMessageBuilderTest, StartWithAKeyFrame) { |
| + SetFrameId(3); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + InsertPacket(); |
| + // Should not trigger ack. |
| + EXPECT_FALSE(feedback_->triggered()); |
| + SetFrameId(5); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + frame_id_map_.RemoveOldFrames(5); // Simulate 5 being pulled for rendering. |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + cast_msg_builder_->UpdateCastMessage(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(5, feedback_->last_frame_acked()); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, OneFrameNackList) { |
| + SetFrameId(0); |
| + SetPacketId(4); |
| + SetMaxPacketId(10); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + EXPECT_FALSE(feedback_->triggered()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetPacketId(5); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(4, feedback_->num_missing_packets(0)); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, CompleteFrameMissing) { |
| + // TODO(mikhal): Add indication. |
| + SetFrameId(0); |
| + SetPacketId(2); |
| + SetMaxPacketId(5); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(2); |
| + SetPacketId(2); |
| + SetMaxPacketId(5); |
| + InsertPacket(); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, FastForwardAck) { |
| + SetFrameId(1); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + InsertPacket(); |
| + EXPECT_FALSE(feedback_->triggered()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(2); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(255, feedback_->last_frame_acked()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(2, feedback_->last_frame_acked()); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, RemoveOldFrames) { |
| + SetFrameId(1); |
| + SetPacketId(0); |
| + SetMaxPacketId(1); |
| + InsertPacket(); |
| + EXPECT_FALSE(feedback_->triggered()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(2); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(3); |
| + SetPacketId(0); |
| + SetMaxPacketId(5); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(255, feedback_->last_frame_acked()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(5); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + frame_id_map_.RemoveOldFrames(5); // Simulate 5 being pulled for rendering. |
| + cast_msg_builder_->UpdateCastMessage(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(5, feedback_->last_frame_acked()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + SetFrameId(1); |
| + SetPacketId(1); |
| + SetMaxPacketId(1); |
| + InsertPacket(); |
| + EXPECT_FALSE(feedback_->triggered()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(5, feedback_->last_frame_acked()); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, WrapFastForward) { |
| + SetFrameId(254); |
| + SetPacketId(0); |
| + SetMaxPacketId(1); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + EXPECT_FALSE(feedback_->triggered()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(255); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(false); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(253, feedback_->last_frame_acked()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(false); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(253, feedback_->last_frame_acked()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetFrameId(254); |
| + SetPacketId(1); |
| + SetMaxPacketId(1); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(0, feedback_->last_frame_acked()); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacket) { |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(20); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetPacketId(5); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(4, feedback_->num_missing_packets(0)); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacketNextFrame) { |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(20); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetPacketId(5); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(4, feedback_->num_missing_packets(0)); |
| + SetFrameId(1); |
| + SetMaxPacketId(2); |
| + SetPacketId(0); |
| + SetKeyFrame(false); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(21 - 2, feedback_->num_missing_packets(0)); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacketNextKey) { |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(20); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + SetPacketId(5); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(4, feedback_->num_missing_packets(0)); |
| + SetFrameId(1); |
| + SetMaxPacketId(0); |
| + SetPacketId(0); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(0, feedback_->num_missing_packets(0)); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, Reset) { |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + cast_msg_builder_->Reset(); |
| + frame_id_map_.Clear(); |
| + // Should reset nack list state and request a key frame. |
| + cast_msg_builder_->UpdateCastMessage(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(0, feedback_->num_missing_packets(0)); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, DeltaAfterReset) { |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(0, feedback_->num_missing_packets(0)); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + cast_msg_builder_->Reset(); |
| + SetFrameId(1); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(true); |
| + EXPECT_FALSE(feedback_->triggered()); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, BasicRps) { |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(0, feedback_->last_frame_acked()); |
| + SetFrameId(3); |
| + SetKeyFrame(false); |
| + SetReferenceFrameId(0); |
| + InsertPacket(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(0, feedback_->last_frame_acked()); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); |
| + frame_id_map_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering. |
| + cast_msg_builder_->UpdateCastMessage(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(3, feedback_->last_frame_acked()); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, InOrderRps) { |
| + // Create a pattern - skip to rps, and don't look back. |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(0, feedback_->last_frame_acked()); |
| + SetFrameId(1); |
| + SetPacketId(0); |
| + SetMaxPacketId(1); |
| + SetKeyFrame(false); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + EXPECT_FALSE(feedback_->triggered()); |
| + SetFrameId(3); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(false); |
| + SetReferenceFrameId(0); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + frame_id_map_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering. |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + cast_msg_builder_->UpdateCastMessage(); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(3, feedback_->last_frame_acked()); |
| + // Make an old frame complete - should not trigger an ack. |
| + SetFrameId(1); |
| + SetPacketId(1); |
| + SetMaxPacketId(1); |
| + SetKeyFrame(false); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + EXPECT_FALSE(feedback_->triggered()); |
| + EXPECT_EQ(3, feedback_->last_frame_acked()); |
| +} |
| + |
| +TEST_F(CastMessageBuilderTest, SlowDownAck) { |
| + SetDecoderSlowerThanMaxFrameRate(3); |
| + SetFrameId(0); |
| + SetPacketId(0); |
| + SetMaxPacketId(0); |
| + SetKeyFrame(true); |
| + InsertPacket(); |
| + |
| + int frame_id; |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + SetKeyFrame(false); |
| + for (frame_id = 1; frame_id < 3; ++frame_id) { |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(frame_id - 1, feedback_->last_frame_acked()); |
| + SetFrameId(frame_id); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + } |
| + // We should now have entered the slowdown ACK state. |
| + uint8_t expected_frame_id = 1; |
| + for (; frame_id < 10; ++frame_id) { |
| + if (frame_id % 2) ++expected_frame_id; |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(expected_frame_id, feedback_->last_frame_acked()); |
| + SetFrameId(frame_id); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + } |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(expected_frame_id, feedback_->last_frame_acked()); |
| + |
| + // Simulate frame_id being pulled for rendering. |
| + frame_id_map_.RemoveOldFrames(frame_id); |
| + // We should now leave the slowdown ACK state. |
| + ++frame_id; |
| + SetFrameId(frame_id); |
| + InsertPacket(); |
| + testing_clock_.Advance( |
| + base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); |
| + EXPECT_TRUE(feedback_->triggered()); |
| + EXPECT_EQ(frame_id, feedback_->last_frame_acked()); |
| +} |
| + |
| +} // namespace cast |
| +} // namespace media |