blob: 8f8fe05d7a9ad72b065c1b9cf3677efcc8d09263 [file] [log] [blame]
minyue435ddf92017-01-23 08:07:05 -08001/*
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.alon7af93572017-03-03 10:51:35 -080013#include <numeric>
minyue435ddf92017-01-23 08:07:05 -080014#include <vector>
15
Fredrik Solenberga8b7c7f2018-01-17 11:18:31 +010016#include "audio/transport_feedback_packet_loss_tracker.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
18#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
19#include "rtc_base/checks.h"
20#include "test/gmock.h"
21#include "test/gtest.h"
minyue435ddf92017-01-23 08:07:05 -080022
minyue435ddf92017-01-23 08:07:05 -080023namespace webrtc {
24
25namespace {
26
elad.alon6a64bd92017-03-21 05:58:04 -070027constexpr int64_t kDefaultSendIntervalMs = 10;
28constexpr int64_t kDefaultMaxWindowSizeMs = 500 * kDefaultSendIntervalMs;
29
elad.alon02455b22017-03-03 11:11:06 -080030class TransportFeedbackPacketLossTrackerTest
31 : public ::testing::TestWithParam<uint16_t> {
32 public:
33 TransportFeedbackPacketLossTrackerTest() = default;
34 virtual ~TransportFeedbackPacketLossTrackerTest() = default;
35
36 protected:
elad.alon3f9b12d2017-03-15 07:38:13 -070037 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.alon02455b22017-03-03 11:11:06 -080049
elad.alon3f9b12d2017-03-15 07:38:13 -070050 // 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.alon7af93572017-03-03 10:51:35 -080053 tracker->Validate();
54 }
55 }
56
elad.alon3f9b12d2017-03-15 07:38:13 -070057 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.alon92e448d2017-03-21 07:31:35 -070077 // 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.alon3f9b12d2017-03-15 07:38:13 -070087 }
88
elad.alond12a8e12017-03-23 11:04:48 -070089 tracker->OnPacketFeedbackVector(packet_feedback_vector);
elad.alon7af93572017-03-03 10:51:35 -080090 tracker->Validate();
91 }
elad.alon7af93572017-03-03 10:51:35 -080092
elad.alon3f9b12d2017-03-15 07:38:13 -070093 // 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) {
eladalonedd6eea2017-05-25 00:15:35 -070099 // TODO(eladalon): Comparing the rtc::Optional<float> directly would have
elad.alon3f9b12d2017-03-15 07:38:13 -0700100 // 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.alon7af93572017-03-03 10:51:35 -0800107
elad.alon3f9b12d2017-03-15 07:38:13 -0700108 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 }
minyue435ddf92017-01-23 08:07:05 -0800113 }
elad.alond83b9672017-02-01 08:36:09 -0800114
elad.alon3f9b12d2017-03-15 07:38:13 -0700115 uint16_t base_{GetParam()};
minyue435ddf92017-01-23 08:07:05 -0800116
elad.alon3f9b12d2017-03-15 07:38:13 -0700117 private:
118 int64_t time_ms_{0};
elad.alond83b9672017-02-01 08:36:09 -0800119
elad.alon3f9b12d2017-03-15 07:38:13 -0700120 RTC_DISALLOW_COPY_AND_ASSIGN(TransportFeedbackPacketLossTrackerTest);
121};
elad.alond83b9672017-02-01 08:36:09 -0800122
minyue435ddf92017-01-23 08:07:05 -0800123} // namespace
124
125// Sanity check on an empty window.
elad.alon3f9b12d2017-03-15 07:38:13 -0700126TEST_P(TransportFeedbackPacketLossTrackerTest, EmptyWindow) {
elad.alon6a64bd92017-03-21 05:58:04 -0700127 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 5);
minyue435ddf92017-01-23 08:07:05 -0800128
elad.alond83b9672017-02-01 08:36:09 -0800129 // PLR and RPLR reported as unknown before reception of first feedback.
Oskar Sundbom606c8822017-11-16 10:57:11 +0100130 ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
minyue435ddf92017-01-23 08:07:05 -0800131}
132
elad.alon7af93572017-03-03 10:51:35 -0800133// A feedback received for an empty window has no effect.
elad.alon02455b22017-03-03 11:11:06 -0800134TEST_P(TransportFeedbackPacketLossTrackerTest, EmptyWindowFeedback) {
elad.alon6a64bd92017-03-21 05:58:04 -0700135 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 3, 2);
elad.alon7af93572017-03-03 10:51:35 -0800136
elad.alon02455b22017-03-03 11:11:06 -0800137 // Feedback doesn't correspond to any packets - ignored.
138 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
Oskar Sundbom606c8822017-11-16 10:57:11 +0100139 ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
elad.alon7af93572017-03-03 10:51:35 -0800140
elad.alon02455b22017-03-03 11:11:06 -0800141 // After the packets are transmitted, acking them would have an effect.
elad.alon6a64bd92017-03-21 05:58:04 -0700142 SendPackets(&tracker, base_, 3, kDefaultSendIntervalMs);
elad.alon02455b22017-03-03 11:11:06 -0800143 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
144 ValidatePacketLossStatistics(tracker, 1.0f / 3.0f, 0.5f);
elad.alon7af93572017-03-03 10:51:35 -0800145}
146
minyue435ddf92017-01-23 08:07:05 -0800147// Sanity check on partially filled window.
elad.alon02455b22017-03-03 11:11:06 -0800148TEST_P(TransportFeedbackPacketLossTrackerTest, PartiallyFilledWindow) {
elad.alon6a64bd92017-03-21 05:58:04 -0700149 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
minyue435ddf92017-01-23 08:07:05 -0800150
elad.alon02455b22017-03-03 11:11:06 -0800151 // PLR unknown before minimum window size reached.
152 // RPLR unknown before minimum pairs reached.
153 // Expected window contents: [] -> [1001].
elad.alon6a64bd92017-03-21 05:58:04 -0700154 SendPackets(&tracker, base_, 3, kDefaultSendIntervalMs);
elad.alon02455b22017-03-03 11:11:06 -0800155 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, false, true});
Oskar Sundbom606c8822017-11-16 10:57:11 +0100156 ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
minyue435ddf92017-01-23 08:07:05 -0800157}
158
elad.alond83b9672017-02-01 08:36:09 -0800159// Sanity check on minimum filled window - PLR known, RPLR unknown.
elad.alon02455b22017-03-03 11:11:06 -0800160TEST_P(TransportFeedbackPacketLossTrackerTest, PlrMinimumFilledWindow) {
elad.alon6a64bd92017-03-21 05:58:04 -0700161 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 5);
minyue435ddf92017-01-23 08:07:05 -0800162
elad.alon02455b22017-03-03 11:11:06 -0800163 // PLR correctly calculated after minimum window size reached.
164 // RPLR not necessarily known at that time (not if min-pairs not reached).
165 // Expected window contents: [] -> [10011].
elad.alon6a64bd92017-03-21 05:58:04 -0700166 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alon02455b22017-03-03 11:11:06 -0800167 AddTransportFeedbackAndValidate(&tracker, base_,
168 {true, false, false, true, true});
Oskar Sundbom606c8822017-11-16 10:57:11 +0100169 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, rtc::nullopt);
minyue435ddf92017-01-23 08:07:05 -0800170}
171
elad.alond83b9672017-02-01 08:36:09 -0800172// Sanity check on minimum filled window - PLR unknown, RPLR known.
elad.alon02455b22017-03-03 11:11:06 -0800173TEST_P(TransportFeedbackPacketLossTrackerTest, RplrMinimumFilledWindow) {
elad.alon6a64bd92017-03-21 05:58:04 -0700174 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 6, 4);
elad.alond83b9672017-02-01 08:36:09 -0800175
elad.alon02455b22017-03-03 11:11:06 -0800176 // RPLR correctly calculated after minimum pairs reached.
177 // PLR not necessarily known at that time (not if min window not reached).
178 // Expected window contents: [] -> [10011].
elad.alon6a64bd92017-03-21 05:58:04 -0700179 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alon02455b22017-03-03 11:11:06 -0800180 AddTransportFeedbackAndValidate(&tracker, base_,
181 {true, false, false, true, true});
Oskar Sundbom606c8822017-11-16 10:57:11 +0100182 ValidatePacketLossStatistics(tracker, rtc::nullopt, 1.0f / 4.0f);
elad.alond83b9672017-02-01 08:36:09 -0800183}
184
elad.alon3f9b12d2017-03-15 07:38:13 -0700185// If packets are sent close enough together that the clock reading for both
186// is the same, that's handled properly.
187TEST_P(TransportFeedbackPacketLossTrackerTest, SameSentTime) {
elad.alon6a64bd92017-03-21 05:58:04 -0700188 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 3, 2);
elad.alon3f9b12d2017-03-15 07:38:13 -0700189
190 // Expected window contents: [] -> [101].
191 SendPackets(&tracker, base_, 3, 0); // Note: time interval = 0ms.
192 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
193
194 ValidatePacketLossStatistics(tracker, 1.0f / 3.0f, 0.5f);
195}
196
elad.alond83b9672017-02-01 08:36:09 -0800197// Additional reports update PLR and RPLR.
elad.alon02455b22017-03-03 11:11:06 -0800198TEST_P(TransportFeedbackPacketLossTrackerTest, ExtendWindow) {
elad.alon6a64bd92017-03-21 05:58:04 -0700199 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 5);
minyue435ddf92017-01-23 08:07:05 -0800200
elad.alon6a64bd92017-03-21 05:58:04 -0700201 SendPackets(&tracker, base_, 25, kDefaultSendIntervalMs);
elad.alon7af93572017-03-03 10:51:35 -0800202
elad.alon02455b22017-03-03 11:11:06 -0800203 // Expected window contents: [] -> [10011].
204 AddTransportFeedbackAndValidate(&tracker, base_,
205 {true, false, false, true, true});
Oskar Sundbom606c8822017-11-16 10:57:11 +0100206 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, rtc::nullopt);
minyue435ddf92017-01-23 08:07:05 -0800207
elad.alon02455b22017-03-03 11:11:06 -0800208 // Expected window contents: [10011] -> [1001110101].
209 AddTransportFeedbackAndValidate(&tracker, base_ + 5,
210 {true, false, true, false, true});
211 ValidatePacketLossStatistics(tracker, 4.0f / 10.0f, 3.0f / 9.0f);
minyue435ddf92017-01-23 08:07:05 -0800212
elad.alon02455b22017-03-03 11:11:06 -0800213 // Expected window contents: [1001110101] -> [1001110101-GAP-10001].
214 AddTransportFeedbackAndValidate(&tracker, base_ + 20,
215 {true, false, false, false, true});
216 ValidatePacketLossStatistics(tracker, 7.0f / 15.0f, 4.0f / 13.0f);
minyue435ddf92017-01-23 08:07:05 -0800217}
218
elad.alon3f9b12d2017-03-15 07:38:13 -0700219// Correct calculation with different packet lengths.
220TEST_P(TransportFeedbackPacketLossTrackerTest, DifferentSentIntervals) {
elad.alon6a64bd92017-03-21 05:58:04 -0700221 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
elad.alon3f9b12d2017-03-15 07:38:13 -0700222
elad.alon3f9b12d2017-03-15 07:38:13 -0700223 int64_t frames[] = {20, 60, 120, 20, 60};
224 for (size_t i = 0; i < sizeof(frames) / sizeof(frames[0]); i++) {
elad.alon6a64bd92017-03-21 05:58:04 -0700225 SendPackets(&tracker, {static_cast<uint16_t>(base_ + i)}, frames[i]);
elad.alon3f9b12d2017-03-15 07:38:13 -0700226 }
227
228 // Expected window contents: [] -> [10011].
229 AddTransportFeedbackAndValidate(&tracker, base_,
230 {true, false, false, true, true});
231 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
232}
233
234// The window retains information up to sent times that exceed the the max
235// window size. The oldest packets get shifted out of window to make room
236// for the newer ones.
237TEST_P(TransportFeedbackPacketLossTrackerTest, MaxWindowSize) {
elad.alon6a64bd92017-03-21 05:58:04 -0700238 TransportFeedbackPacketLossTracker tracker(4 * kDefaultSendIntervalMs, 5, 1);
elad.alon3f9b12d2017-03-15 07:38:13 -0700239
elad.alon6a64bd92017-03-21 05:58:04 -0700240 SendPackets(&tracker, base_, 6, kDefaultSendIntervalMs, true);
elad.alon3f9b12d2017-03-15 07:38:13 -0700241
elad.alon6a64bd92017-03-21 05:58:04 -0700242 // Up to the maximum time-span retained (first + 4 * kDefaultSendIntervalMs).
elad.alon3f9b12d2017-03-15 07:38:13 -0700243 // Expected window contents: [] -> [01001].
244 AddTransportFeedbackAndValidate(&tracker, base_,
245 {false, true, false, false, true});
246 ValidatePacketLossStatistics(tracker, 3.0f / 5.0f, 2.0f / 4.0f);
247
248 // After the maximum time-span, older entries are discarded to accommodate
249 // newer ones.
250 // Expected window contents: [01001] -> [10011].
251 AddTransportFeedbackAndValidate(&tracker, base_ + 5, {true});
252 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
253}
254
255// All packets received.
elad.alon02455b22017-03-03 11:11:06 -0800256TEST_P(TransportFeedbackPacketLossTrackerTest, AllReceived) {
elad.alon6a64bd92017-03-21 05:58:04 -0700257 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
minyue435ddf92017-01-23 08:07:05 -0800258
elad.alon02455b22017-03-03 11:11:06 -0800259 // Expected window contents: [] -> [11111].
elad.alon6a64bd92017-03-21 05:58:04 -0700260 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alon02455b22017-03-03 11:11:06 -0800261 AddTransportFeedbackAndValidate(&tracker, base_,
262 {true, true, true, true, true});
263 ValidatePacketLossStatistics(tracker, 0.0f, 0.0f);
minyue435ddf92017-01-23 08:07:05 -0800264}
265
elad.alon3f9b12d2017-03-15 07:38:13 -0700266// All packets lost.
elad.alon02455b22017-03-03 11:11:06 -0800267TEST_P(TransportFeedbackPacketLossTrackerTest, AllLost) {
elad.alon6a64bd92017-03-21 05:58:04 -0700268 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
elad.alon7af93572017-03-03 10:51:35 -0800269
elad.alon3f9b12d2017-03-15 07:38:13 -0700270 // Note: The last packet in the feedback does not belong to the stream.
271 // It's only there because we're not allowed to end a feedback with a loss.
elad.alon02455b22017-03-03 11:11:06 -0800272 // Expected window contents: [] -> [00000].
elad.alon6a64bd92017-03-21 05:58:04 -0700273 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alon02455b22017-03-03 11:11:06 -0800274 AddTransportFeedbackAndValidate(&tracker, base_,
275 {false, false, false, false, false, true});
276 ValidatePacketLossStatistics(tracker, 1.0f, 0.0f);
elad.alon7af93572017-03-03 10:51:35 -0800277}
278
minyue435ddf92017-01-23 08:07:05 -0800279// Repeated reports are ignored.
elad.alon02455b22017-03-03 11:11:06 -0800280TEST_P(TransportFeedbackPacketLossTrackerTest, ReportRepetition) {
elad.alon6a64bd92017-03-21 05:58:04 -0700281 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
minyue435ddf92017-01-23 08:07:05 -0800282
elad.alon6a64bd92017-03-21 05:58:04 -0700283 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alon7af93572017-03-03 10:51:35 -0800284
elad.alon02455b22017-03-03 11:11:06 -0800285 // Expected window contents: [] -> [10011].
286 AddTransportFeedbackAndValidate(&tracker, base_,
287 {true, false, false, true, true});
288 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800289
elad.alon02455b22017-03-03 11:11:06 -0800290 // Repeat entire previous feedback
291 // Expected window contents: [10011] -> [10011].
292 AddTransportFeedbackAndValidate(&tracker, base_,
293 {true, false, false, true, true});
294 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800295}
296
297// Report overlap.
elad.alon02455b22017-03-03 11:11:06 -0800298TEST_P(TransportFeedbackPacketLossTrackerTest, ReportOverlap) {
elad.alon6a64bd92017-03-21 05:58:04 -0700299 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 1);
minyue435ddf92017-01-23 08:07:05 -0800300
elad.alon6a64bd92017-03-21 05:58:04 -0700301 SendPackets(&tracker, base_, 15, kDefaultSendIntervalMs);
elad.alon7af93572017-03-03 10:51:35 -0800302
elad.alon02455b22017-03-03 11:11:06 -0800303 // Expected window contents: [] -> [10011].
304 AddTransportFeedbackAndValidate(&tracker, base_,
305 {true, false, false, true, true});
306 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800307
elad.alon02455b22017-03-03 11:11:06 -0800308 // Expected window contents: [10011] -> [1001101].
309 AddTransportFeedbackAndValidate(&tracker, base_ + 3,
310 {true, true, false, true});
311 ValidatePacketLossStatistics(tracker, 3.0f / 7.0f, 2.0f / 6.0f);
minyue435ddf92017-01-23 08:07:05 -0800312}
313
314// Report conflict.
elad.alon02455b22017-03-03 11:11:06 -0800315TEST_P(TransportFeedbackPacketLossTrackerTest, ReportConflict) {
elad.alon6a64bd92017-03-21 05:58:04 -0700316 TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 4);
minyue435ddf92017-01-23 08:07:05 -0800317
elad.alon3f9b12d2017-03-15 07:38:13 -0700318 SendPackets(&tracker, base_, 15, 10);
elad.alon7af93572017-03-03 10:51:35 -0800319
elad.alon02455b22017-03-03 11:11:06 -0800320 // Expected window contents: [] -> [01001].
321 AddTransportFeedbackAndValidate(&tracker, base_,
322 {false, true, false, false, true});
323 ValidatePacketLossStatistics(tracker, 3.0f / 5.0f, 2.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800324
elad.alon02455b22017-03-03 11:11:06 -0800325 // Expected window contents: [01001] -> [11101].
326 // While false->true will be applied, true -> false will be ignored.
327 AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true});
328 ValidatePacketLossStatistics(tracker, 1.0f / 5.0f, 1.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800329}
330
331// Skipped packets treated as unknown (not lost).
elad.alon02455b22017-03-03 11:11:06 -0800332TEST_P(TransportFeedbackPacketLossTrackerTest, SkippedPackets) {
elad.alon6a64bd92017-03-21 05:58:04 -0700333 TransportFeedbackPacketLossTracker tracker(200 * kDefaultSendIntervalMs, 5,
334 1);
minyue435ddf92017-01-23 08:07:05 -0800335
elad.alon6a64bd92017-03-21 05:58:04 -0700336 SendPackets(&tracker, base_, 200, kDefaultSendIntervalMs);
elad.alon7af93572017-03-03 10:51:35 -0800337
elad.alon02455b22017-03-03 11:11:06 -0800338 // Expected window contents: [] -> [10011].
339 AddTransportFeedbackAndValidate(&tracker, base_,
340 {true, false, false, true, true});
341 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800342
elad.alon02455b22017-03-03 11:11:06 -0800343 // Expected window contents: [10011] -> [10011-GAP-101].
344 AddTransportFeedbackAndValidate(&tracker, base_ + 100, {true, false, true});
345 ValidatePacketLossStatistics(tracker, 3.0f / 8.0f, 2.0f / 6.0f);
minyue435ddf92017-01-23 08:07:05 -0800346}
347
elad.alon3f9b12d2017-03-15 07:38:13 -0700348// Moving a window, if it excludes some old acked messages, can leave
349// in-window unacked messages intact, and ready to be used later.
350TEST_P(TransportFeedbackPacketLossTrackerTest, MovedWindowRetainsRelevantInfo) {
351 constexpr int64_t max_window_size_ms = 100;
352 TransportFeedbackPacketLossTracker tracker(max_window_size_ms, 5, 1);
minyue435ddf92017-01-23 08:07:05 -0800353
elad.alon3f9b12d2017-03-15 07:38:13 -0700354 // Note: All messages in this test are sent 1ms apart from each other.
355 // Therefore, the delta in sequence numbers equals the timestamps delta.
356 SendPackets(&tracker, base_, 4 * max_window_size_ms, 1);
elad.alon7af93572017-03-03 10:51:35 -0800357
elad.alon02455b22017-03-03 11:11:06 -0800358 // Expected window contents: [] -> [10101].
359 AddTransportFeedbackAndValidate(&tracker, base_,
360 {true, false, true, false, true});
361 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 2.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800362
elad.alon3f9b12d2017-03-15 07:38:13 -0700363 // Expected window contents: [10101] -> [100011].
364 const int64_t moved_oldest_acked = base_ + 2 * max_window_size_ms;
365 const std::vector<bool> feedback = {true, false, false, false, true, true};
366 AddTransportFeedbackAndValidate(&tracker, moved_oldest_acked, feedback);
367 ValidatePacketLossStatistics(tracker, 3.0f / 6.0f, 1.0f / 5.0f);
minyue435ddf92017-01-23 08:07:05 -0800368
elad.alon3f9b12d2017-03-15 07:38:13 -0700369 // Having acked |feedback.size()| starting with |moved_oldest_acked|, the
370 // newest of the acked ones is now:
371 const int64_t moved_newest_acked = moved_oldest_acked + feedback.size() - 1;
372
373 // Messages that *are* more than the span-limit away from the newest
374 // acked message *are* too old. Acking them would have no effect.
375 AddTransportFeedbackAndValidate(
376 &tracker, moved_newest_acked - max_window_size_ms - 1, {true});
377 ValidatePacketLossStatistics(tracker, 3.0f / 6.0f, 1.0f / 5.0f);
378
379 // Messages that are *not* more than the span-limit away from the newest
380 // acked message are *not* too old. Acking them would have an effect.
381 AddTransportFeedbackAndValidate(
382 &tracker, moved_newest_acked - max_window_size_ms, {true});
383 ValidatePacketLossStatistics(tracker, 3.0f / 7.0f, 1.0f / 5.0f);
minyue435ddf92017-01-23 08:07:05 -0800384}
385
elad.alon3f9b12d2017-03-15 07:38:13 -0700386// Inserting feedback into the middle of a window works correctly - can
elad.alon7af93572017-03-03 10:51:35 -0800387// complete two pairs.
elad.alon02455b22017-03-03 11:11:06 -0800388TEST_P(TransportFeedbackPacketLossTrackerTest, InsertionCompletesTwoPairs) {
elad.alon6a64bd92017-03-21 05:58:04 -0700389 TransportFeedbackPacketLossTracker tracker(150 * kDefaultSendIntervalMs, 5,
390 1);
elad.alond83b9672017-02-01 08:36:09 -0800391
elad.alon6a64bd92017-03-21 05:58:04 -0700392 SendPackets(&tracker, base_, 15, kDefaultSendIntervalMs);
elad.alon7af93572017-03-03 10:51:35 -0800393
elad.alon02455b22017-03-03 11:11:06 -0800394 // Expected window contents: [] -> [10111].
395 AddTransportFeedbackAndValidate(&tracker, base_,
396 {true, false, true, true, true});
397 ValidatePacketLossStatistics(tracker, 1.0f / 5.0f, 1.0f / 4.0f);
elad.alond83b9672017-02-01 08:36:09 -0800398
elad.alon02455b22017-03-03 11:11:06 -0800399 // Expected window contents: [10111] -> [10111-GAP-10101].
400 AddTransportFeedbackAndValidate(&tracker, base_ + 7,
401 {true, false, true, false, true});
402 ValidatePacketLossStatistics(tracker, 3.0f / 10.0f, 3.0f / 8.0f);
elad.alond83b9672017-02-01 08:36:09 -0800403
elad.alon02455b22017-03-03 11:11:06 -0800404 // Insert in between, closing the gap completely.
elad.alon3f9b12d2017-03-15 07:38:13 -0700405 // Expected window contents: [10111-GAP-10101] -> [101110110101].
elad.alon02455b22017-03-03 11:11:06 -0800406 AddTransportFeedbackAndValidate(&tracker, base_ + 5, {false, true});
407 ValidatePacketLossStatistics(tracker, 4.0f / 12.0f, 4.0f / 11.0f);
elad.alond83b9672017-02-01 08:36:09 -0800408}
409
elad.alon7af93572017-03-03 10:51:35 -0800410// Sequence number gaps are not gaps in reception. However, gaps in reception
411// are still possible, if a packet which WAS sent on the stream is not acked.
elad.alon02455b22017-03-03 11:11:06 -0800412TEST_P(TransportFeedbackPacketLossTrackerTest, SanityGapsInSequenceNumbers) {
elad.alon6a64bd92017-03-21 05:58:04 -0700413 TransportFeedbackPacketLossTracker tracker(50 * kDefaultSendIntervalMs, 5, 1);
minyue435ddf92017-01-23 08:07:05 -0800414
elad.alon3f9b12d2017-03-15 07:38:13 -0700415 SendPackets(&tracker,
416 {static_cast<uint16_t>(base_),
417 static_cast<uint16_t>(base_ + 2),
418 static_cast<uint16_t>(base_ + 4),
419 static_cast<uint16_t>(base_ + 6),
420 static_cast<uint16_t>(base_ + 8)},
elad.alon6a64bd92017-03-21 05:58:04 -0700421 kDefaultSendIntervalMs);
minyue435ddf92017-01-23 08:07:05 -0800422
elad.alon02455b22017-03-03 11:11:06 -0800423 // Gaps in sequence numbers not considered as gaps in window, because only
424 // those sequence numbers which were associated with the stream count.
425 // Expected window contents: [] -> [11011].
426 AddTransportFeedbackAndValidate(
elad.alon3f9b12d2017-03-15 07:38:13 -0700427 // Note: Left packets belong to this stream, right ones ignored.
elad.alon02455b22017-03-03 11:11:06 -0800428 &tracker, base_, {true, false,
429 true, false,
430 false, false,
431 true, false,
432 true, true});
433 ValidatePacketLossStatistics(tracker, 1.0f / 5.0f, 1.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800434
elad.alon02455b22017-03-03 11:11:06 -0800435 // Create gap by sending [base + 10] but not acking it.
436 // Note: Acks for [base + 11] and [base + 13] ignored (other stream).
437 // Expected window contents: [11011] -> [11011-GAP-01].
elad.alon3f9b12d2017-03-15 07:38:13 -0700438 SendPackets(&tracker,
439 {static_cast<uint16_t>(base_ + 10),
440 static_cast<uint16_t>(base_ + 12),
441 static_cast<uint16_t>(base_ + 14)},
elad.alon6a64bd92017-03-21 05:58:04 -0700442 kDefaultSendIntervalMs);
elad.alon02455b22017-03-03 11:11:06 -0800443 AddTransportFeedbackAndValidate(&tracker, base_ + 11,
444 {false, false, false, true, true});
445 ValidatePacketLossStatistics(tracker, 2.0f / 7.0f, 2.0f / 5.0f);
minyue435ddf92017-01-23 08:07:05 -0800446}
447
elad.alon3f9b12d2017-03-15 07:38:13 -0700448// The window cannot span more than 0x8000 in sequence numbers, regardless
449// of time stamps and ack/unacked status.
450TEST_P(TransportFeedbackPacketLossTrackerTest, MaxUnackedPackets) {
451 TransportFeedbackPacketLossTracker tracker(0x10000, 4, 1);
minyue435ddf92017-01-23 08:07:05 -0800452
elad.alon3f9b12d2017-03-15 07:38:13 -0700453 SendPackets(&tracker, base_, 0x2000, 1, false);
454
455 // Expected window contents: [] -> [10011].
elad.alon02455b22017-03-03 11:11:06 -0800456 AddTransportFeedbackAndValidate(&tracker, base_,
elad.alon3f9b12d2017-03-15 07:38:13 -0700457 {true, false, false, true, true});
458 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800459
elad.alon3f9b12d2017-03-15 07:38:13 -0700460 // Sending more unacked packets, up to 0x7fff from the base, does not
461 // move the window or discard any information.
462 SendPackets(&tracker, static_cast<uint16_t>(base_ + 0x8000 - 0x2000), 0x2000,
463 1, false);
464 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 1.0f / 4.0f);
465
466 // Sending more unacked packets, up to 0x7fff from the base, does not
467 // move the window or discard any information.
468 // Expected window contents: [10011] -> [0011].
469 SendPackets(&tracker, static_cast<uint16_t>(base_ + 0x8000), 1, 1);
470 ValidatePacketLossStatistics(tracker, 2.0f / 4.0f, 1.0f / 3.0f);
minyue435ddf92017-01-23 08:07:05 -0800471}
472
elad.alon3f9b12d2017-03-15 07:38:13 -0700473// The window holds acked packets up until the difference in timestamps between
474// the oldest and newest reaches the configured maximum. Once this maximum
475// is exceeded, old packets are shifted out of window until the maximum is
476// once again observed.
477TEST_P(TransportFeedbackPacketLossTrackerTest, TimeDifferenceMaximumObserved) {
478 constexpr int64_t max_window_size_ms = 500;
479 TransportFeedbackPacketLossTracker tracker(max_window_size_ms, 3, 1);
480
481 // Note: All messages in this test are sent 1ms apart from each other.
482 // Therefore, the delta in sequence numbers equals the timestamps delta.
minyue435ddf92017-01-23 08:07:05 -0800483
elad.alon02455b22017-03-03 11:11:06 -0800484 // Baseline - window has acked messages.
elad.alon3f9b12d2017-03-15 07:38:13 -0700485 // Expected window contents: [] -> [01101].
486 const std::vector<bool> feedback = {false, true, true, false, true};
487 SendPackets(&tracker, base_, feedback.size(), 1);
488 AddTransportFeedbackAndValidate(&tracker, base_, feedback);
elad.alon02455b22017-03-03 11:11:06 -0800489 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 2.0f / 4.0f);
minyue435ddf92017-01-23 08:07:05 -0800490
elad.alon3f9b12d2017-03-15 07:38:13 -0700491 // Test - window base not moved.
492 // Expected window contents: [01101] -> [011011].
493 AdvanceClock(max_window_size_ms - feedback.size());
494 SendPackets(&tracker, static_cast<uint16_t>(base_ + feedback.size()), 1, 1);
495 AddTransportFeedbackAndValidate(
496 &tracker, static_cast<uint16_t>(base_ + feedback.size()), {true});
elad.alon02455b22017-03-03 11:11:06 -0800497 ValidatePacketLossStatistics(tracker, 2.0f / 6.0f, 2.0f / 5.0f);
minyue435ddf92017-01-23 08:07:05 -0800498
elad.alon3f9b12d2017-03-15 07:38:13 -0700499 // Another packet, sent 1ms later, would already be too late. The window will
500 // be moved, but only after the ACK is received.
501 const uint16_t new_packet_seq_num =
502 static_cast<uint16_t>(base_ + feedback.size() + 1);
503 SendPackets(&tracker, {new_packet_seq_num}, 1);
504 ValidatePacketLossStatistics(tracker, 2.0f / 6.0f, 2.0f / 5.0f);
505 // Expected window contents: [011011] -> [110111].
506 AddTransportFeedbackAndValidate(&tracker, new_packet_seq_num, {true});
507 ValidatePacketLossStatistics(tracker, 1.0f / 6.0f, 1.0f / 5.0f);
508}
elad.alon7af93572017-03-03 10:51:35 -0800509
elad.alon3f9b12d2017-03-15 07:38:13 -0700510TEST_P(TransportFeedbackPacketLossTrackerTest, RepeatedSeqNumResetsWindow) {
elad.alon6a64bd92017-03-21 05:58:04 -0700511 TransportFeedbackPacketLossTracker tracker(50 * kDefaultSendIntervalMs, 2, 1);
elad.alon3f9b12d2017-03-15 07:38:13 -0700512
513 // Baseline - window has acked messages.
514 // Expected window contents: [] -> [01101].
elad.alon6a64bd92017-03-21 05:58:04 -0700515 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alon3f9b12d2017-03-15 07:38:13 -0700516 AddTransportFeedbackAndValidate(&tracker, base_,
517 {false, true, true, false, true});
518 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 2.0f / 4.0f);
519
520 // A reset occurs.
elad.alon6a64bd92017-03-21 05:58:04 -0700521 SendPackets(&tracker, {static_cast<uint16_t>(base_ + 2)},
522 kDefaultSendIntervalMs);
Oskar Sundbom606c8822017-11-16 10:57:11 +0100523 ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
minyue435ddf92017-01-23 08:07:05 -0800524}
525
elad.alon3f9b12d2017-03-15 07:38:13 -0700526// The window is reset by the sending of a packet which is 0x8000 or more
527// away from the newest packet acked/unacked packet.
528TEST_P(TransportFeedbackPacketLossTrackerTest,
529 SendAfterLongSuspensionResetsWindow) {
elad.alon6a64bd92017-03-21 05:58:04 -0700530 TransportFeedbackPacketLossTracker tracker(50 * kDefaultSendIntervalMs, 2, 1);
elad.alon3f9b12d2017-03-15 07:38:13 -0700531
532 // Baseline - window has acked messages.
533 // Expected window contents: [] -> [01101].
elad.alon6a64bd92017-03-21 05:58:04 -0700534 SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs);
elad.alon3f9b12d2017-03-15 07:38:13 -0700535 AddTransportFeedbackAndValidate(&tracker, base_,
536 {false, true, true, false, true});
537 ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, 2.0f / 4.0f);
538
539 // A reset occurs.
elad.alon6a64bd92017-03-21 05:58:04 -0700540 SendPackets(&tracker, {static_cast<uint16_t>(base_ + 5 + 0x8000)},
541 kDefaultSendIntervalMs);
Oskar Sundbom606c8822017-11-16 10:57:11 +0100542 ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt);
elad.alon3f9b12d2017-03-15 07:38:13 -0700543}
544
545#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
546TEST(TransportFeedbackPacketLossTrackerTest, InvalidConfigMaxWindowSize) {
547 EXPECT_DEATH(TransportFeedbackPacketLossTracker tracker(0, 20, 10), "");
548}
549
550TEST(TransportFeedbackPacketLossTrackerTest, InvalidConfigPlrMinAcked) {
551 EXPECT_DEATH(TransportFeedbackPacketLossTracker tracker(5000, 0, 10), "");
552}
553
554TEST(TransportFeedbackPacketLossTrackerTest, InvalidConfigRplrMinPairs) {
555 EXPECT_DEATH(TransportFeedbackPacketLossTracker tracker(5000, 20, 0), "");
556}
557
558TEST(TransportFeedbackPacketLossTrackerTest, TimeCantFlowBackwards) {
559 TransportFeedbackPacketLossTracker tracker(5000, 2, 1);
560 tracker.OnPacketAdded(100, 0);
561 tracker.OnPacketAdded(101, 2);
562 EXPECT_DEATH(tracker.OnPacketAdded(102, 1), "");
563}
564#endif
565
elad.alon02455b22017-03-03 11:11:06 -0800566// All tests are run multiple times with various baseline sequence number,
567// to weed out potential bugs with wrap-around handling.
568constexpr uint16_t kBases[] = {0x0000, 0x3456, 0xc032, 0xfffe};
569
570INSTANTIATE_TEST_CASE_P(_,
571 TransportFeedbackPacketLossTrackerTest,
572 testing::ValuesIn(kBases));
573
minyue435ddf92017-01-23 08:07:05 -0800574} // namespace webrtc