blob: 8f6a5125a3ef92a9a2ba312cba6b9d4d56cf1c42 [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;
Chen Xing9c16af72019-06-12 12:13:22 +020034using ::testing::TestWithParam;
35using ::testing::Values;
36
37constexpr size_t kPacketInfosCountMax = 5;
38
39// Simple "guaranteed to be correct" re-implementation of |SourceTracker| for
40// dual-implementation testing purposes.
41class ExpectedSourceTracker {
42 public:
43 explicit ExpectedSourceTracker(Clock* clock) : clock_(clock) {}
44
45 void OnFrameDelivered(const RtpPacketInfos& packet_infos) {
46 const int64_t now_ms = clock_->TimeInMilliseconds();
47
48 for (const auto& packet_info : packet_infos) {
49 for (const auto& csrc : packet_info.csrcs()) {
50 entries_.emplace_front(now_ms, csrc, RtpSourceType::CSRC,
51 packet_info.audio_level(),
52 packet_info.rtp_timestamp());
53 }
54
55 entries_.emplace_front(now_ms, packet_info.ssrc(), RtpSourceType::SSRC,
56 packet_info.audio_level(),
57 packet_info.rtp_timestamp());
58 }
59
60 PruneEntries(now_ms);
61 }
62
63 std::vector<RtpSource> GetSources() const {
64 PruneEntries(clock_->TimeInMilliseconds());
65
66 return std::vector<RtpSource>(entries_.begin(), entries_.end());
67 }
68
69 private:
70 void PruneEntries(int64_t now_ms) const {
71 const int64_t prune_ms = now_ms - 10000; // 10 seconds
72
73 std::set<std::pair<RtpSourceType, uint32_t>> seen;
74
75 auto it = entries_.begin();
76 auto end = entries_.end();
77 while (it != end) {
78 auto next = it;
79 ++next;
80
81 auto key = std::make_pair(it->source_type(), it->source_id());
82 if (!seen.insert(key).second || it->timestamp_ms() < prune_ms) {
83 entries_.erase(it);
84 }
85
86 it = next;
87 }
88 }
89
90 Clock* const clock_;
91
92 mutable std::list<RtpSource> entries_;
93};
94
95class SourceTrackerRandomTest
96 : public TestWithParam<std::tuple<uint32_t, uint32_t>> {
97 protected:
98 SourceTrackerRandomTest()
99 : ssrcs_count_(std::get<0>(GetParam())),
100 csrcs_count_(std::get<1>(GetParam())),
101 generator_(42) {}
102
103 RtpPacketInfos GeneratePacketInfos() {
104 size_t count = std::uniform_int_distribution<size_t>(
105 1, kPacketInfosCountMax)(generator_);
106
107 RtpPacketInfos::vector_type packet_infos;
108 for (size_t i = 0; i < count; ++i) {
109 packet_infos.emplace_back(GenerateSsrc(), GenerateCsrcs(),
Chen Xing9c16af72019-06-12 12:13:22 +0200110 GenerateRtpTimestamp(), GenerateAudioLevel(),
Chen Xinge08648d2019-08-05 16:29:13 +0200111 GenerateAbsoluteCaptureTime(),
Chen Xing9c16af72019-06-12 12:13:22 +0200112 GenerateReceiveTimeMs());
113 }
114
115 return RtpPacketInfos(std::move(packet_infos));
116 }
117
118 int64_t GenerateClockAdvanceTimeMilliseconds() {
119 double roll = std::uniform_real_distribution<double>(0.0, 1.0)(generator_);
120
121 if (roll < 0.05) {
122 return 0;
123 }
124
125 if (roll < 0.08) {
126 return SourceTracker::kTimeoutMs - 1;
127 }
128
129 if (roll < 0.11) {
130 return SourceTracker::kTimeoutMs;
131 }
132
133 if (roll < 0.19) {
134 return std::uniform_int_distribution<int64_t>(
135 SourceTracker::kTimeoutMs,
136 SourceTracker::kTimeoutMs * 1000)(generator_);
137 }
138
139 return std::uniform_int_distribution<int64_t>(
140 1, SourceTracker::kTimeoutMs - 1)(generator_);
141 }
142
143 private:
144 uint32_t GenerateSsrc() {
145 return std::uniform_int_distribution<uint32_t>(1, ssrcs_count_)(generator_);
146 }
147
148 std::vector<uint32_t> GenerateCsrcs() {
149 std::vector<uint32_t> csrcs;
150 for (size_t i = 1; i <= csrcs_count_ && csrcs.size() < kRtpCsrcSize; ++i) {
151 if (std::bernoulli_distribution(0.5)(generator_)) {
152 csrcs.push_back(i);
153 }
154 }
155
156 return csrcs;
157 }
158
Chen Xing9c16af72019-06-12 12:13:22 +0200159 uint32_t GenerateRtpTimestamp() {
160 return std::uniform_int_distribution<uint32_t>()(generator_);
161 }
162
163 absl::optional<uint8_t> GenerateAudioLevel() {
164 if (std::bernoulli_distribution(0.25)(generator_)) {
165 return absl::nullopt;
166 }
167
168 // Workaround for std::uniform_int_distribution<uint8_t> not being allowed.
169 return static_cast<uint8_t>(
170 std::uniform_int_distribution<uint16_t>()(generator_));
171 }
172
Chen Xinge08648d2019-08-05 16:29:13 +0200173 absl::optional<AbsoluteCaptureTime> GenerateAbsoluteCaptureTime() {
174 if (std::bernoulli_distribution(0.25)(generator_)) {
175 return absl::nullopt;
176 }
177
178 AbsoluteCaptureTime value;
179
180 value.absolute_capture_timestamp =
181 std::uniform_int_distribution<uint64_t>()(generator_);
182
183 if (std::bernoulli_distribution(0.5)(generator_)) {
184 value.estimated_capture_clock_offset = absl::nullopt;
185 } else {
186 value.estimated_capture_clock_offset =
187 std::uniform_int_distribution<int64_t>()(generator_);
188 }
189
190 return value;
191 }
192
Chen Xing9c16af72019-06-12 12:13:22 +0200193 int64_t GenerateReceiveTimeMs() {
194 return std::uniform_int_distribution<int64_t>()(generator_);
195 }
196
197 const uint32_t ssrcs_count_;
198 const uint32_t csrcs_count_;
199
200 std::mt19937 generator_;
201};
202
203} // namespace
204
205TEST_P(SourceTrackerRandomTest, RandomOperations) {
206 constexpr size_t kIterationsCount = 200;
207
208 SimulatedClock clock(1000000000000ULL);
209 SourceTracker actual_tracker(&clock);
210 ExpectedSourceTracker expected_tracker(&clock);
211
212 ASSERT_THAT(actual_tracker.GetSources(), IsEmpty());
213 ASSERT_THAT(expected_tracker.GetSources(), IsEmpty());
214
215 for (size_t i = 0; i < kIterationsCount; ++i) {
216 RtpPacketInfos packet_infos = GeneratePacketInfos();
217
218 actual_tracker.OnFrameDelivered(packet_infos);
219 expected_tracker.OnFrameDelivered(packet_infos);
220
221 clock.AdvanceTimeMilliseconds(GenerateClockAdvanceTimeMilliseconds());
222
223 ASSERT_THAT(actual_tracker.GetSources(),
224 ElementsAreArray(expected_tracker.GetSources()));
225 }
226}
227
Mirko Bonadei1b575412019-09-23 08:34:50 +0200228INSTANTIATE_TEST_SUITE_P(All,
Chen Xing9c16af72019-06-12 12:13:22 +0200229 SourceTrackerRandomTest,
230 Combine(/*ssrcs_count_=*/Values(1, 2, 4),
231 /*csrcs_count_=*/Values(0, 1, 3, 7)));
232
233TEST(SourceTrackerTest, StartEmpty) {
234 SimulatedClock clock(1000000000000ULL);
235 SourceTracker tracker(&clock);
236
237 EXPECT_THAT(tracker.GetSources(), IsEmpty());
238}
239
240TEST(SourceTrackerTest, OnFrameDeliveredRecordsSources) {
241 constexpr uint32_t kSsrc = 10;
Chen Xing12d64de2019-06-13 20:36:12 +0200242 constexpr uint32_t kCsrcs0 = 20;
243 constexpr uint32_t kCsrcs1 = 21;
Chen Xing9c16af72019-06-12 12:13:22 +0200244 constexpr uint32_t kRtpTimestamp = 40;
245 constexpr absl::optional<uint8_t> kAudioLevel = 50;
Chen Xinge08648d2019-08-05 16:29:13 +0200246 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime = {};
Chen Xing9c16af72019-06-12 12:13:22 +0200247 constexpr int64_t kReceiveTimeMs = 60;
248
249 SimulatedClock clock(1000000000000ULL);
250 SourceTracker tracker(&clock);
251
Chen Xinge08648d2019-08-05 16:29:13 +0200252 tracker.OnFrameDelivered(RtpPacketInfos(
253 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp, kAudioLevel,
254 kAbsoluteCaptureTime, kReceiveTimeMs)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200255
256 int64_t timestamp_ms = clock.TimeInMilliseconds();
257
Chen Xing12d64de2019-06-13 20:36:12 +0200258 EXPECT_THAT(tracker.GetSources(),
259 ElementsAre(RtpSource(timestamp_ms, kSsrc, RtpSourceType::SSRC,
260 kAudioLevel, kRtpTimestamp),
261 RtpSource(timestamp_ms, kCsrcs1, RtpSourceType::CSRC,
262 kAudioLevel, kRtpTimestamp),
263 RtpSource(timestamp_ms, kCsrcs0, RtpSourceType::CSRC,
264 kAudioLevel, kRtpTimestamp)));
Chen Xing9c16af72019-06-12 12:13:22 +0200265}
266
267TEST(SourceTrackerTest, OnFrameDeliveredUpdatesSources) {
268 constexpr uint32_t kSsrc = 10;
269 constexpr uint32_t kCsrcs0 = 20;
270 constexpr uint32_t kCsrcs1 = 21;
271 constexpr uint32_t kCsrcs2 = 22;
Chen Xing9c16af72019-06-12 12:13:22 +0200272 constexpr uint32_t kRtpTimestamp0 = 40;
273 constexpr uint32_t kRtpTimestamp1 = 41;
274 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
275 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
Chen Xinge08648d2019-08-05 16:29:13 +0200276 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime = {};
Chen Xing9c16af72019-06-12 12:13:22 +0200277 constexpr int64_t kReceiveTimeMs0 = 60;
278 constexpr int64_t kReceiveTimeMs1 = 61;
279
280 SimulatedClock clock(1000000000000ULL);
281 SourceTracker tracker(&clock);
282
Chen Xinge08648d2019-08-05 16:29:13 +0200283 tracker.OnFrameDelivered(RtpPacketInfos(
284 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kAudioLevel0,
285 kAbsoluteCaptureTime, kReceiveTimeMs0)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200286
287 int64_t timestamp_ms_0 = clock.TimeInMilliseconds();
288
289 clock.AdvanceTimeMilliseconds(17);
290
Chen Xinge08648d2019-08-05 16:29:13 +0200291 tracker.OnFrameDelivered(RtpPacketInfos(
292 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1, kAudioLevel1,
293 kAbsoluteCaptureTime, kReceiveTimeMs1)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200294
295 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
296
297 EXPECT_THAT(
298 tracker.GetSources(),
299 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
300 kAudioLevel1, kRtpTimestamp1),
301 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
302 kAudioLevel1, kRtpTimestamp1),
303 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
304 kAudioLevel1, kRtpTimestamp1),
305 RtpSource(timestamp_ms_0, kCsrcs1, RtpSourceType::CSRC,
306 kAudioLevel0, kRtpTimestamp0)));
307}
308
309TEST(SourceTrackerTest, TimedOutSourcesAreRemoved) {
310 constexpr uint32_t kSsrc = 10;
311 constexpr uint32_t kCsrcs0 = 20;
312 constexpr uint32_t kCsrcs1 = 21;
313 constexpr uint32_t kCsrcs2 = 22;
Chen Xing9c16af72019-06-12 12:13:22 +0200314 constexpr uint32_t kRtpTimestamp0 = 40;
315 constexpr uint32_t kRtpTimestamp1 = 41;
316 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
317 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
Chen Xinge08648d2019-08-05 16:29:13 +0200318 constexpr absl::optional<AbsoluteCaptureTime> kAbsoluteCaptureTime = {};
Chen Xing9c16af72019-06-12 12:13:22 +0200319 constexpr int64_t kReceiveTimeMs0 = 60;
320 constexpr int64_t kReceiveTimeMs1 = 61;
321
322 SimulatedClock clock(1000000000000ULL);
323 SourceTracker tracker(&clock);
324
Chen Xinge08648d2019-08-05 16:29:13 +0200325 tracker.OnFrameDelivered(RtpPacketInfos(
326 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0, kAudioLevel0,
327 kAbsoluteCaptureTime, kReceiveTimeMs0)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200328
329 clock.AdvanceTimeMilliseconds(17);
330
Chen Xinge08648d2019-08-05 16:29:13 +0200331 tracker.OnFrameDelivered(RtpPacketInfos(
332 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1, kAudioLevel1,
333 kAbsoluteCaptureTime, kReceiveTimeMs1)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200334
335 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
336
337 clock.AdvanceTimeMilliseconds(SourceTracker::kTimeoutMs);
338
339 EXPECT_THAT(
340 tracker.GetSources(),
341 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
342 kAudioLevel1, kRtpTimestamp1),
343 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
344 kAudioLevel1, kRtpTimestamp1),
345 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
346 kAudioLevel1, kRtpTimestamp1)));
347}
348
349} // namespace webrtc