OLD | NEW |
(Empty) | |
| 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 // TODO(sprang): Once we support max length lower than RTCP length limit, |
| 393 // add back test for max size in bytes. |
| 394 } |
| 395 |
| 396 TEST(RtcpPacketTest, TransportFeedback_Padding) { |
| 397 const size_t kExpectedSizeBytes = |
| 398 kHeaderSize + kStatusChunkSize + kSmallDeltaSize; |
| 399 const size_t kExpectedSizeWords = (kExpectedSizeBytes + 3) / 4; |
| 400 |
| 401 TransportFeedback feedback; |
| 402 feedback.WithBase(0, 0); |
| 403 EXPECT_TRUE(feedback.WithReceivedPacket(0, 0)); |
| 404 |
| 405 rtc::scoped_ptr<rtcp::RawPacket> packet(feedback.Build()); |
| 406 EXPECT_EQ(kExpectedSizeWords * 4, packet->Length()); |
| 407 ASSERT_GT(kExpectedSizeWords * 4, kExpectedSizeBytes); |
| 408 for (size_t i = kExpectedSizeBytes; i < kExpectedSizeWords * 4; ++i) |
| 409 EXPECT_EQ(0u, packet->Buffer()[i]); |
| 410 |
| 411 // Modify packet by adding 4 bytes of padding at the end. Not currently used |
| 412 // when we're sending, but need to be able to handle it when receiving. |
| 413 |
| 414 const int kPaddingBytes = 4; |
| 415 const size_t kExpectedSizeWithPadding = |
| 416 (kExpectedSizeWords * 4) + kPaddingBytes; |
| 417 uint8_t mod_buffer[kExpectedSizeWithPadding]; |
| 418 memcpy(mod_buffer, packet->Buffer(), kExpectedSizeWords * 4); |
| 419 memset(&mod_buffer[kExpectedSizeWords * 4], 0, kPaddingBytes - 1); |
| 420 mod_buffer[kExpectedSizeWithPadding - 1] = kPaddingBytes; |
| 421 const uint8_t padding_flag = 1 << 5; |
| 422 mod_buffer[0] |= padding_flag; |
| 423 ByteWriter<uint16_t>::WriteBigEndian( |
| 424 &mod_buffer[2], ByteReader<uint16_t>::ReadBigEndian(&mod_buffer[2]) + |
| 425 ((kPaddingBytes + 3) / 4)); |
| 426 |
| 427 rtc::scoped_ptr<TransportFeedback> parsed_packet( |
| 428 TransportFeedback::ParseFrom(mod_buffer, kExpectedSizeWithPadding)); |
| 429 ASSERT_TRUE(parsed_packet.get() != nullptr); |
| 430 EXPECT_EQ(kExpectedSizeWords * 4, packet->Length()); // Padding not included. |
| 431 } |
| 432 |
| 433 } // namespace |
| 434 } // namespace webrtc |
OLD | NEW |