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

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

Powered by Google App Engine
This is Rietveld 408576698