| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <stdint.h> | |
| 6 | |
| 7 #include "base/memory/scoped_ptr.h" | |
| 8 #include "base/test/simple_test_tick_clock.h" | |
| 9 #include "media/cast/framer/cast_message_builder.h" | |
| 10 #include "media/cast/rtcp/rtcp.h" | |
| 11 #include "media/cast/rtp_receiver/rtp_receiver_defines.h" | |
| 12 #include "testing/gtest/include/gtest/gtest.h" | |
| 13 | |
| 14 namespace media { | |
| 15 namespace cast { | |
| 16 | |
| 17 namespace { | |
| 18 static const uint32 kSsrc = 0x1234; | |
| 19 static const uint32 kShortTimeIncrementMs = 10; | |
| 20 static const uint32 kLongTimeIncrementMs = 40; | |
| 21 static const int64 kStartMillisecond = INT64_C(12345678900000); | |
| 22 | |
| 23 typedef std::map<uint32, size_t> MissingPacketsMap; | |
| 24 | |
| 25 class NackFeedbackVerification : public RtpPayloadFeedback { | |
| 26 public: | |
| 27 NackFeedbackVerification() | |
| 28 : triggered_(false), missing_packets_(), last_frame_acked_(0) {} | |
| 29 | |
| 30 virtual void CastFeedback(const RtcpCastMessage& cast_feedback) OVERRIDE { | |
| 31 EXPECT_EQ(kSsrc, cast_feedback.media_ssrc_); | |
| 32 | |
| 33 last_frame_acked_ = cast_feedback.ack_frame_id_; | |
| 34 | |
| 35 MissingFramesAndPacketsMap::const_iterator frame_it = | |
| 36 cast_feedback.missing_frames_and_packets_.begin(); | |
| 37 | |
| 38 // Keep track of the number of missing packets per frame. | |
| 39 missing_packets_.clear(); | |
| 40 while (frame_it != cast_feedback.missing_frames_and_packets_.end()) { | |
| 41 // Check for complete frame lost. | |
| 42 if ((frame_it->second.size() == 1) && | |
| 43 (*frame_it->second.begin() == kRtcpCastAllPacketsLost)) { | |
| 44 missing_packets_.insert( | |
| 45 std::make_pair(frame_it->first, kRtcpCastAllPacketsLost)); | |
| 46 } else { | |
| 47 missing_packets_.insert( | |
| 48 std::make_pair(frame_it->first, frame_it->second.size())); | |
| 49 } | |
| 50 ++frame_it; | |
| 51 } | |
| 52 triggered_ = true; | |
| 53 } | |
| 54 | |
| 55 size_t num_missing_packets(uint32 frame_id) { | |
| 56 MissingPacketsMap::iterator it; | |
| 57 it = missing_packets_.find(frame_id); | |
| 58 if (it == missing_packets_.end()) | |
| 59 return 0; | |
| 60 | |
| 61 return it->second; | |
| 62 } | |
| 63 | |
| 64 // Holds value for one call. | |
| 65 bool triggered() { | |
| 66 bool ret_val = triggered_; | |
| 67 triggered_ = false; | |
| 68 return ret_val; | |
| 69 } | |
| 70 | |
| 71 uint32 last_frame_acked() { return last_frame_acked_; } | |
| 72 | |
| 73 private: | |
| 74 bool triggered_; | |
| 75 MissingPacketsMap missing_packets_; // Missing packets per frame. | |
| 76 uint32 last_frame_acked_; | |
| 77 | |
| 78 DISALLOW_COPY_AND_ASSIGN(NackFeedbackVerification); | |
| 79 }; | |
| 80 } // namespace | |
| 81 | |
| 82 class CastMessageBuilderTest : public ::testing::Test { | |
| 83 protected: | |
| 84 CastMessageBuilderTest() | |
| 85 : cast_msg_builder_(new CastMessageBuilder(&testing_clock_, | |
| 86 &feedback_, | |
| 87 &frame_id_map_, | |
| 88 kSsrc, | |
| 89 true, | |
| 90 0)) { | |
| 91 rtp_header_.sender_ssrc = kSsrc; | |
| 92 rtp_header_.is_key_frame = false; | |
| 93 testing_clock_.Advance( | |
| 94 base::TimeDelta::FromMilliseconds(kStartMillisecond)); | |
| 95 } | |
| 96 | |
| 97 virtual ~CastMessageBuilderTest() {} | |
| 98 | |
| 99 void SetFrameIds(uint32 frame_id, uint32 reference_frame_id) { | |
| 100 rtp_header_.frame_id = frame_id; | |
| 101 rtp_header_.reference_frame_id = reference_frame_id; | |
| 102 } | |
| 103 | |
| 104 void SetPacketId(uint16 packet_id) { rtp_header_.packet_id = packet_id; } | |
| 105 | |
| 106 void SetMaxPacketId(uint16 max_packet_id) { | |
| 107 rtp_header_.max_packet_id = max_packet_id; | |
| 108 } | |
| 109 | |
| 110 void SetKeyFrame(bool is_key) { rtp_header_.is_key_frame = is_key; } | |
| 111 | |
| 112 void InsertPacket() { | |
| 113 PacketType packet_type = frame_id_map_.InsertPacket(rtp_header_); | |
| 114 if (packet_type == kNewPacketCompletingFrame) { | |
| 115 cast_msg_builder_->CompleteFrameReceived(rtp_header_.frame_id); | |
| 116 } | |
| 117 cast_msg_builder_->UpdateCastMessage(); | |
| 118 } | |
| 119 | |
| 120 void SetDecoderSlowerThanMaxFrameRate(int max_unacked_frames) { | |
| 121 cast_msg_builder_.reset(new CastMessageBuilder(&testing_clock_, | |
| 122 &feedback_, | |
| 123 &frame_id_map_, | |
| 124 kSsrc, | |
| 125 false, | |
| 126 max_unacked_frames)); | |
| 127 } | |
| 128 | |
| 129 NackFeedbackVerification feedback_; | |
| 130 scoped_ptr<CastMessageBuilder> cast_msg_builder_; | |
| 131 RtpCastHeader rtp_header_; | |
| 132 FrameIdMap frame_id_map_; | |
| 133 base::SimpleTestTickClock testing_clock_; | |
| 134 | |
| 135 DISALLOW_COPY_AND_ASSIGN(CastMessageBuilderTest); | |
| 136 }; | |
| 137 | |
| 138 TEST_F(CastMessageBuilderTest, OneFrameNackList) { | |
| 139 SetFrameIds(0, 0); | |
| 140 SetPacketId(4); | |
| 141 SetMaxPacketId(10); | |
| 142 InsertPacket(); | |
| 143 testing_clock_.Advance( | |
| 144 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 145 EXPECT_FALSE(feedback_.triggered()); | |
| 146 testing_clock_.Advance( | |
| 147 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 148 SetPacketId(5); | |
| 149 InsertPacket(); | |
| 150 EXPECT_TRUE(feedback_.triggered()); | |
| 151 EXPECT_EQ(4u, feedback_.num_missing_packets(0)); | |
| 152 } | |
| 153 | |
| 154 TEST_F(CastMessageBuilderTest, CompleteFrameMissing) { | |
| 155 SetFrameIds(0, 0); | |
| 156 SetPacketId(2); | |
| 157 SetMaxPacketId(5); | |
| 158 InsertPacket(); | |
| 159 testing_clock_.Advance( | |
| 160 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 161 SetFrameIds(2, 1); | |
| 162 SetPacketId(2); | |
| 163 SetMaxPacketId(5); | |
| 164 InsertPacket(); | |
| 165 EXPECT_TRUE(feedback_.triggered()); | |
| 166 EXPECT_EQ(kRtcpCastAllPacketsLost, feedback_.num_missing_packets(1)); | |
| 167 } | |
| 168 | |
| 169 TEST_F(CastMessageBuilderTest, RemoveOldFrames) { | |
| 170 SetFrameIds(1, 0); | |
| 171 SetPacketId(0); | |
| 172 SetMaxPacketId(1); | |
| 173 InsertPacket(); | |
| 174 EXPECT_FALSE(feedback_.triggered()); | |
| 175 testing_clock_.Advance( | |
| 176 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 177 SetFrameIds(2, 1); | |
| 178 SetPacketId(0); | |
| 179 SetMaxPacketId(0); | |
| 180 InsertPacket(); | |
| 181 EXPECT_TRUE(feedback_.triggered()); | |
| 182 testing_clock_.Advance( | |
| 183 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 184 SetFrameIds(3, 2); | |
| 185 SetPacketId(0); | |
| 186 SetMaxPacketId(5); | |
| 187 InsertPacket(); | |
| 188 EXPECT_TRUE(feedback_.triggered()); | |
| 189 EXPECT_EQ(2u, feedback_.last_frame_acked()); | |
| 190 testing_clock_.Advance( | |
| 191 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 192 SetFrameIds(5, 5); | |
| 193 SetPacketId(0); | |
| 194 SetMaxPacketId(0); | |
| 195 SetKeyFrame(true); | |
| 196 InsertPacket(); | |
| 197 testing_clock_.Advance( | |
| 198 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 199 frame_id_map_.RemoveOldFrames(5); // Simulate 5 being pulled for rendering. | |
| 200 cast_msg_builder_->UpdateCastMessage(); | |
| 201 EXPECT_TRUE(feedback_.triggered()); | |
| 202 EXPECT_EQ(5u, feedback_.last_frame_acked()); | |
| 203 testing_clock_.Advance( | |
| 204 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 205 SetFrameIds(1, 0); | |
| 206 SetPacketId(1); | |
| 207 SetMaxPacketId(1); | |
| 208 InsertPacket(); | |
| 209 EXPECT_FALSE(feedback_.triggered()); | |
| 210 testing_clock_.Advance( | |
| 211 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 212 InsertPacket(); | |
| 213 EXPECT_TRUE(feedback_.triggered()); | |
| 214 EXPECT_EQ(5u, feedback_.last_frame_acked()); | |
| 215 } | |
| 216 | |
| 217 TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacket) { | |
| 218 SetFrameIds(0, 0); | |
| 219 SetPacketId(0); | |
| 220 SetMaxPacketId(20); | |
| 221 SetKeyFrame(true); | |
| 222 InsertPacket(); | |
| 223 testing_clock_.Advance( | |
| 224 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 225 SetPacketId(5); | |
| 226 InsertPacket(); | |
| 227 EXPECT_TRUE(feedback_.triggered()); | |
| 228 EXPECT_EQ(4u, feedback_.num_missing_packets(0)); | |
| 229 } | |
| 230 | |
| 231 TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacketNextFrame) { | |
| 232 SetFrameIds(0, 0); | |
| 233 SetPacketId(0); | |
| 234 SetMaxPacketId(20); | |
| 235 SetKeyFrame(true); | |
| 236 InsertPacket(); | |
| 237 testing_clock_.Advance( | |
| 238 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 239 SetPacketId(5); | |
| 240 InsertPacket(); | |
| 241 testing_clock_.Advance( | |
| 242 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 243 EXPECT_TRUE(feedback_.triggered()); | |
| 244 EXPECT_EQ(4u, feedback_.num_missing_packets(0)); | |
| 245 SetFrameIds(1, 0); | |
| 246 SetMaxPacketId(2); | |
| 247 SetPacketId(0); | |
| 248 SetKeyFrame(false); | |
| 249 InsertPacket(); | |
| 250 testing_clock_.Advance( | |
| 251 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 252 EXPECT_TRUE(feedback_.triggered()); | |
| 253 EXPECT_EQ(19u, feedback_.num_missing_packets(0)); | |
| 254 } | |
| 255 | |
| 256 TEST_F(CastMessageBuilderTest, NackUntilMaxReceivedPacketNextKey) { | |
| 257 SetFrameIds(0, 0); | |
| 258 SetPacketId(0); | |
| 259 SetMaxPacketId(20); | |
| 260 SetKeyFrame(true); | |
| 261 InsertPacket(); | |
| 262 testing_clock_.Advance( | |
| 263 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 264 SetPacketId(5); | |
| 265 InsertPacket(); | |
| 266 testing_clock_.Advance( | |
| 267 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 268 EXPECT_TRUE(feedback_.triggered()); | |
| 269 EXPECT_EQ(4u, feedback_.num_missing_packets(0)); | |
| 270 SetFrameIds(1, 1); | |
| 271 SetMaxPacketId(0); | |
| 272 SetPacketId(0); | |
| 273 SetKeyFrame(true); | |
| 274 InsertPacket(); | |
| 275 testing_clock_.Advance( | |
| 276 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 277 EXPECT_TRUE(feedback_.triggered()); | |
| 278 EXPECT_EQ(0u, feedback_.num_missing_packets(0)); | |
| 279 } | |
| 280 | |
| 281 TEST_F(CastMessageBuilderTest, Reset) { | |
| 282 InsertPacket(); | |
| 283 testing_clock_.Advance( | |
| 284 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 285 cast_msg_builder_->Reset(); | |
| 286 frame_id_map_.Clear(); | |
| 287 // Should reset nack list state and request a key frame. | |
| 288 cast_msg_builder_->UpdateCastMessage(); | |
| 289 EXPECT_TRUE(feedback_.triggered()); | |
| 290 EXPECT_EQ(0u, feedback_.num_missing_packets(0)); | |
| 291 } | |
| 292 | |
| 293 TEST_F(CastMessageBuilderTest, DeltaAfterReset) { | |
| 294 SetFrameIds(0, 0); | |
| 295 SetPacketId(0); | |
| 296 SetMaxPacketId(0); | |
| 297 SetKeyFrame(true); | |
| 298 InsertPacket(); | |
| 299 EXPECT_TRUE(feedback_.triggered()); | |
| 300 EXPECT_EQ(0u, feedback_.num_missing_packets(0)); | |
| 301 testing_clock_.Advance( | |
| 302 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 303 cast_msg_builder_->Reset(); | |
| 304 SetFrameIds(1, 0); | |
| 305 SetPacketId(0); | |
| 306 SetMaxPacketId(0); | |
| 307 SetKeyFrame(true); | |
| 308 EXPECT_FALSE(feedback_.triggered()); | |
| 309 } | |
| 310 | |
| 311 TEST_F(CastMessageBuilderTest, BasicRps) { | |
| 312 SetFrameIds(0, 0); | |
| 313 SetPacketId(0); | |
| 314 SetMaxPacketId(0); | |
| 315 SetKeyFrame(true); | |
| 316 InsertPacket(); | |
| 317 testing_clock_.Advance( | |
| 318 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 319 EXPECT_TRUE(feedback_.triggered()); | |
| 320 EXPECT_EQ(0u, feedback_.last_frame_acked()); | |
| 321 SetFrameIds(3, 0); | |
| 322 SetKeyFrame(false); | |
| 323 InsertPacket(); | |
| 324 EXPECT_TRUE(feedback_.triggered()); | |
| 325 EXPECT_EQ(3u, feedback_.last_frame_acked()); | |
| 326 testing_clock_.Advance( | |
| 327 base::TimeDelta::FromMilliseconds(kLongTimeIncrementMs)); | |
| 328 frame_id_map_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering. | |
| 329 cast_msg_builder_->UpdateCastMessage(); | |
| 330 EXPECT_TRUE(feedback_.triggered()); | |
| 331 EXPECT_EQ(3u, feedback_.last_frame_acked()); | |
| 332 } | |
| 333 | |
| 334 TEST_F(CastMessageBuilderTest, InOrderRps) { | |
| 335 // Create a pattern - skip to rps, and don't look back. | |
| 336 SetFrameIds(0, 0); | |
| 337 SetPacketId(0); | |
| 338 SetMaxPacketId(0); | |
| 339 SetKeyFrame(true); | |
| 340 InsertPacket(); | |
| 341 testing_clock_.Advance( | |
| 342 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 343 EXPECT_TRUE(feedback_.triggered()); | |
| 344 EXPECT_EQ(0u, feedback_.last_frame_acked()); | |
| 345 SetFrameIds(1, 0); | |
| 346 SetPacketId(0); | |
| 347 SetMaxPacketId(1); | |
| 348 SetKeyFrame(false); | |
| 349 InsertPacket(); | |
| 350 testing_clock_.Advance( | |
| 351 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 352 EXPECT_FALSE(feedback_.triggered()); | |
| 353 SetFrameIds(3, 0); | |
| 354 SetPacketId(0); | |
| 355 SetMaxPacketId(0); | |
| 356 SetKeyFrame(false); | |
| 357 InsertPacket(); | |
| 358 testing_clock_.Advance( | |
| 359 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 360 frame_id_map_.RemoveOldFrames(3); // Simulate 3 being pulled for rendering. | |
| 361 testing_clock_.Advance( | |
| 362 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 363 cast_msg_builder_->UpdateCastMessage(); | |
| 364 EXPECT_TRUE(feedback_.triggered()); | |
| 365 EXPECT_EQ(3u, feedback_.last_frame_acked()); | |
| 366 // Make an old frame complete - should not trigger an ack. | |
| 367 SetFrameIds(1, 0); | |
| 368 SetPacketId(1); | |
| 369 SetMaxPacketId(1); | |
| 370 SetKeyFrame(false); | |
| 371 InsertPacket(); | |
| 372 testing_clock_.Advance( | |
| 373 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 374 EXPECT_FALSE(feedback_.triggered()); | |
| 375 EXPECT_EQ(3u, feedback_.last_frame_acked()); | |
| 376 } | |
| 377 | |
| 378 TEST_F(CastMessageBuilderTest, SlowDownAck) { | |
| 379 SetDecoderSlowerThanMaxFrameRate(3); | |
| 380 SetFrameIds(0, 0); | |
| 381 SetPacketId(0); | |
| 382 SetMaxPacketId(0); | |
| 383 SetKeyFrame(true); | |
| 384 InsertPacket(); | |
| 385 | |
| 386 uint32 frame_id; | |
| 387 testing_clock_.Advance( | |
| 388 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 389 SetKeyFrame(false); | |
| 390 for (frame_id = 1; frame_id < 3; ++frame_id) { | |
| 391 EXPECT_TRUE(feedback_.triggered()); | |
| 392 EXPECT_EQ(frame_id - 1, feedback_.last_frame_acked()); | |
| 393 SetFrameIds(frame_id, frame_id - 1); | |
| 394 InsertPacket(); | |
| 395 testing_clock_.Advance( | |
| 396 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 397 } | |
| 398 // We should now have entered the slowdown ACK state. | |
| 399 uint32 expected_frame_id = 1; | |
| 400 for (; frame_id < 10; ++frame_id) { | |
| 401 if (frame_id % 2) { | |
| 402 ++expected_frame_id; | |
| 403 EXPECT_TRUE(feedback_.triggered()); | |
| 404 } else { | |
| 405 EXPECT_FALSE(feedback_.triggered()); | |
| 406 } | |
| 407 EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked()); | |
| 408 SetFrameIds(frame_id, frame_id - 1); | |
| 409 InsertPacket(); | |
| 410 testing_clock_.Advance( | |
| 411 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 412 } | |
| 413 EXPECT_FALSE(feedback_.triggered()); | |
| 414 EXPECT_EQ(expected_frame_id, feedback_.last_frame_acked()); | |
| 415 | |
| 416 // Simulate frame_id being pulled for rendering. | |
| 417 frame_id_map_.RemoveOldFrames(frame_id); | |
| 418 // We should now leave the slowdown ACK state. | |
| 419 ++frame_id; | |
| 420 SetFrameIds(frame_id, frame_id - 1); | |
| 421 InsertPacket(); | |
| 422 testing_clock_.Advance( | |
| 423 base::TimeDelta::FromMilliseconds(kShortTimeIncrementMs)); | |
| 424 EXPECT_TRUE(feedback_.triggered()); | |
| 425 EXPECT_EQ(frame_id, feedback_.last_frame_acked()); | |
| 426 } | |
| 427 | |
| 428 } // namespace cast | |
| 429 } // namespace media | |
| OLD | NEW |