Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(492)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc

Issue 1175263002: Add packetization and coding/decoding of feedback message format. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Make size constants unsigned Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698