blob: 55ae4d1a35a9961b0210384ddc2a2df904802dc0 [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
21#include "api/rtp_headers.h"
22#include "api/rtp_packet_info.h"
23#include "api/rtp_packet_infos.h"
24#include "test/gmock.h"
25#include "test/gtest.h"
26
27namespace webrtc {
28namespace {
29
30using ::testing::Combine;
31using ::testing::ElementsAre;
32using ::testing::ElementsAreArray;
33using ::testing::IsEmpty;
34using ::testing::SizeIs;
35using ::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) {
50 for (const auto& csrc : packet_info.csrcs()) {
51 entries_.emplace_front(now_ms, csrc, RtpSourceType::CSRC,
52 packet_info.audio_level(),
53 packet_info.rtp_timestamp());
54 }
55
56 entries_.emplace_front(now_ms, packet_info.ssrc(), RtpSourceType::SSRC,
57 packet_info.audio_level(),
58 packet_info.rtp_timestamp());
59 }
60
61 PruneEntries(now_ms);
62 }
63
64 std::vector<RtpSource> GetSources() const {
65 PruneEntries(clock_->TimeInMilliseconds());
66
67 return std::vector<RtpSource>(entries_.begin(), entries_.end());
68 }
69
70 private:
71 void PruneEntries(int64_t now_ms) const {
72 const int64_t prune_ms = now_ms - 10000; // 10 seconds
73
74 std::set<std::pair<RtpSourceType, uint32_t>> seen;
75
76 auto it = entries_.begin();
77 auto end = entries_.end();
78 while (it != end) {
79 auto next = it;
80 ++next;
81
82 auto key = std::make_pair(it->source_type(), it->source_id());
83 if (!seen.insert(key).second || it->timestamp_ms() < prune_ms) {
84 entries_.erase(it);
85 }
86
87 it = next;
88 }
89 }
90
91 Clock* const clock_;
92
93 mutable std::list<RtpSource> entries_;
94};
95
96class SourceTrackerRandomTest
97 : public TestWithParam<std::tuple<uint32_t, uint32_t>> {
98 protected:
99 SourceTrackerRandomTest()
100 : ssrcs_count_(std::get<0>(GetParam())),
101 csrcs_count_(std::get<1>(GetParam())),
102 generator_(42) {}
103
104 RtpPacketInfos GeneratePacketInfos() {
105 size_t count = std::uniform_int_distribution<size_t>(
106 1, kPacketInfosCountMax)(generator_);
107
108 RtpPacketInfos::vector_type packet_infos;
109 for (size_t i = 0; i < count; ++i) {
110 packet_infos.emplace_back(GenerateSsrc(), GenerateCsrcs(),
Chen Xing9c16af72019-06-12 12:13:22 +0200111 GenerateRtpTimestamp(), GenerateAudioLevel(),
Chen Xinge08648d2019-08-05 16:29:13 +0200112 GenerateAbsoluteCaptureTime(),
Chen Xing9c16af72019-06-12 12:13:22 +0200113 GenerateReceiveTimeMs());
114 }
115
116 return RtpPacketInfos(std::move(packet_infos));
117 }
118
119 int64_t GenerateClockAdvanceTimeMilliseconds() {
120 double roll = std::uniform_real_distribution<double>(0.0, 1.0)(generator_);
121
122 if (roll < 0.05) {
123 return 0;
124 }
125
126 if (roll < 0.08) {
127 return SourceTracker::kTimeoutMs - 1;
128 }
129
130 if (roll < 0.11) {
131 return SourceTracker::kTimeoutMs;
132 }
133
134 if (roll < 0.19) {
135 return std::uniform_int_distribution<int64_t>(
136 SourceTracker::kTimeoutMs,
137 SourceTracker::kTimeoutMs * 1000)(generator_);
138 }
139
140 return std::uniform_int_distribution<int64_t>(
141 1, SourceTracker::kTimeoutMs - 1)(generator_);
142 }
143
144 private:
145 uint32_t GenerateSsrc() {
146 return std::uniform_int_distribution<uint32_t>(1, ssrcs_count_)(generator_);
147 }
148
149 std::vector<uint32_t> GenerateCsrcs() {
150 std::vector<uint32_t> csrcs;
151 for (size_t i = 1; i <= csrcs_count_ && csrcs.size() < kRtpCsrcSize; ++i) {
152 if (std::bernoulli_distribution(0.5)(generator_)) {
153 csrcs.push_back(i);
154 }
155 }
156
157 return csrcs;
158 }
159
Chen Xing9c16af72019-06-12 12:13:22 +0200160 uint32_t GenerateRtpTimestamp() {
161 return std::uniform_int_distribution<uint32_t>()(generator_);
162 }
163
164 absl::optional<uint8_t> GenerateAudioLevel() {
165 if (std::bernoulli_distribution(0.25)(generator_)) {
166 return absl::nullopt;
167 }
168
169 // Workaround for std::uniform_int_distribution<uint8_t> not being allowed.
170 return static_cast<uint8_t>(
171 std::uniform_int_distribution<uint16_t>()(generator_));
172 }
173
Chen Xinge08648d2019-08-05 16:29:13 +0200174 absl::optional<AbsoluteCaptureTime> GenerateAbsoluteCaptureTime() {
175 if (std::bernoulli_distribution(0.25)(generator_)) {
176 return absl::nullopt;
177 }
178
179 AbsoluteCaptureTime value;
180
181 value.absolute_capture_timestamp =
182 std::uniform_int_distribution<uint64_t>()(generator_);
183
184 if (std::bernoulli_distribution(0.5)(generator_)) {
185 value.estimated_capture_clock_offset = absl::nullopt;
186 } else {
187 value.estimated_capture_clock_offset =
188 std::uniform_int_distribution<int64_t>()(generator_);
189 }
190
191 return value;
192 }
193
Chen Xing9c16af72019-06-12 12:13:22 +0200194 int64_t GenerateReceiveTimeMs() {
195 return std::uniform_int_distribution<int64_t>()(generator_);
196 }
197
198 const uint32_t ssrcs_count_;
199 const uint32_t csrcs_count_;
200
201 std::mt19937 generator_;
202};
203
204} // namespace
205
206TEST_P(SourceTrackerRandomTest, RandomOperations) {
207 constexpr size_t kIterationsCount = 200;
208
209 SimulatedClock clock(1000000000000ULL);
210 SourceTracker actual_tracker(&clock);
211 ExpectedSourceTracker expected_tracker(&clock);
212
213 ASSERT_THAT(actual_tracker.GetSources(), IsEmpty());
214 ASSERT_THAT(expected_tracker.GetSources(), IsEmpty());
215
216 for (size_t i = 0; i < kIterationsCount; ++i) {
217 RtpPacketInfos packet_infos = GeneratePacketInfos();
218
219 actual_tracker.OnFrameDelivered(packet_infos);
220 expected_tracker.OnFrameDelivered(packet_infos);
221
222 clock.AdvanceTimeMilliseconds(GenerateClockAdvanceTimeMilliseconds());
223
224 ASSERT_THAT(actual_tracker.GetSources(),
225 ElementsAreArray(expected_tracker.GetSources()));
226 }
227}
228
229INSTANTIATE_TEST_SUITE_P(,
230 SourceTrackerRandomTest,
231 Combine(/*ssrcs_count_=*/Values(1, 2, 4),
232 /*csrcs_count_=*/Values(0, 1, 3, 7)));
233
234TEST(SourceTrackerTest, StartEmpty) {
235 SimulatedClock clock(1000000000000ULL);
236 SourceTracker tracker(&clock);
237
238 EXPECT_THAT(tracker.GetSources(), IsEmpty());
239}
240
241TEST(SourceTrackerTest, OnFrameDeliveredRecordsSources) {
242 constexpr uint32_t kSsrc = 10;
Chen Xing12d64de2019-06-13 20:36:12 +0200243 constexpr uint32_t kCsrcs0 = 20;
244 constexpr uint32_t kCsrcs1 = 21;
Chen Xing9c16af72019-06-12 12:13:22 +0200245 constexpr uint32_t kRtpTimestamp = 40;
246 constexpr absl::optional<uint8_t> kAudioLevel = 50;
Chen Xinge08648d2019-08-05 16:29:13 +0200247 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime = {};
Chen Xing9c16af72019-06-12 12:13:22 +0200248 constexpr int64_t kReceiveTimeMs = 60;
249
250 SimulatedClock clock(1000000000000ULL);
251 SourceTracker tracker(&clock);
252
Chen Xinge08648d2019-08-05 16:29:13 +0200253 tracker.OnFrameDelivered(RtpPacketInfos(
254 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp, kAudioLevel,
255 kAbsoluteCaptureTime, kReceiveTimeMs)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200256
257 int64_t timestamp_ms = clock.TimeInMilliseconds();
258
Chen Xing12d64de2019-06-13 20:36:12 +0200259 EXPECT_THAT(tracker.GetSources(),
260 ElementsAre(RtpSource(timestamp_ms, kSsrc, RtpSourceType::SSRC,
261 kAudioLevel, kRtpTimestamp),
262 RtpSource(timestamp_ms, kCsrcs1, RtpSourceType::CSRC,
263 kAudioLevel, kRtpTimestamp),
264 RtpSource(timestamp_ms, kCsrcs0, RtpSourceType::CSRC,
265 kAudioLevel, kRtpTimestamp)));
Chen Xing9c16af72019-06-12 12:13:22 +0200266}
267
268TEST(SourceTrackerTest, OnFrameDeliveredUpdatesSources) {
269 constexpr uint32_t kSsrc = 10;
270 constexpr uint32_t kCsrcs0 = 20;
271 constexpr uint32_t kCsrcs1 = 21;
272 constexpr uint32_t kCsrcs2 = 22;
Chen Xing9c16af72019-06-12 12:13:22 +0200273 constexpr uint32_t kRtpTimestamp0 = 40;
274 constexpr uint32_t kRtpTimestamp1 = 41;
275 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
276 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
Chen Xinge08648d2019-08-05 16:29:13 +0200277 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime = {};
Chen Xing9c16af72019-06-12 12:13:22 +0200278 constexpr int64_t kReceiveTimeMs0 = 60;
279 constexpr int64_t kReceiveTimeMs1 = 61;
280
281 SimulatedClock clock(1000000000000ULL);
282 SourceTracker tracker(&clock);
283
Chen Xinge08648d2019-08-05 16:29:13 +0200284 tracker.OnFrameDelivered(RtpPacketInfos(
285 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kAudioLevel0,
286 kAbsoluteCaptureTime, kReceiveTimeMs0)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200287
288 int64_t timestamp_ms_0 = clock.TimeInMilliseconds();
289
290 clock.AdvanceTimeMilliseconds(17);
291
Chen Xinge08648d2019-08-05 16:29:13 +0200292 tracker.OnFrameDelivered(RtpPacketInfos(
293 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1, kAudioLevel1,
294 kAbsoluteCaptureTime, kReceiveTimeMs1)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200295
296 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
297
298 EXPECT_THAT(
299 tracker.GetSources(),
300 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
301 kAudioLevel1, kRtpTimestamp1),
302 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
303 kAudioLevel1, kRtpTimestamp1),
304 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
305 kAudioLevel1, kRtpTimestamp1),
306 RtpSource(timestamp_ms_0, kCsrcs1, RtpSourceType::CSRC,
307 kAudioLevel0, kRtpTimestamp0)));
308}
309
310TEST(SourceTrackerTest, TimedOutSourcesAreRemoved) {
311 constexpr uint32_t kSsrc = 10;
312 constexpr uint32_t kCsrcs0 = 20;
313 constexpr uint32_t kCsrcs1 = 21;
314 constexpr uint32_t kCsrcs2 = 22;
Chen Xing9c16af72019-06-12 12:13:22 +0200315 constexpr uint32_t kRtpTimestamp0 = 40;
316 constexpr uint32_t kRtpTimestamp1 = 41;
317 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
318 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
Chen Xinge08648d2019-08-05 16:29:13 +0200319 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime = {};
Chen Xing9c16af72019-06-12 12:13:22 +0200320 constexpr int64_t kReceiveTimeMs0 = 60;
321 constexpr int64_t kReceiveTimeMs1 = 61;
322
323 SimulatedClock clock(1000000000000ULL);
324 SourceTracker tracker(&clock);
325
Chen Xinge08648d2019-08-05 16:29:13 +0200326 tracker.OnFrameDelivered(RtpPacketInfos(
327 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kAudioLevel0,
328 kAbsoluteCaptureTime, kReceiveTimeMs0)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200329
330 clock.AdvanceTimeMilliseconds(17);
331
Chen Xinge08648d2019-08-05 16:29:13 +0200332 tracker.OnFrameDelivered(RtpPacketInfos(
333 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1, kAudioLevel1,
334 kAbsoluteCaptureTime, kReceiveTimeMs1)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200335
336 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
337
338 clock.AdvanceTimeMilliseconds(SourceTracker::kTimeoutMs);
339
340 EXPECT_THAT(
341 tracker.GetSources(),
342 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
343 kAudioLevel1, kRtpTimestamp1),
344 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
345 kAudioLevel1, kRtpTimestamp1),
346 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
347 kAudioLevel1, kRtpTimestamp1)));
348}
349
350} // namespace webrtc