blob: b3fa25bf4fbe6b969b86c8648524e16556be4edd [file] [log] [blame]
minyue022a2832017-01-23 16:07:051/*
2 * Copyright (c) 2017 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#include <memory>
elad.alon5f254892017-03-03 18:51:3513#include <numeric>
minyue022a2832017-01-23 16:07:0514#include <vector>
15
elad.alona6a45e62017-03-21 14:31:3516#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
minyue022a2832017-01-23 16:07:0517#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
Edward Lemur76de83e2017-07-06 17:44:3418#include "webrtc/rtc_base/checks.h"
minyue022a2832017-01-23 16:07:0519#include "webrtc/test/gmock.h"
20#include "webrtc/test/gtest.h"
21#include "webrtc/voice_engine/transport_feedback_packet_loss_tracker.h"
22
minyue022a2832017-01-23 16:07:0523namespace webrtc {
24
25namespace {
26
elad.alon8132e172017-03-21 12:58:0427constexpr int64_t kDefaultSendIntervalMs = 10;
28constexpr int64_t kDefaultMaxWindowSizeMs = 500 * kDefaultSendIntervalMs;
29
elad.alond24531a2017-03-03 19:11:0630class TransportFeedbackPacketLossTrackerTest
31 : public ::testing::TestWithParam<uint16_t> {
32 public:
33 TransportFeedbackPacketLossTrackerTest() = default;
34 virtual ~TransportFeedbackPacketLossTrackerTest() = default;
35
36 protected:
elad.alonde1cc662017-03-15 14:38:1337 void SendPackets(TransportFeedbackPacketLossTracker* tracker,
38 const std::vector<uint16_t>& sequence_numbers,
39 int64_t send_time_interval_ms,
40 bool validate_all = true) {
41 RTC_CHECK_GE(send_time_interval_ms, 0);
42 for (uint16_t sequence_number : sequence_numbers) {
43 tracker->OnPacketAdded(sequence_number, time_ms_);
44 if (validate_all) {
45 tracker->Validate();
46 }
47 time_ms_ += send_time_interval_ms;
48 }
elad.alond24531a2017-03-03 19:11:0649
elad.alonde1cc662017-03-15 14:38:1350 // We've either validated after each packet, or, for making sure the UT
51 // doesn't run too long, we might validate only at the end of the range.
52 if (!validate_all) {
elad.alon5f254892017-03-03 18:51:3553 tracker->Validate();
54 }
55 }
56
elad.alonde1cc662017-03-15 14:38:1357 void SendPackets(TransportFeedbackPacketLossTracker* tracker,
58 uint16_t first_seq_num,
59 size_t num_of_packets,
60 int64_t send_time_interval_ms,
61 bool validate_all = true) {
62 RTC_CHECK_GE(send_time_interval_ms, 0);
63 std::vector<uint16_t> sequence_numbers(num_of_packets);
64 std::iota(sequence_numbers.begin(), sequence_numbers.end(), first_seq_num);
65 SendPackets(tracker, sequence_numbers, send_time_interval_ms, validate_all);
66 }
67
68 void AdvanceClock(int64_t time_delta_ms) {
69 RTC_CHECK_GT(time_delta_ms, 0);
70 time_ms_ += time_delta_ms;
71 }
72
73 void AddTransportFeedbackAndValidate(
74 TransportFeedbackPacketLossTracker* tracker,
75 uint16_t base_sequence_num,
76 const std::vector<bool>& reception_status_vec) {
elad.alona6a45e62017-03-21 14:31:3577 // Any positive integer signals reception. kNotReceived signals loss.
78 // Other values are just illegal.
79 constexpr int64_t kArrivalTimeMs = 1234;
80
81 std::vector<PacketFeedback> packet_feedback_vector;
82 uint16_t seq_num = base_sequence_num;
83 for (bool received : reception_status_vec) {
84 packet_feedback_vector.emplace_back(PacketFeedback(
85 received ? kArrivalTimeMs : PacketFeedback::kNotReceived, seq_num));
86 ++seq_num;
elad.alonde1cc662017-03-15 14:38:1387 }
88
elad.alon49d19872017-03-23 18:04:4889 tracker->OnPacketFeedbackVector(packet_feedback_vector);
elad.alon5f254892017-03-03 18:51:3590 tracker->Validate();
91 }
elad.alon5f254892017-03-03 18:51:3592
elad.alonde1cc662017-03-15 14:38:1393 // Checks that validty is as expected. If valid, checks also that
94 // value is as expected.
95 void ValidatePacketLossStatistics(
96 const TransportFeedbackPacketLossTracker& tracker,
97 rtc::Optional<float> expected_plr,
98 rtc::Optional<float> expected_rplr) {
eladalonb11cc612017-05-25 07:15:3599 // TODO(eladalon): Comparing the rtc::Optional<float> directly would have
elad.alonde1cc662017-03-15 14:38:13100 // given concise code, but less readable error messages. If we modify
101 // the way rtc::Optional is printed, we can get rid of this.
102 rtc::Optional<float> plr = tracker.GetPacketLossRate();
103 EXPECT_EQ(static_cast<bool>(expected_plr), static_cast<bool>(plr));
104 if (expected_plr && plr) {
105 EXPECT_EQ(*expected_plr, *plr);
106 }
elad.alon5f254892017-03-03 18:51:35107
elad.alonde1cc662017-03-15 14:38:13108 rtc::Optional<float> rplr = tracker.GetRecoverablePacketLossRate();
109 EXPECT_EQ(static_cast<bool>(expected_rplr), static_cast<bool>(rplr));
110 if (expected_rplr && rplr) {
111 EXPECT_EQ(*expected_rplr, *rplr);
112 }
minyue022a2832017-01-23 16:07:05113 }
elad.alond35e1022017-02-01 16:36:09114
elad.alonde1cc662017-03-15 14:38:13115 // Convenience function for when both are valid, and explicitly stating
116 // the rtc::Optional<float> constructor is just cumbersome.
117 void ValidatePacketLossStatistics(
118 const TransportFeedbackPacketLossTracker& tracker,
119 float expected_plr,
120 float expected_rplr) {
121 ValidatePacketLossStatistics(tracker, rtc::Optional<float>(expected_plr),
122 rtc::Optional<float>(expected_rplr));
elad.alond35e1022017-02-01 16:36:09123 }
124
elad.alonde1cc662017-03-15 14:38:13125 uint16_t base_{GetParam()};
minyue022a2832017-01-23 16:07:05126
elad.alonde1cc662017-03-15 14:38:13127 private:
128 int64_t time_ms_{0};
elad.alond35e1022017-02-01 16:36:09129
elad.alonde1cc662017-03-15 14:38:13130 RTC_DISALLOW_COPY_AND_ASSIGN(TransportFeedbackPacketLossTrackerTest);
131};
elad.alond35e1022017-02-01 16:36:09132
minyue022a2832017-01-23 16:07:05133} // namespace
134
135// Sanity check on an empty window.
elad.alonde1cc662017-03-15 14:38:13136TEST_P(TransportFeedbackPacketLossTrackerTest, EmptyWindow) {
elad.alon8132e172017-03-21 12:58:04137 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 5);
minyue022a2832017-01-23 16:07:05138
elad.alond35e1022017-02-01 16:36:09139 // PLR and RPLR reported as unknown before reception of first feedback.
140 ValidatePacketLossStatistics(tracker,
141 rtc::Optional<float>(),
142 rtc::Optional<float>());
minyue022a2832017-01-23 16:07:05143}
144
elad.alon5f254892017-03-03 18:51:35145// A feedback received for an empty window has no effect.
elad.alond24531a2017-03-03 19:11:06146TEST_P(TransportFeedbackPacketLossTrackerTest, EmptyWindowFeedback) {
elad.alon8132e172017-03-21 12:58:04147 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 3, 2);
elad.alon5f254892017-03-03 18:51:35148
elad.alond24531a2017-03-03 19:11:06149 // Feedback doesn't correspond to any packets - ignored.
150 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
151 ValidatePacketLossStatistics(tracker,
152 rtc::Optional<float>(),
153 rtc::Optional<float>());
elad.alon5f254892017-03-03 18:51:35154
elad.alond24531a2017-03-03 19:11:06155 // After the packets are transmitted, acking them would have an effect.
elad.alon8132e172017-03-21 12:58:04156 SendPackets(&tracker, base_, 3, kDefaultSendIntervalMs);
elad.alond24531a2017-03-03 19:11:06157 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
158 ValidatePacketLossStatistics(tracker, 1.0f / 3.0f, 0.5f);
elad.alon5f254892017-03-03 18:51:35159}
160
minyue022a2832017-01-23 16:07:05161// Sanity check on partially filled window.
elad.alond24531a2017-03-03 19:11:06162TEST_P(TransportFeedbackPacketLossTrackerTest, PartiallyFilledWindow) {
elad.alon8132e172017-03-21 12:58:04163 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
minyue022a2832017-01-23 16:07:05164
elad.alond24531a2017-03-03 19:11:06165 // PLR unknown before minimum window size reached.
166 // RPLR unknown before minimum pairs reached.
167 // Expected window contents: [] -> [1001].
elad.alon8132e172017-03-21 12:58:04168 SendPackets(&tracker, base_, 3, kDefaultSendIntervalMs);
elad.alond24531a2017-03-03 19:11:06169 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, false, true});
170 ValidatePacketLossStatistics(tracker,
171 rtc::Optional<float>(),
172 rtc::Optional<float>());
minyue022a2832017-01-23 16:07:05173}
174
elad.alond35e1022017-02-01 16:36:09175// Sanity check on minimum filled window - PLR known, RPLR unknown.
elad.alond24531a2017-03-03 19:11:06176TEST_P(TransportFeedbackPacketLossTrackerTest, PlrMinimumFilledWindow) {
elad.alon8132e172017-03-21 12:58:04177 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 5);
minyue022a2832017-01-23 16:07:05178
elad.alond24531a2017-03-03 19:11:06179 // PLR correctly calculated after minimum window size reached.
180 // RPLR not necessarily known at that time (not if min-pairs not reached).
181 // Expected window contents: [] -> [10011].
elad.alon8132e172017-03-21 12:58:04182 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alond24531a2017-03-03 19:11:06183 AddTransportFeedbackAndValidate(&tracker, base_,
184 {true, false, false, true, true});
185 ValidatePacketLossStatistics(tracker,
186 rtc::Optional<float>(2.0f / 5.0f),
187 rtc::Optional<float>());
minyue022a2832017-01-23 16:07:05188}
189
elad.alond35e1022017-02-01 16:36:09190// Sanity check on minimum filled window - PLR unknown, RPLR known.
elad.alond24531a2017-03-03 19:11:06191TEST_P(TransportFeedbackPacketLossTrackerTest, RplrMinimumFilledWindow) {
elad.alon8132e172017-03-21 12:58:04192 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 6, 4);
elad.alond35e1022017-02-01 16:36:09193
elad.alond24531a2017-03-03 19:11:06194 // RPLR correctly calculated after minimum pairs reached.
195 // PLR not necessarily known at that time (not if min window not reached).
196 // Expected window contents: [] -> [10011].
elad.alon8132e172017-03-21 12:58:04197 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alond24531a2017-03-03 19:11:06198 AddTransportFeedbackAndValidate(&tracker, base_,
199 {true, false, false, true, true});
200 ValidatePacketLossStatistics(tracker,
201 rtc::Optional<float>(),
202 rtc::Optional<float>(1.0f / 4.0f));
elad.alond35e1022017-02-01 16:36:09203}
204
elad.alonde1cc662017-03-15 14:38:13205// If packets are sent close enough together that the clock reading for both
206// is the same, that's handled properly.
207TEST_P(TransportFeedbackPacketLossTrackerTest, SameSentTime) {
elad.alon8132e172017-03-21 12:58:04208 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 3, 2);
elad.alonde1cc662017-03-15 14:38:13209
210 // Expected window contents: [] -> [101].
211 SendPackets(&tracker, base_, 3, 0); // Note: time interval = 0ms.
212 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
213
214 ValidatePacketLossStatistics(tracker, 1.0f / 3.0f, 0.5f);
215}
216
elad.alond35e1022017-02-01 16:36:09217// Additional reports update PLR and RPLR.
elad.alond24531a2017-03-03 19:11:06218TEST_P(TransportFeedbackPacketLossTrackerTest, ExtendWindow) {
elad.alon8132e172017-03-21 12:58:04219 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 5);
minyue022a2832017-01-23 16:07:05220
elad.alon8132e172017-03-21 12:58:04221 SendPackets(&tracker, base_, 25, kDefaultSendIntervalMs);
elad.alon5f254892017-03-03 18:51:35222
elad.alond24531a2017-03-03 19:11:06223 // Expected window contents: [] -> [10011].
224 AddTransportFeedbackAndValidate(&tracker, base_,
225 {true, false, false, true, true});
226 ValidatePacketLossStatistics(tracker,
227 rtc::Optional<float>(2.0f / 5.0f),
228 rtc::Optional<float>());
minyue022a2832017-01-23 16:07:05229
elad.alond24531a2017-03-03 19:11:06230 // Expected window contents: [10011] -> [1001110101].
231 AddTransportFeedbackAndValidate(&tracker, base_ + 5,
232 {true, false, true, false, true});
233 ValidatePacketLossStatistics(tracker, 4.0f / 10.0f, 3.0f / 9.0f);
minyue022a2832017-01-23 16:07:05234
elad.alond24531a2017-03-03 19:11:06235 // Expected window contents: [1001110101] -> [1001110101-GAP-10001].
236 AddTransportFeedbackAndValidate(&tracker, base_ + 20,
237 {true, false, false, false, true});
238 ValidatePacketLossStatistics(tracker, 7.0f / 15.0f, 4.0f / 13.0f);
minyue022a2832017-01-23 16:07:05239}
240
elad.alonde1cc662017-03-15 14:38:13241// Correct calculation with different packet lengths.
242TEST_P(TransportFeedbackPacketLossTrackerTest, DifferentSentIntervals) {
elad.alon8132e172017-03-21 12:58:04243 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
elad.alonde1cc662017-03-15 14:38:13244
elad.alonde1cc662017-03-15 14:38:13245 int64_t frames[] = {20, 60, 120, 20, 60};
246 for (size_t i = 0; i < sizeof(frames) / sizeof(frames[0]); i++) {
elad.alon8132e172017-03-21 12:58:04247 SendPackets(&tracker, {static_cast<uint16_t>(base_ + i)}, frames[i]);
elad.alonde1cc662017-03-15 14:38:13248 }
249
250 // Expected window contents: [] -> [10011].
251 AddTransportFeedbackAndValidate(&tracker, base_,
252 {true, false, false, true, true});
253 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
254}
255
256// The window retains information up to sent times that exceed the the max
257// window size. The oldest packets get shifted out of window to make room
258// for the newer ones.
259TEST_P(TransportFeedbackPacketLossTrackerTest, MaxWindowSize) {
elad.alon8132e172017-03-21 12:58:04260 TransportFeedbackPacketLossTracker tracker(4 * kDefaultSendIntervalMs, 5, 1);
elad.alonde1cc662017-03-15 14:38:13261
elad.alon8132e172017-03-21 12:58:04262 SendPackets(&tracker, base_, 6, kDefaultSendIntervalMs, true);
elad.alonde1cc662017-03-15 14:38:13263
elad.alon8132e172017-03-21 12:58:04264 // Up to the maximum time-span retained (first + 4 * kDefaultSendIntervalMs).
elad.alonde1cc662017-03-15 14:38:13265 // Expected window contents: [] -> [01001].
266 AddTransportFeedbackAndValidate(&tracker, base_,
267 {false, true, false, false, true});
268 ValidatePacketLossStatistics(tracker, 3.0f / 5.0f, 2.0f / 4.0f);
269
270 // After the maximum time-span, older entries are discarded to accommodate
271 // newer ones.
272 // Expected window contents: [01001] -> [10011].
273 AddTransportFeedbackAndValidate(&tracker, base_ + 5, {true});
274 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
275}
276
277// All packets received.
elad.alond24531a2017-03-03 19:11:06278TEST_P(TransportFeedbackPacketLossTrackerTest, AllReceived) {
elad.alon8132e172017-03-21 12:58:04279 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
minyue022a2832017-01-23 16:07:05280
elad.alond24531a2017-03-03 19:11:06281 // Expected window contents: [] -> [11111].
elad.alon8132e172017-03-21 12:58:04282 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alond24531a2017-03-03 19:11:06283 AddTransportFeedbackAndValidate(&tracker, base_,
284 {true, true, true, true, true});
285 ValidatePacketLossStatistics(tracker, 0.0f, 0.0f);
minyue022a2832017-01-23 16:07:05286}
287
elad.alonde1cc662017-03-15 14:38:13288// All packets lost.
elad.alond24531a2017-03-03 19:11:06289TEST_P(TransportFeedbackPacketLossTrackerTest, AllLost) {
elad.alon8132e172017-03-21 12:58:04290 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
elad.alon5f254892017-03-03 18:51:35291
elad.alonde1cc662017-03-15 14:38:13292 // Note: The last packet in the feedback does not belong to the stream.
293 // It's only there because we're not allowed to end a feedback with a loss.
elad.alond24531a2017-03-03 19:11:06294 // Expected window contents: [] -> [00000].
elad.alon8132e172017-03-21 12:58:04295 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alond24531a2017-03-03 19:11:06296 AddTransportFeedbackAndValidate(&tracker, base_,
297 {false, false, false, false, false, true});
298 ValidatePacketLossStatistics(tracker, 1.0f, 0.0f);
elad.alon5f254892017-03-03 18:51:35299}
300
minyue022a2832017-01-23 16:07:05301// Repeated reports are ignored.
elad.alond24531a2017-03-03 19:11:06302TEST_P(TransportFeedbackPacketLossTrackerTest, ReportRepetition) {
elad.alon8132e172017-03-21 12:58:04303 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
minyue022a2832017-01-23 16:07:05304
elad.alon8132e172017-03-21 12:58:04305 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alon5f254892017-03-03 18:51:35306
elad.alond24531a2017-03-03 19:11:06307 // Expected window contents: [] -> [10011].
308 AddTransportFeedbackAndValidate(&tracker, base_,
309 {true, false, false, true, true});
310 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue022a2832017-01-23 16:07:05311
elad.alond24531a2017-03-03 19:11:06312 // Repeat entire previous feedback
313 // Expected window contents: [10011] -> [10011].
314 AddTransportFeedbackAndValidate(&tracker, base_,
315 {true, false, false, true, true});
316 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue022a2832017-01-23 16:07:05317}
318
319// Report overlap.
elad.alond24531a2017-03-03 19:11:06320TEST_P(TransportFeedbackPacketLossTrackerTest, ReportOverlap) {
elad.alon8132e172017-03-21 12:58:04321 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 1);
minyue022a2832017-01-23 16:07:05322
elad.alon8132e172017-03-21 12:58:04323 SendPackets(&tracker, base_, 15, kDefaultSendIntervalMs);
elad.alon5f254892017-03-03 18:51:35324
elad.alond24531a2017-03-03 19:11:06325 // Expected window contents: [] -> [10011].
326 AddTransportFeedbackAndValidate(&tracker, base_,
327 {true, false, false, true, true});
328 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue022a2832017-01-23 16:07:05329
elad.alond24531a2017-03-03 19:11:06330 // Expected window contents: [10011] -> [1001101].
331 AddTransportFeedbackAndValidate(&tracker, base_ + 3,
332 {true, true, false, true});
333 ValidatePacketLossStatistics(tracker, 3.0f / 7.0f, 2.0f / 6.0f);
minyue022a2832017-01-23 16:07:05334}
335
336// Report conflict.
elad.alond24531a2017-03-03 19:11:06337TEST_P(TransportFeedbackPacketLossTrackerTest, ReportConflict) {
elad.alon8132e172017-03-21 12:58:04338 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
minyue022a2832017-01-23 16:07:05339
elad.alonde1cc662017-03-15 14:38:13340 SendPackets(&tracker, base_, 15, 10);
elad.alon5f254892017-03-03 18:51:35341
elad.alond24531a2017-03-03 19:11:06342 // Expected window contents: [] -> [01001].
343 AddTransportFeedbackAndValidate(&tracker, base_,
344 {false, true, false, false, true});
345 ValidatePacketLossStatistics(tracker, 3.0f / 5.0f, 2.0f / 4.0f);
minyue022a2832017-01-23 16:07:05346
elad.alond24531a2017-03-03 19:11:06347 // Expected window contents: [01001] -> [11101].
348 // While false->true will be applied, true -> false will be ignored.
349 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
350 ValidatePacketLossStatistics(tracker, 1.0f / 5.0f, 1.0f / 4.0f);
minyue022a2832017-01-23 16:07:05351}
352
353// Skipped packets treated as unknown (not lost).
elad.alond24531a2017-03-03 19:11:06354TEST_P(TransportFeedbackPacketLossTrackerTest, SkippedPackets) {
elad.alon8132e172017-03-21 12:58:04355 TransportFeedbackPacketLossTracker tracker(200 * kDefaultSendIntervalMs, 5,
356 1);
minyue022a2832017-01-23 16:07:05357
elad.alon8132e172017-03-21 12:58:04358 SendPackets(&tracker, base_, 200, kDefaultSendIntervalMs);
elad.alon5f254892017-03-03 18:51:35359
elad.alond24531a2017-03-03 19:11:06360 // Expected window contents: [] -> [10011].
361 AddTransportFeedbackAndValidate(&tracker, base_,
362 {true, false, false, true, true});
363 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue022a2832017-01-23 16:07:05364
elad.alond24531a2017-03-03 19:11:06365 // Expected window contents: [10011] -> [10011-GAP-101].
366 AddTransportFeedbackAndValidate(&tracker, base_ + 100, {true, false, true});
367 ValidatePacketLossStatistics(tracker, 3.0f / 8.0f, 2.0f / 6.0f);
minyue022a2832017-01-23 16:07:05368}
369
elad.alonde1cc662017-03-15 14:38:13370// Moving a window, if it excludes some old acked messages, can leave
371// in-window unacked messages intact, and ready to be used later.
372TEST_P(TransportFeedbackPacketLossTrackerTest, MovedWindowRetainsRelevantInfo) {
373 constexpr int64_t max_window_size_ms = 100;
374 TransportFeedbackPacketLossTracker tracker(max_window_size_ms, 5, 1);
minyue022a2832017-01-23 16:07:05375
elad.alonde1cc662017-03-15 14:38:13376 // Note: All messages in this test are sent 1ms apart from each other.
377 // Therefore, the delta in sequence numbers equals the timestamps delta.
378 SendPackets(&tracker, base_, 4 * max_window_size_ms, 1);
elad.alon5f254892017-03-03 18:51:35379
elad.alond24531a2017-03-03 19:11:06380 // Expected window contents: [] -> [10101].
381 AddTransportFeedbackAndValidate(&tracker, base_,
382 {true, false, true, false, true});
383 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 2.0f / 4.0f);
minyue022a2832017-01-23 16:07:05384
elad.alonde1cc662017-03-15 14:38:13385 // Expected window contents: [10101] -> [100011].
386 const int64_t moved_oldest_acked = base_ + 2 * max_window_size_ms;
387 const std::vector<bool> feedback = {true, false, false, false, true, true};
388 AddTransportFeedbackAndValidate(&tracker, moved_oldest_acked, feedback);
389 ValidatePacketLossStatistics(tracker, 3.0f / 6.0f, 1.0f / 5.0f);
minyue022a2832017-01-23 16:07:05390
elad.alonde1cc662017-03-15 14:38:13391 // Having acked |feedback.size()| starting with |moved_oldest_acked|, the
392 // newest of the acked ones is now:
393 const int64_t moved_newest_acked = moved_oldest_acked + feedback.size() - 1;
394
395 // Messages that *are* more than the span-limit away from the newest
396 // acked message *are* too old. Acking them would have no effect.
397 AddTransportFeedbackAndValidate(
398 &tracker, moved_newest_acked - max_window_size_ms - 1, {true});
399 ValidatePacketLossStatistics(tracker, 3.0f / 6.0f, 1.0f / 5.0f);
400
401 // Messages that are *not* more than the span-limit away from the newest
402 // acked message are *not* too old. Acking them would have an effect.
403 AddTransportFeedbackAndValidate(
404 &tracker, moved_newest_acked - max_window_size_ms, {true});
405 ValidatePacketLossStatistics(tracker, 3.0f / 7.0f, 1.0f / 5.0f);
minyue022a2832017-01-23 16:07:05406}
407
elad.alonde1cc662017-03-15 14:38:13408// Inserting feedback into the middle of a window works correctly - can
elad.alon5f254892017-03-03 18:51:35409// complete two pairs.
elad.alond24531a2017-03-03 19:11:06410TEST_P(TransportFeedbackPacketLossTrackerTest, InsertionCompletesTwoPairs) {
elad.alon8132e172017-03-21 12:58:04411 TransportFeedbackPacketLossTracker tracker(150 * kDefaultSendIntervalMs, 5,
412 1);
elad.alond35e1022017-02-01 16:36:09413
elad.alon8132e172017-03-21 12:58:04414 SendPackets(&tracker, base_, 15, kDefaultSendIntervalMs);
elad.alon5f254892017-03-03 18:51:35415
elad.alond24531a2017-03-03 19:11:06416 // Expected window contents: [] -> [10111].
417 AddTransportFeedbackAndValidate(&tracker, base_,
418 {true, false, true, true, true});
419 ValidatePacketLossStatistics(tracker, 1.0f / 5.0f, 1.0f / 4.0f);
elad.alond35e1022017-02-01 16:36:09420
elad.alond24531a2017-03-03 19:11:06421 // Expected window contents: [10111] -> [10111-GAP-10101].
422 AddTransportFeedbackAndValidate(&tracker, base_ + 7,
423 {true, false, true, false, true});
424 ValidatePacketLossStatistics(tracker, 3.0f / 10.0f, 3.0f / 8.0f);
elad.alond35e1022017-02-01 16:36:09425
elad.alond24531a2017-03-03 19:11:06426 // Insert in between, closing the gap completely.
elad.alonde1cc662017-03-15 14:38:13427 // Expected window contents: [10111-GAP-10101] -> [101110110101].
elad.alond24531a2017-03-03 19:11:06428 AddTransportFeedbackAndValidate(&tracker, base_ + 5, {false, true});
429 ValidatePacketLossStatistics(tracker, 4.0f / 12.0f, 4.0f / 11.0f);
elad.alond35e1022017-02-01 16:36:09430}
431
elad.alon5f254892017-03-03 18:51:35432// Sequence number gaps are not gaps in reception. However, gaps in reception
433// are still possible, if a packet which WAS sent on the stream is not acked.
elad.alond24531a2017-03-03 19:11:06434TEST_P(TransportFeedbackPacketLossTrackerTest, SanityGapsInSequenceNumbers) {
elad.alon8132e172017-03-21 12:58:04435 TransportFeedbackPacketLossTracker tracker(50 * kDefaultSendIntervalMs, 5, 1);
minyue022a2832017-01-23 16:07:05436
elad.alonde1cc662017-03-15 14:38:13437 SendPackets(&tracker,
438 {static_cast<uint16_t>(base_),
439 static_cast<uint16_t>(base_ + 2),
440 static_cast<uint16_t>(base_ + 4),
441 static_cast<uint16_t>(base_ + 6),
442 static_cast<uint16_t>(base_ + 8)},
elad.alon8132e172017-03-21 12:58:04443 kDefaultSendIntervalMs);
minyue022a2832017-01-23 16:07:05444
elad.alond24531a2017-03-03 19:11:06445 // Gaps in sequence numbers not considered as gaps in window, because only
446 // those sequence numbers which were associated with the stream count.
447 // Expected window contents: [] -> [11011].
448 AddTransportFeedbackAndValidate(
elad.alonde1cc662017-03-15 14:38:13449 // Note: Left packets belong to this stream, right ones ignored.
elad.alond24531a2017-03-03 19:11:06450 &tracker, base_, {true, false,
451 true, false,
452 false, false,
453 true, false,
454 true, true});
455 ValidatePacketLossStatistics(tracker, 1.0f / 5.0f, 1.0f / 4.0f);
minyue022a2832017-01-23 16:07:05456
elad.alond24531a2017-03-03 19:11:06457 // Create gap by sending [base + 10] but not acking it.
458 // Note: Acks for [base + 11] and [base + 13] ignored (other stream).
459 // Expected window contents: [11011] -> [11011-GAP-01].
elad.alonde1cc662017-03-15 14:38:13460 SendPackets(&tracker,
461 {static_cast<uint16_t>(base_ + 10),
462 static_cast<uint16_t>(base_ + 12),
463 static_cast<uint16_t>(base_ + 14)},
elad.alon8132e172017-03-21 12:58:04464 kDefaultSendIntervalMs);
elad.alond24531a2017-03-03 19:11:06465 AddTransportFeedbackAndValidate(&tracker, base_ + 11,
466 {false, false, false, true, true});
467 ValidatePacketLossStatistics(tracker, 2.0f / 7.0f, 2.0f / 5.0f);
minyue022a2832017-01-23 16:07:05468}
469
elad.alonde1cc662017-03-15 14:38:13470// The window cannot span more than 0x8000 in sequence numbers, regardless
471// of time stamps and ack/unacked status.
472TEST_P(TransportFeedbackPacketLossTrackerTest, MaxUnackedPackets) {
473 TransportFeedbackPacketLossTracker tracker(0x10000, 4, 1);
minyue022a2832017-01-23 16:07:05474
elad.alonde1cc662017-03-15 14:38:13475 SendPackets(&tracker, base_, 0x2000, 1, false);
476
477 // Expected window contents: [] -> [10011].
elad.alond24531a2017-03-03 19:11:06478 AddTransportFeedbackAndValidate(&tracker, base_,
elad.alonde1cc662017-03-15 14:38:13479 {true, false, false, true, true});
480 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue022a2832017-01-23 16:07:05481
elad.alonde1cc662017-03-15 14:38:13482 // Sending more unacked packets, up to 0x7fff from the base, does not
483 // move the window or discard any information.
484 SendPackets(&tracker, static_cast<uint16_t>(base_ + 0x8000 - 0x2000), 0x2000,
485 1, false);
486 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
487
488 // Sending more unacked packets, up to 0x7fff from the base, does not
489 // move the window or discard any information.
490 // Expected window contents: [10011] -> [0011].
491 SendPackets(&tracker, static_cast<uint16_t>(base_ + 0x8000), 1, 1);
492 ValidatePacketLossStatistics(tracker, 2.0f / 4.0f, 1.0f / 3.0f);
minyue022a2832017-01-23 16:07:05493}
494
elad.alonde1cc662017-03-15 14:38:13495// The window holds acked packets up until the difference in timestamps between
496// the oldest and newest reaches the configured maximum. Once this maximum
497// is exceeded, old packets are shifted out of window until the maximum is
498// once again observed.
499TEST_P(TransportFeedbackPacketLossTrackerTest, TimeDifferenceMaximumObserved) {
500 constexpr int64_t max_window_size_ms = 500;
501 TransportFeedbackPacketLossTracker tracker(max_window_size_ms, 3, 1);
502
503 // Note: All messages in this test are sent 1ms apart from each other.
504 // Therefore, the delta in sequence numbers equals the timestamps delta.
minyue022a2832017-01-23 16:07:05505
elad.alond24531a2017-03-03 19:11:06506 // Baseline - window has acked messages.
elad.alonde1cc662017-03-15 14:38:13507 // Expected window contents: [] -> [01101].
508 const std::vector<bool> feedback = {false, true, true, false, true};
509 SendPackets(&tracker, base_, feedback.size(), 1);
510 AddTransportFeedbackAndValidate(&tracker, base_, feedback);
elad.alond24531a2017-03-03 19:11:06511 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 2.0f / 4.0f);
minyue022a2832017-01-23 16:07:05512
elad.alonde1cc662017-03-15 14:38:13513 // Test - window base not moved.
514 // Expected window contents: [01101] -> [011011].
515 AdvanceClock(max_window_size_ms - feedback.size());
516 SendPackets(&tracker, static_cast<uint16_t>(base_ + feedback.size()), 1, 1);
517 AddTransportFeedbackAndValidate(
518 &tracker, static_cast<uint16_t>(base_ + feedback.size()), {true});
elad.alond24531a2017-03-03 19:11:06519 ValidatePacketLossStatistics(tracker, 2.0f / 6.0f, 2.0f / 5.0f);
minyue022a2832017-01-23 16:07:05520
elad.alonde1cc662017-03-15 14:38:13521 // Another packet, sent 1ms later, would already be too late. The window will
522 // be moved, but only after the ACK is received.
523 const uint16_t new_packet_seq_num =
524 static_cast<uint16_t>(base_ + feedback.size() + 1);
525 SendPackets(&tracker, {new_packet_seq_num}, 1);
526 ValidatePacketLossStatistics(tracker, 2.0f / 6.0f, 2.0f / 5.0f);
527 // Expected window contents: [011011] -> [110111].
528 AddTransportFeedbackAndValidate(&tracker, new_packet_seq_num, {true});
529 ValidatePacketLossStatistics(tracker, 1.0f / 6.0f, 1.0f / 5.0f);
530}
elad.alon5f254892017-03-03 18:51:35531
elad.alonde1cc662017-03-15 14:38:13532TEST_P(TransportFeedbackPacketLossTrackerTest, RepeatedSeqNumResetsWindow) {
elad.alon8132e172017-03-21 12:58:04533 TransportFeedbackPacketLossTracker tracker(50 * kDefaultSendIntervalMs, 2, 1);
elad.alonde1cc662017-03-15 14:38:13534
535 // Baseline - window has acked messages.
536 // Expected window contents: [] -> [01101].
elad.alon8132e172017-03-21 12:58:04537 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alonde1cc662017-03-15 14:38:13538 AddTransportFeedbackAndValidate(&tracker, base_,
539 {false, true, true, false, true});
540 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 2.0f / 4.0f);
541
542 // A reset occurs.
elad.alon8132e172017-03-21 12:58:04543 SendPackets(&tracker, {static_cast<uint16_t>(base_ + 2)},
544 kDefaultSendIntervalMs);
elad.alond24531a2017-03-03 19:11:06545 ValidatePacketLossStatistics(tracker,
546 rtc::Optional<float>(),
547 rtc::Optional<float>());
minyue022a2832017-01-23 16:07:05548}
549
elad.alonde1cc662017-03-15 14:38:13550// The window is reset by the sending of a packet which is 0x8000 or more
551// away from the newest packet acked/unacked packet.
552TEST_P(TransportFeedbackPacketLossTrackerTest,
553 SendAfterLongSuspensionResetsWindow) {
elad.alon8132e172017-03-21 12:58:04554 TransportFeedbackPacketLossTracker tracker(50 * kDefaultSendIntervalMs, 2, 1);
elad.alonde1cc662017-03-15 14:38:13555
556 // Baseline - window has acked messages.
557 // Expected window contents: [] -> [01101].
elad.alon8132e172017-03-21 12:58:04558 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alonde1cc662017-03-15 14:38:13559 AddTransportFeedbackAndValidate(&tracker, base_,
560 {false, true, true, false, true});
561 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 2.0f / 4.0f);
562
563 // A reset occurs.
elad.alon8132e172017-03-21 12:58:04564 SendPackets(&tracker, {static_cast<uint16_t>(base_ + 5 + 0x8000)},
565 kDefaultSendIntervalMs);
elad.alonde1cc662017-03-15 14:38:13566 ValidatePacketLossStatistics(tracker,
567 rtc::Optional<float>(),
568 rtc::Optional<float>());
569}
570
571#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
572TEST(TransportFeedbackPacketLossTrackerTest, InvalidConfigMaxWindowSize) {
573 EXPECT_DEATH(TransportFeedbackPacketLossTracker tracker(0, 20, 10), "");
574}
575
576TEST(TransportFeedbackPacketLossTrackerTest, InvalidConfigPlrMinAcked) {
577 EXPECT_DEATH(TransportFeedbackPacketLossTracker tracker(5000, 0, 10), "");
578}
579
580TEST(TransportFeedbackPacketLossTrackerTest, InvalidConfigRplrMinPairs) {
581 EXPECT_DEATH(TransportFeedbackPacketLossTracker tracker(5000, 20, 0), "");
582}
583
584TEST(TransportFeedbackPacketLossTrackerTest, TimeCantFlowBackwards) {
585 TransportFeedbackPacketLossTracker tracker(5000, 2, 1);
586 tracker.OnPacketAdded(100, 0);
587 tracker.OnPacketAdded(101, 2);
588 EXPECT_DEATH(tracker.OnPacketAdded(102, 1), "");
589}
590#endif
591
elad.alond24531a2017-03-03 19:11:06592// All tests are run multiple times with various baseline sequence number,
593// to weed out potential bugs with wrap-around handling.
594constexpr uint16_t kBases[] = {0x0000, 0x3456, 0xc032, 0xfffe};
595
596INSTANTIATE_TEST_CASE_P(_,
597 TransportFeedbackPacketLossTrackerTest,
598 testing::ValuesIn(kBases));
599
minyue022a2832017-01-23 16:07:05600} // namespace webrtc