1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" 12 13 #include <limits> 14 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" 18 19 using webrtc::rtcp::TransportFeedback; 20 21 namespace webrtc { 22 namespace { 23 24 static const int kHeaderSize = 20; 25 static const int kStatusChunkSize = 2; 26 static const int kSmallDeltaSize = 1; 27 static const int kLargeDeltaSize = 2; 28 29 static const int64_t kDeltaLimit = 0xFF * TransportFeedback::kDeltaScaleFactor; 30 31 class FeedbackTester { 32 public: 33 FeedbackTester() 34 : expected_size_(kAnySize), 35 default_delta_(TransportFeedback::kDeltaScaleFactor * 4) {} 36 37 void WithExpectedSize(size_t expected_size) { 38 expected_size_ = expected_size; 39 } 40 41 void WithDefaultDelta(int64_t delta) { default_delta_ = delta; } 42 43 void WithInput(const uint16_t received_seq[], 44 const int64_t received_ts[], 45 uint16_t length) { 46 rtc::scoped_ptr<int64_t[]> temp_deltas; 47 if (received_ts == nullptr) { 48 temp_deltas.reset(new int64_t[length]); 49 GenerateDeltas(received_seq, length, temp_deltas.get()); 50 received_ts = temp_deltas.get(); 51 } 52 53 expected_seq_.clear(); 54 expected_deltas_.clear(); 55 feedback_.reset(new TransportFeedback()); 56 57 feedback_->WithBase(received_seq[0], received_ts[0]); 58 int64_t last_time = feedback_->GetBaseTimeUs(); 59 for (int i = 0; i < length; ++i) { 60 int64_t time = received_ts[i]; 61 EXPECT_TRUE(feedback_->WithReceivedPacket(received_seq[i], time)); 62 63 if (last_time != -1) { 64 int64_t delta = time - last_time; 65 expected_deltas_.push_back(delta); 66 } 67 last_time = time; 68 } 69 expected_seq_.insert(expected_seq_.begin(), &received_seq[0], 70 &received_seq[length]); 71 } 72 73 void VerifyPacket() { 74 serialized_ = feedback_->Build(); 75 VerifyInternal(); 76 feedback_ = TransportFeedback::ParseFrom(serialized_->Buffer(), 77 serialized_->Length()); 78 ASSERT_NE(nullptr, feedback_.get()); 79 VerifyInternal(); 80 } 81 82 static const size_t kAnySize = static_cast<size_t>(0) - 1; 83 84 private: 85 void VerifyInternal() { 86 if (expected_size_ != kAnySize) { 87 // Round up to whole 32-bit words. 88 size_t expected_size_words = (expected_size_ + 3) / 4; 89 size_t expected_size_bytes = expected_size_words * 4; 90 EXPECT_EQ(expected_size_bytes, serialized_->Length()); 91 } 92 93 std::vector<TransportFeedback::StatusSymbol> symbols = 94 feedback_->GetStatusVector(); 95 uint16_t seq = feedback_->GetBaseSequence(); 96 auto seq_it = expected_seq_.begin(); 97 for (TransportFeedback::StatusSymbol symbol : symbols) { 98 bool received = 99 (symbol == TransportFeedback::StatusSymbol::kReceivedSmallDelta || 100 symbol == TransportFeedback::StatusSymbol::kReceivedLargeDelta); 101 if (seq_it != expected_seq_.end()) { 102 if (seq == *seq_it) { 103 ASSERT_NE(expected_seq_.end(), seq_it); 104 ASSERT_TRUE(received) << "Expected received packet @ " << seq; 105 ++seq_it; 106 } else { 107 ASSERT_FALSE(received) << "Did not expect received packet @ " << seq; 108 } 109 } 110 ++seq; 111 } 112 ASSERT_EQ(expected_seq_.end(), seq_it); 113 114 std::vector<int64_t> deltas = feedback_->GetReceiveDeltasUs(); 115 ASSERT_EQ(expected_deltas_.size(), deltas.size()); 116 for (size_t i = 0; i < expected_deltas_.size(); ++i) 117 EXPECT_EQ(expected_deltas_[i], deltas[i]) << "Delta mismatch @ " << i; 118 } 119 120 void GenerateDeltas(const uint16_t seq[], 121 const size_t length, 122 int64_t* deltas) { 123 uint16_t last_seq = seq[0]; 124 int64_t offset = 0; 125 126 for (size_t i = 0; i < length; ++i) { 127 if (seq[i] < last_seq) 128 offset += 0x10000 * default_delta_; 129 last_seq = seq[i]; 130 131 deltas[i] = offset + (last_seq * default_delta_); 132 } 133 } 134 135 std::vector<uint16_t> expected_seq_; 136 std::vector<int64_t> expected_deltas_; 137 size_t expected_size_; 138 int64_t default_delta_; 139 rtc::scoped_ptr<TransportFeedback> feedback_; 140 rtc::scoped_ptr<rtcp::RawPacket> serialized_; 141 }; 142 143 TEST(RtcpPacketTest, TransportFeedback_OneBitVector) { 144 const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13}; 145 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 146 const size_t kExpectedSizeBytes = 147 kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize); 148 149 FeedbackTester test; 150 test.WithExpectedSize(kExpectedSizeBytes); 151 test.WithInput(kReceived, nullptr, kLength); 152 test.VerifyPacket(); 153 } 154 155 TEST(RtcpPacketTest, TransportFeedback_FullOneBitVector) { 156 const uint16_t kReceived[] = {1, 2, 7, 8, 9, 10, 13, 14}; 157 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 158 const size_t kExpectedSizeBytes = 159 kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize); 160 161 FeedbackTester test; 162 test.WithExpectedSize(kExpectedSizeBytes); 163 test.WithInput(kReceived, nullptr, kLength); 164 test.VerifyPacket(); 165 } 166 167 TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapReceived) { 168 const uint16_t kMax = 0xFFFF; 169 const uint16_t kReceived[] = {kMax - 2, kMax - 1, kMax, 0, 1, 2}; 170 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 171 const size_t kExpectedSizeBytes = 172 kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize); 173 174 FeedbackTester test; 175 test.WithExpectedSize(kExpectedSizeBytes); 176 test.WithInput(kReceived, nullptr, kLength); 177 test.VerifyPacket(); 178 } 179 180 TEST(RtcpPacketTest, TransportFeedback_OneBitVector_WrapMissing) { 181 const uint16_t kMax = 0xFFFF; 182 const uint16_t kReceived[] = {kMax - 2, kMax - 1, 1, 2}; 183 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 184 const size_t kExpectedSizeBytes = 185 kHeaderSize + kStatusChunkSize + (kLength * kSmallDeltaSize); 186 187 FeedbackTester test; 188 test.WithExpectedSize(kExpectedSizeBytes); 189 test.WithInput(kReceived, nullptr, kLength); 190 test.VerifyPacket(); 191 } 192 193 TEST(RtcpPacketTest, TransportFeedback_TwoBitVector) { 194 const uint16_t kReceived[] = {1, 2, 6, 7}; 195 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 196 const size_t kExpectedSizeBytes = 197 kHeaderSize + kStatusChunkSize + (kLength * kLargeDeltaSize); 198 199 FeedbackTester test; 200 test.WithExpectedSize(kExpectedSizeBytes); 201 test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaScaleFactor); 202 test.WithInput(kReceived, nullptr, kLength); 203 test.VerifyPacket(); 204 } 205 206 TEST(RtcpPacketTest, TransportFeedback_TwoBitVectorFull) { 207 const uint16_t kReceived[] = {1, 2, 6, 7, 8}; 208 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 209 const size_t kExpectedSizeBytes = 210 kHeaderSize + (2 * kStatusChunkSize) + (kLength * kLargeDeltaSize); 211 212 FeedbackTester test; 213 test.WithExpectedSize(kExpectedSizeBytes); 214 test.WithDefaultDelta(kDeltaLimit + TransportFeedback::kDeltaScaleFactor); 215 test.WithInput(kReceived, nullptr, kLength); 216 test.VerifyPacket(); 217 } 218 219 TEST(RtcpPacketTest, TransportFeedback_LargeAndNegativeDeltas) { 220 const uint16_t kReceived[] = {1, 2, 6, 7, 8}; 221 const int64_t kReceiveTimes[] = { 222 2000, 223 1000, 224 4000, 225 3000, 226 3000 + TransportFeedback::kDeltaScaleFactor * (1 << 8)}; 227 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 228 const size_t kExpectedSizeBytes = 229 kHeaderSize + kStatusChunkSize + (3 * kLargeDeltaSize) + kSmallDeltaSize; 230 231 FeedbackTester test; 232 test.WithExpectedSize(kExpectedSizeBytes); 233 test.WithInput(kReceived, kReceiveTimes, kLength); 234 test.VerifyPacket(); 235 } 236 237 TEST(RtcpPacketTest, TransportFeedback_MaxRle) { 238 // Expected chunks created: 239 // * 1-bit vector chunk (1xreceived + 13xdropped) 240 // * RLE chunk of max length for dropped symbol 241 // * 1-bit vector chunk (1xreceived + 13xdropped) 242 243 const size_t kPacketCount = (1 << 13) - 1 + 14; 244 const uint16_t kReceived[] = {0, kPacketCount}; 245 const int64_t kReceiveTimes[] = {1000, 2000}; 246 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 247 const size_t kExpectedSizeBytes = 248 kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize); 249 250 FeedbackTester test; 251 test.WithExpectedSize(kExpectedSizeBytes); 252 test.WithInput(kReceived, kReceiveTimes, kLength); 253 test.VerifyPacket(); 254 } 255 256 TEST(RtcpPacketTest, TransportFeedback_MinRle) { 257 // Expected chunks created: 258 // * 1-bit vector chunk (1xreceived + 13xdropped) 259 // * RLE chunk of length 15 for dropped symbol 260 // * 1-bit vector chunk (1xreceived + 13xdropped) 261 262 const uint16_t kReceived[] = {0, (14 * 2) + 1}; 263 const int64_t kReceiveTimes[] = {1000, 2000}; 264 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 265 const size_t kExpectedSizeBytes = 266 kHeaderSize + (3 * kStatusChunkSize) + (kLength * kSmallDeltaSize); 267 268 FeedbackTester test; 269 test.WithExpectedSize(kExpectedSizeBytes); 270 test.WithInput(kReceived, kReceiveTimes, kLength); 271 test.VerifyPacket(); 272 } 273 274 TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVector) { 275 const size_t kTwoBitVectorCapacity = 7; 276 const uint16_t kReceived[] = {0, kTwoBitVectorCapacity - 1}; 277 const int64_t kReceiveTimes[] = { 278 0, kDeltaLimit + TransportFeedback::kDeltaScaleFactor}; 279 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 280 const size_t kExpectedSizeBytes = 281 kHeaderSize + kStatusChunkSize + kSmallDeltaSize + kLargeDeltaSize; 282 283 FeedbackTester test; 284 test.WithExpectedSize(kExpectedSizeBytes); 285 test.WithInput(kReceived, kReceiveTimes, kLength); 286 test.VerifyPacket(); 287 } 288 289 TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSimpleSplit) { 290 const size_t kTwoBitVectorCapacity = 7; 291 const uint16_t kReceived[] = {0, kTwoBitVectorCapacity}; 292 const int64_t kReceiveTimes[] = { 293 0, kDeltaLimit + TransportFeedback::kDeltaScaleFactor}; 294 const size_t kLength = sizeof(kReceived) / sizeof(uint16_t); 295 const size_t kExpectedSizeBytes = 296 kHeaderSize + (kStatusChunkSize * 2) + kSmallDeltaSize + kLargeDeltaSize; 297 298 FeedbackTester test; 299 test.WithExpectedSize(kExpectedSizeBytes); 300 test.WithInput(kReceived, kReceiveTimes, kLength); 301 test.VerifyPacket(); 302 } 303 304 TEST(RtcpPacketTest, TransportFeedback_OneToTwoBitVectorSplit) { 305 // With received small delta = S, received large delta = L, use input 306 // SSSSSSSSLSSSSSSSSSSSS. This will cause a 1:2 split at the L. 307 // After split there will be two symbols in symbol_vec: SL. 308 309 const int64_t kLargeDelta = TransportFeedback::kDeltaScaleFactor * (1 << 8); 310 const size_t kNumPackets = (3 * 7) + 1; 311 const size_t kExpectedSizeBytes = kHeaderSize + (kStatusChunkSize * 3) + 312 (kSmallDeltaSize * (kNumPackets - 1)) + 313 (kLargeDeltaSize * 1); 314 315 uint16_t kReceived[kNumPackets]; 316 for (size_t i = 0; i < kNumPackets; ++i) 317 kReceived[i] = i; 318 319 int64_t kReceiveTimes[kNumPackets]; 320 kReceiveTimes[0] = 1000; 321 for (size_t i = 1; i < kNumPackets; ++i) { 322 int delta = (i == 8) ? kLargeDelta : 1000; 323 kReceiveTimes[i] = kReceiveTimes[i - 1] + delta; 324 } 325 326 FeedbackTester test; 327 test.WithExpectedSize(kExpectedSizeBytes); 328 test.WithInput(kReceived, kReceiveTimes, kNumPackets); 329 test.VerifyPacket(); 330 } 331 332 TEST(RtcpPacketTest, TransportFeedback_Aliasing) { 333 TransportFeedback feedback; 334 feedback.WithBase(0, 0); 335 336 const int kSamples = 100; 337 const int64_t kTooSmallDelta = TransportFeedback::kDeltaScaleFactor / 3; 338 339 for (int i = 0; i < kSamples; ++i) 340 feedback.WithReceivedPacket(i, i * kTooSmallDelta); 341 342 feedback.Build(); 343 std::vector<int64_t> deltas = feedback.GetReceiveDeltasUs(); 344 345 int64_t accumulated_delta = 0; 346 int num_samples = 0; 347 for (int64_t delta : deltas) { 348 accumulated_delta += delta; 349 int64_t expected_time = num_samples * kTooSmallDelta; 350 ++num_samples; 351 352 EXPECT_NEAR(expected_time, accumulated_delta, 353 TransportFeedback::kDeltaScaleFactor / 2); 354 } 355 } 356 357 TEST(RtcpPacketTest, TransportFeedback_Limits) { 358 // Sequence number wrap above 0x8000. 359 rtc::scoped_ptr<TransportFeedback> packet(new TransportFeedback()); 360 packet->WithBase(0, 0); 361 EXPECT_TRUE(packet->WithReceivedPacket(0x8000, 1000)); 362 363 packet.reset(new TransportFeedback()); 364 packet->WithBase(0, 0); 365 EXPECT_FALSE(packet->WithReceivedPacket(0x8000 + 1, 1000)); 366 367 // Packet status count max 0xFFFF. 368 packet.reset(new TransportFeedback()); 369 packet->WithBase(0, 0); 370 EXPECT_TRUE(packet->WithReceivedPacket(0x8000, 1000)); 371 EXPECT_TRUE(packet->WithReceivedPacket(0xFFFF, 2000)); 372 EXPECT_FALSE(packet->WithReceivedPacket(0, 3000)); 373 374 // Too large delta. 375 packet.reset(new TransportFeedback()); 376 packet->WithBase(0, 0); 377 int64_t kMaxPositiveTimeDelta = std::numeric_limits<int16_t>::max() * 378 TransportFeedback::kDeltaScaleFactor; 379 EXPECT_FALSE(packet->WithReceivedPacket( 380 1, kMaxPositiveTimeDelta + TransportFeedback::kDeltaScaleFactor)); 381 EXPECT_TRUE(packet->WithReceivedPacket(1, kMaxPositiveTimeDelta)); 382 383 // Too large negative delta. 384 packet.reset(new TransportFeedback()); 385 packet->WithBase(0, 0); 386 int64_t kMaxNegativeTimeDelta = std::numeric_limits<int16_t>::min() * 387 TransportFeedback::kDeltaScaleFactor; 388 EXPECT_FALSE(packet->WithReceivedPacket( 389 1, kMaxNegativeTimeDelta - TransportFeedback::kDeltaScaleFactor)); 390 EXPECT_TRUE(packet->WithReceivedPacket(1, kMaxNegativeTimeDelta)); 391 392 // Base time at maximum value. 393 int64_t kMaxBaseTime = 394 static_cast<int64_t>(TransportFeedback::kDeltaScaleFactor) * (1L << 8) * 395 ((1L << 23) - 1); 396 packet.reset(new TransportFeedback()); 397 packet->WithBase(0, kMaxBaseTime); 398 packet->WithReceivedPacket(0, kMaxBaseTime); 399 // Serialize and de-serialize (verify 24bit parsing). 400 rtc::scoped_ptr<rtcp::RawPacket> raw_packet = packet->Build(); 401 packet = 402 TransportFeedback::ParseFrom(raw_packet->Buffer(), raw_packet->Length()); 403 EXPECT_EQ(kMaxBaseTime, packet->GetBaseTimeUs()); 404 405 // Base time above maximum value. 406 int64_t kTooLargeBaseTime = 407 kMaxBaseTime + (TransportFeedback::kDeltaScaleFactor * (1L << 8)); 408 packet.reset(new TransportFeedback()); 409 packet->WithBase(0, kTooLargeBaseTime); 410 packet->WithReceivedPacket(0, kTooLargeBaseTime); 411 raw_packet = packet->Build(); 412 packet = 413 TransportFeedback::ParseFrom(raw_packet->Buffer(), raw_packet->Length()); 414 EXPECT_NE(kTooLargeBaseTime, packet->GetBaseTimeUs()); 415 416 // TODO(sprang): Once we support max length lower than RTCP length limit, 417 // add back test for max size in bytes. 418 } 419 420 TEST(RtcpPacketTest, TransportFeedback_Padding) { 421 const size_t kExpectedSizeBytes = 422 kHeaderSize + kStatusChunkSize + kSmallDeltaSize; 423 const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4; 424 425 TransportFeedback feedback; 426 feedback.WithBase(0, 0); 427 EXPECT_TRUE(feedback.WithReceivedPacket(0, 0)); 428 429 rtc::scoped_ptr<rtcp::RawPacket> packet(feedback.Build()); 430 EXPECT_EQ(kExpectedSizeWords * 4, packet->Length()); 431 ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes); 432 for (size_t i = kExpectedSizeBytes; i < kExpectedSizeWords * 4; ++i) 433 EXPECT_EQ(0u, packet->Buffer()[i]); 434 435 // Modify packet by adding 4 bytes of padding at the end. Not currently used 436 // when we're sending, but need to be able to handle it when receiving. 437 438 const int kPaddingBytes = 4; 439 const size_t kExpectedSizeWithPadding = 440 (kExpectedSizeWords * 4) + kPaddingBytes; 441 uint8_t mod_buffer[kExpectedSizeWithPadding]; 442 memcpy(mod_buffer, packet->Buffer(), kExpectedSizeWords * 4); 443 memset(&mod_buffer[kExpectedSizeWords * 4], 0, kPaddingBytes - 1); 444 mod_buffer[kExpectedSizeWithPadding - 1] = kPaddingBytes; 445 const uint8_t padding_flag = 1 << 5; 446 mod_buffer[0] |= padding_flag; 447 ByteWriter<uint16_t>::WriteBigEndian( 448 &mod_buffer[2], ByteReader<uint16_t>::ReadBigEndian(&mod_buffer[2]) + 449 ((kPaddingBytes + 3) / 4)); 450 451 rtc::scoped_ptr<TransportFeedback> parsed_packet( 452 TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWithPadding)); 453 ASSERT_TRUE(parsed_packet.get() != nullptr); 454 EXPECT_EQ(kExpectedSizeWords * 4, packet->Length()); // Padding not included. 455 } 456 457 TEST(RtcpPacketTest, TransportFeedback_CorrectlySplitsVectorChunks) { 458 const int kOneBitVectorCapacity = 14; 459 const int64_t kLargeTimeDelta = 460 TransportFeedback::kDeltaScaleFactor * (1 << 8); 461 462 // Test that a number of small deltas followed by a large delta results in a 463 // correct split into multiple chunks, as needed. 464 465 for (int deltas = 0; deltas <= kOneBitVectorCapacity + 1; ++deltas) { 466 TransportFeedback feedback; 467 feedback.WithBase(0, 0); 468 for (int i = 0; i < deltas; ++i) 469 feedback.WithReceivedPacket(i, i * 1000); 470 feedback.WithReceivedPacket(deltas, deltas * 1000 + kLargeTimeDelta); 471 472 rtc::scoped_ptr<rtcp::RawPacket> serialized_packet = feedback.Build(); 473 EXPECT_TRUE(serialized_packet.get() != nullptr); 474 rtc::scoped_ptr<TransportFeedback> deserialized_packet = 475 TransportFeedback::ParseFrom(serialized_packet->Buffer(), 476 serialized_packet->Length()); 477 EXPECT_TRUE(deserialized_packet.get() != nullptr); 478 } 479 } 480 481 } // namespace 482 } // namespace webrtc 483