blob: 32f9f4b2a3182e7e340ed8ddd3fe274322286c4b [file] [log] [blame]
Chen Xing9c16af72019-06-12 12:13:22 +02001/*
2 * Copyright (c) 2019 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 "modules/rtp_rtcp/source/source_tracker.h"
12
13#include <algorithm>
14#include <list>
15#include <random>
16#include <set>
17#include <tuple>
18#include <utility>
19#include <vector>
20
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +010021#include "absl/types/optional.h"
Chen Xing9c16af72019-06-12 12:13:22 +020022#include "api/rtp_headers.h"
23#include "api/rtp_packet_info.h"
24#include "api/rtp_packet_infos.h"
25#include "test/gmock.h"
26#include "test/gtest.h"
27
28namespace webrtc {
29namespace {
30
31using ::testing::Combine;
32using ::testing::ElementsAre;
33using ::testing::ElementsAreArray;
34using ::testing::IsEmpty;
Chen Xing9c16af72019-06-12 12:13:22 +020035using ::testing::TestWithParam;
36using ::testing::Values;
37
38constexpr size_t kPacketInfosCountMax = 5;
39
40// Simple "guaranteed to be correct" re-implementation of |SourceTracker| for
41// dual-implementation testing purposes.
42class ExpectedSourceTracker {
43 public:
44 explicit ExpectedSourceTracker(Clock* clock) : clock_(clock) {}
45
46 void OnFrameDelivered(const RtpPacketInfos& packet_infos) {
47 const int64_t now_ms = clock_->TimeInMilliseconds();
48
49 for (const auto& packet_info : packet_infos) {
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +010050 RtpSource::Extensions extensions = {packet_info.audio_level(),
51 packet_info.absolute_capture_time()};
52
Chen Xing9c16af72019-06-12 12:13:22 +020053 for (const auto& csrc : packet_info.csrcs()) {
54 entries_.emplace_front(now_ms, csrc, RtpSourceType::CSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +010055 packet_info.rtp_timestamp(), extensions);
Chen Xing9c16af72019-06-12 12:13:22 +020056 }
57
58 entries_.emplace_front(now_ms, packet_info.ssrc(), RtpSourceType::SSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +010059 packet_info.rtp_timestamp(), extensions);
Chen Xing9c16af72019-06-12 12:13:22 +020060 }
61
62 PruneEntries(now_ms);
63 }
64
65 std::vector<RtpSource> GetSources() const {
66 PruneEntries(clock_->TimeInMilliseconds());
67
68 return std::vector<RtpSource>(entries_.begin(), entries_.end());
69 }
70
71 private:
72 void PruneEntries(int64_t now_ms) const {
73 const int64_t prune_ms = now_ms - 10000; // 10 seconds
74
75 std::set<std::pair<RtpSourceType, uint32_t>> seen;
76
77 auto it = entries_.begin();
78 auto end = entries_.end();
79 while (it != end) {
80 auto next = it;
81 ++next;
82
83 auto key = std::make_pair(it->source_type(), it->source_id());
84 if (!seen.insert(key).second || it->timestamp_ms() < prune_ms) {
85 entries_.erase(it);
86 }
87
88 it = next;
89 }
90 }
91
92 Clock* const clock_;
93
94 mutable std::list<RtpSource> entries_;
95};
96
97class SourceTrackerRandomTest
98 : public TestWithParam<std::tuple<uint32_t, uint32_t>> {
99 protected:
100 SourceTrackerRandomTest()
101 : ssrcs_count_(std::get<0>(GetParam())),
102 csrcs_count_(std::get<1>(GetParam())),
103 generator_(42) {}
104
105 RtpPacketInfos GeneratePacketInfos() {
106 size_t count = std::uniform_int_distribution<size_t>(
107 1, kPacketInfosCountMax)(generator_);
108
109 RtpPacketInfos::vector_type packet_infos;
110 for (size_t i = 0; i < count; ++i) {
111 packet_infos.emplace_back(GenerateSsrc(), GenerateCsrcs(),
Chen Xing9c16af72019-06-12 12:13:22 +0200112 GenerateRtpTimestamp(), GenerateAudioLevel(),
Chen Xinge08648d2019-08-05 16:29:13 +0200113 GenerateAbsoluteCaptureTime(),
Chen Xing9c16af72019-06-12 12:13:22 +0200114 GenerateReceiveTimeMs());
115 }
116
117 return RtpPacketInfos(std::move(packet_infos));
118 }
119
120 int64_t GenerateClockAdvanceTimeMilliseconds() {
121 double roll = std::uniform_real_distribution<double>(0.0, 1.0)(generator_);
122
123 if (roll < 0.05) {
124 return 0;
125 }
126
127 if (roll < 0.08) {
128 return SourceTracker::kTimeoutMs - 1;
129 }
130
131 if (roll < 0.11) {
132 return SourceTracker::kTimeoutMs;
133 }
134
135 if (roll < 0.19) {
136 return std::uniform_int_distribution<int64_t>(
137 SourceTracker::kTimeoutMs,
138 SourceTracker::kTimeoutMs * 1000)(generator_);
139 }
140
141 return std::uniform_int_distribution<int64_t>(
142 1, SourceTracker::kTimeoutMs - 1)(generator_);
143 }
144
145 private:
146 uint32_t GenerateSsrc() {
147 return std::uniform_int_distribution<uint32_t>(1, ssrcs_count_)(generator_);
148 }
149
150 std::vector<uint32_t> GenerateCsrcs() {
151 std::vector<uint32_t> csrcs;
152 for (size_t i = 1; i <= csrcs_count_ && csrcs.size() < kRtpCsrcSize; ++i) {
153 if (std::bernoulli_distribution(0.5)(generator_)) {
154 csrcs.push_back(i);
155 }
156 }
157
158 return csrcs;
159 }
160
Chen Xing9c16af72019-06-12 12:13:22 +0200161 uint32_t GenerateRtpTimestamp() {
162 return std::uniform_int_distribution<uint32_t>()(generator_);
163 }
164
165 absl::optional<uint8_t> GenerateAudioLevel() {
166 if (std::bernoulli_distribution(0.25)(generator_)) {
167 return absl::nullopt;
168 }
169
170 // Workaround for std::uniform_int_distribution<uint8_t> not being allowed.
171 return static_cast<uint8_t>(
172 std::uniform_int_distribution<uint16_t>()(generator_));
173 }
174
Chen Xinge08648d2019-08-05 16:29:13 +0200175 absl::optional<AbsoluteCaptureTime> GenerateAbsoluteCaptureTime() {
176 if (std::bernoulli_distribution(0.25)(generator_)) {
177 return absl::nullopt;
178 }
179
180 AbsoluteCaptureTime value;
181
182 value.absolute_capture_timestamp =
183 std::uniform_int_distribution<uint64_t>()(generator_);
184
185 if (std::bernoulli_distribution(0.5)(generator_)) {
186 value.estimated_capture_clock_offset = absl::nullopt;
187 } else {
188 value.estimated_capture_clock_offset =
189 std::uniform_int_distribution<int64_t>()(generator_);
190 }
191
192 return value;
193 }
194
Chen Xing9c16af72019-06-12 12:13:22 +0200195 int64_t GenerateReceiveTimeMs() {
196 return std::uniform_int_distribution<int64_t>()(generator_);
197 }
198
199 const uint32_t ssrcs_count_;
200 const uint32_t csrcs_count_;
201
202 std::mt19937 generator_;
203};
204
205} // namespace
206
207TEST_P(SourceTrackerRandomTest, RandomOperations) {
208 constexpr size_t kIterationsCount = 200;
209
210 SimulatedClock clock(1000000000000ULL);
211 SourceTracker actual_tracker(&clock);
212 ExpectedSourceTracker expected_tracker(&clock);
213
214 ASSERT_THAT(actual_tracker.GetSources(), IsEmpty());
215 ASSERT_THAT(expected_tracker.GetSources(), IsEmpty());
216
217 for (size_t i = 0; i < kIterationsCount; ++i) {
218 RtpPacketInfos packet_infos = GeneratePacketInfos();
219
220 actual_tracker.OnFrameDelivered(packet_infos);
221 expected_tracker.OnFrameDelivered(packet_infos);
222
223 clock.AdvanceTimeMilliseconds(GenerateClockAdvanceTimeMilliseconds());
224
225 ASSERT_THAT(actual_tracker.GetSources(),
226 ElementsAreArray(expected_tracker.GetSources()));
227 }
228}
229
Mirko Bonadei1b575412019-09-23 08:34:50 +0200230INSTANTIATE_TEST_SUITE_P(All,
Chen Xing9c16af72019-06-12 12:13:22 +0200231 SourceTrackerRandomTest,
232 Combine(/*ssrcs_count_=*/Values(1, 2, 4),
233 /*csrcs_count_=*/Values(0, 1, 3, 7)));
234
235TEST(SourceTrackerTest, StartEmpty) {
236 SimulatedClock clock(1000000000000ULL);
237 SourceTracker tracker(&clock);
238
239 EXPECT_THAT(tracker.GetSources(), IsEmpty());
240}
241
242TEST(SourceTrackerTest, OnFrameDeliveredRecordsSources) {
243 constexpr uint32_t kSsrc = 10;
Chen Xing12d64de2019-06-13 20:36:12 +0200244 constexpr uint32_t kCsrcs0 = 20;
245 constexpr uint32_t kCsrcs1 = 21;
Chen Xing9c16af72019-06-12 12:13:22 +0200246 constexpr uint32_t kRtpTimestamp = 40;
247 constexpr absl::optional<uint8_t> kAudioLevel = 50;
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100248 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime =
249 AbsoluteCaptureTime{/*absolute_capture_timestamp=*/12,
250 /*estimated_capture_clock_offset=*/absl::nullopt};
Chen Xing9c16af72019-06-12 12:13:22 +0200251 constexpr int64_t kReceiveTimeMs = 60;
252
253 SimulatedClock clock(1000000000000ULL);
254 SourceTracker tracker(&clock);
255
Chen Xinge08648d2019-08-05 16:29:13 +0200256 tracker.OnFrameDelivered(RtpPacketInfos(
257 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp, kAudioLevel,
258 kAbsoluteCaptureTime, kReceiveTimeMs)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200259
260 int64_t timestamp_ms = clock.TimeInMilliseconds();
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100261 constexpr RtpSource::Extensions extensions = {kAudioLevel,
262 kAbsoluteCaptureTime};
Chen Xing9c16af72019-06-12 12:13:22 +0200263
Chen Xing12d64de2019-06-13 20:36:12 +0200264 EXPECT_THAT(tracker.GetSources(),
265 ElementsAre(RtpSource(timestamp_ms, kSsrc, RtpSourceType::SSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100266 kRtpTimestamp, extensions),
Chen Xing12d64de2019-06-13 20:36:12 +0200267 RtpSource(timestamp_ms, kCsrcs1, RtpSourceType::CSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100268 kRtpTimestamp, extensions),
Chen Xing12d64de2019-06-13 20:36:12 +0200269 RtpSource(timestamp_ms, kCsrcs0, RtpSourceType::CSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100270 kRtpTimestamp, extensions)));
Chen Xing9c16af72019-06-12 12:13:22 +0200271}
272
273TEST(SourceTrackerTest, OnFrameDeliveredUpdatesSources) {
274 constexpr uint32_t kSsrc = 10;
275 constexpr uint32_t kCsrcs0 = 20;
276 constexpr uint32_t kCsrcs1 = 21;
277 constexpr uint32_t kCsrcs2 = 22;
Chen Xing9c16af72019-06-12 12:13:22 +0200278 constexpr uint32_t kRtpTimestamp0 = 40;
279 constexpr uint32_t kRtpTimestamp1 = 41;
280 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
281 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100282 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime0 =
283 AbsoluteCaptureTime{12, 34};
284 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime1 =
285 AbsoluteCaptureTime{56, 78};
Chen Xing9c16af72019-06-12 12:13:22 +0200286 constexpr int64_t kReceiveTimeMs0 = 60;
287 constexpr int64_t kReceiveTimeMs1 = 61;
288
289 SimulatedClock clock(1000000000000ULL);
290 SourceTracker tracker(&clock);
291
Chen Xinge08648d2019-08-05 16:29:13 +0200292 tracker.OnFrameDelivered(RtpPacketInfos(
293 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kAudioLevel0,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100294 kAbsoluteCaptureTime0, kReceiveTimeMs0)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200295
296 int64_t timestamp_ms_0 = clock.TimeInMilliseconds();
297
298 clock.AdvanceTimeMilliseconds(17);
299
Chen Xinge08648d2019-08-05 16:29:13 +0200300 tracker.OnFrameDelivered(RtpPacketInfos(
301 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1, kAudioLevel1,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100302 kAbsoluteCaptureTime1, kReceiveTimeMs1)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200303
304 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
305
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100306 constexpr RtpSource::Extensions extensions0 = {kAudioLevel0,
307 kAbsoluteCaptureTime0};
308 constexpr RtpSource::Extensions extensions1 = {kAudioLevel1,
309 kAbsoluteCaptureTime1};
310
Chen Xing9c16af72019-06-12 12:13:22 +0200311 EXPECT_THAT(
312 tracker.GetSources(),
313 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100314 kRtpTimestamp1, extensions1),
Chen Xing9c16af72019-06-12 12:13:22 +0200315 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100316 kRtpTimestamp1, extensions1),
Chen Xing9c16af72019-06-12 12:13:22 +0200317 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100318 kRtpTimestamp1, extensions1),
Chen Xing9c16af72019-06-12 12:13:22 +0200319 RtpSource(timestamp_ms_0, kCsrcs1, RtpSourceType::CSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100320 kRtpTimestamp0, extensions0)));
Chen Xing9c16af72019-06-12 12:13:22 +0200321}
322
323TEST(SourceTrackerTest, TimedOutSourcesAreRemoved) {
324 constexpr uint32_t kSsrc = 10;
325 constexpr uint32_t kCsrcs0 = 20;
326 constexpr uint32_t kCsrcs1 = 21;
327 constexpr uint32_t kCsrcs2 = 22;
Chen Xing9c16af72019-06-12 12:13:22 +0200328 constexpr uint32_t kRtpTimestamp0 = 40;
329 constexpr uint32_t kRtpTimestamp1 = 41;
330 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
331 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100332 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime0 =
333 AbsoluteCaptureTime{12, 34};
334 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime1 =
335 AbsoluteCaptureTime{56, 78};
Chen Xing9c16af72019-06-12 12:13:22 +0200336 constexpr int64_t kReceiveTimeMs0 = 60;
337 constexpr int64_t kReceiveTimeMs1 = 61;
338
339 SimulatedClock clock(1000000000000ULL);
340 SourceTracker tracker(&clock);
341
Chen Xinge08648d2019-08-05 16:29:13 +0200342 tracker.OnFrameDelivered(RtpPacketInfos(
343 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kAudioLevel0,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100344 kAbsoluteCaptureTime0, kReceiveTimeMs0)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200345
346 clock.AdvanceTimeMilliseconds(17);
347
Chen Xinge08648d2019-08-05 16:29:13 +0200348 tracker.OnFrameDelivered(RtpPacketInfos(
349 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1, kAudioLevel1,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100350 kAbsoluteCaptureTime1, kReceiveTimeMs1)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200351
352 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
353
354 clock.AdvanceTimeMilliseconds(SourceTracker::kTimeoutMs);
355
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100356 constexpr RtpSource::Extensions extensions1 = {kAudioLevel1,
357 kAbsoluteCaptureTime1};
358
Chen Xing9c16af72019-06-12 12:13:22 +0200359 EXPECT_THAT(
360 tracker.GetSources(),
361 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100362 kRtpTimestamp1, extensions1),
Chen Xing9c16af72019-06-12 12:13:22 +0200363 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100364 kRtpTimestamp1, extensions1),
Chen Xing9c16af72019-06-12 12:13:22 +0200365 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
Ruslan Burakovd51cc7b2019-11-20 16:48:34 +0100366 kRtpTimestamp1, extensions1)));
Chen Xing9c16af72019-06-12 12:13:22 +0200367}
368
369} // namespace webrtc