blob: 23426978ada440177e27436c878ce46743a8d701 [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(),
112 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
173 int64_t GenerateReceiveTimeMs() {
174 return std::uniform_int_distribution<int64_t>()(generator_);
175 }
176
177 const uint32_t ssrcs_count_;
178 const uint32_t csrcs_count_;
179
180 std::mt19937 generator_;
181};
182
183} // namespace
184
185TEST_P(SourceTrackerRandomTest, RandomOperations) {
186 constexpr size_t kIterationsCount = 200;
187
188 SimulatedClock clock(1000000000000ULL);
189 SourceTracker actual_tracker(&clock);
190 ExpectedSourceTracker expected_tracker(&clock);
191
192 ASSERT_THAT(actual_tracker.GetSources(), IsEmpty());
193 ASSERT_THAT(expected_tracker.GetSources(), IsEmpty());
194
195 for (size_t i = 0; i < kIterationsCount; ++i) {
196 RtpPacketInfos packet_infos = GeneratePacketInfos();
197
198 actual_tracker.OnFrameDelivered(packet_infos);
199 expected_tracker.OnFrameDelivered(packet_infos);
200
201 clock.AdvanceTimeMilliseconds(GenerateClockAdvanceTimeMilliseconds());
202
203 ASSERT_THAT(actual_tracker.GetSources(),
204 ElementsAreArray(expected_tracker.GetSources()));
205 }
206}
207
208INSTANTIATE_TEST_SUITE_P(,
209 SourceTrackerRandomTest,
210 Combine(/*ssrcs_count_=*/Values(1, 2, 4),
211 /*csrcs_count_=*/Values(0, 1, 3, 7)));
212
213TEST(SourceTrackerTest, StartEmpty) {
214 SimulatedClock clock(1000000000000ULL);
215 SourceTracker tracker(&clock);
216
217 EXPECT_THAT(tracker.GetSources(), IsEmpty());
218}
219
220TEST(SourceTrackerTest, OnFrameDeliveredRecordsSources) {
221 constexpr uint32_t kSsrc = 10;
Chen Xing12d64de2019-06-13 20:36:12 +0200222 constexpr uint32_t kCsrcs0 = 20;
223 constexpr uint32_t kCsrcs1 = 21;
Chen Xing9c16af72019-06-12 12:13:22 +0200224 constexpr uint32_t kRtpTimestamp = 40;
225 constexpr absl::optional<uint8_t> kAudioLevel = 50;
226 constexpr int64_t kReceiveTimeMs = 60;
227
228 SimulatedClock clock(1000000000000ULL);
229 SourceTracker tracker(&clock);
230
Chen Xing12d64de2019-06-13 20:36:12 +0200231 tracker.OnFrameDelivered(RtpPacketInfos({RtpPacketInfo(
232 kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp, kAudioLevel, kReceiveTimeMs)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200233
234 int64_t timestamp_ms = clock.TimeInMilliseconds();
235
Chen Xing12d64de2019-06-13 20:36:12 +0200236 EXPECT_THAT(tracker.GetSources(),
237 ElementsAre(RtpSource(timestamp_ms, kSsrc, RtpSourceType::SSRC,
238 kAudioLevel, kRtpTimestamp),
239 RtpSource(timestamp_ms, kCsrcs1, RtpSourceType::CSRC,
240 kAudioLevel, kRtpTimestamp),
241 RtpSource(timestamp_ms, kCsrcs0, RtpSourceType::CSRC,
242 kAudioLevel, kRtpTimestamp)));
Chen Xing9c16af72019-06-12 12:13:22 +0200243}
244
245TEST(SourceTrackerTest, OnFrameDeliveredUpdatesSources) {
246 constexpr uint32_t kSsrc = 10;
247 constexpr uint32_t kCsrcs0 = 20;
248 constexpr uint32_t kCsrcs1 = 21;
249 constexpr uint32_t kCsrcs2 = 22;
Chen Xing9c16af72019-06-12 12:13:22 +0200250 constexpr uint32_t kRtpTimestamp0 = 40;
251 constexpr uint32_t kRtpTimestamp1 = 41;
252 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
253 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
254 constexpr int64_t kReceiveTimeMs0 = 60;
255 constexpr int64_t kReceiveTimeMs1 = 61;
256
257 SimulatedClock clock(1000000000000ULL);
258 SourceTracker tracker(&clock);
259
Chen Xing12d64de2019-06-13 20:36:12 +0200260 tracker.OnFrameDelivered(
261 RtpPacketInfos({RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0,
262 kAudioLevel0, kReceiveTimeMs0)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200263
264 int64_t timestamp_ms_0 = clock.TimeInMilliseconds();
265
266 clock.AdvanceTimeMilliseconds(17);
267
Chen Xing12d64de2019-06-13 20:36:12 +0200268 tracker.OnFrameDelivered(
269 RtpPacketInfos({RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1,
270 kAudioLevel1, kReceiveTimeMs1)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200271
272 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
273
274 EXPECT_THAT(
275 tracker.GetSources(),
276 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
277 kAudioLevel1, kRtpTimestamp1),
278 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
279 kAudioLevel1, kRtpTimestamp1),
280 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
281 kAudioLevel1, kRtpTimestamp1),
282 RtpSource(timestamp_ms_0, kCsrcs1, RtpSourceType::CSRC,
283 kAudioLevel0, kRtpTimestamp0)));
284}
285
286TEST(SourceTrackerTest, TimedOutSourcesAreRemoved) {
287 constexpr uint32_t kSsrc = 10;
288 constexpr uint32_t kCsrcs0 = 20;
289 constexpr uint32_t kCsrcs1 = 21;
290 constexpr uint32_t kCsrcs2 = 22;
Chen Xing9c16af72019-06-12 12:13:22 +0200291 constexpr uint32_t kRtpTimestamp0 = 40;
292 constexpr uint32_t kRtpTimestamp1 = 41;
293 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
294 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
295 constexpr int64_t kReceiveTimeMs0 = 60;
296 constexpr int64_t kReceiveTimeMs1 = 61;
297
298 SimulatedClock clock(1000000000000ULL);
299 SourceTracker tracker(&clock);
300
Chen Xing12d64de2019-06-13 20:36:12 +0200301 tracker.OnFrameDelivered(
302 RtpPacketInfos({RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kRtpTimestamp0,
303 kAudioLevel0, kReceiveTimeMs0)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200304
305 clock.AdvanceTimeMilliseconds(17);
306
Chen Xing12d64de2019-06-13 20:36:12 +0200307 tracker.OnFrameDelivered(
308 RtpPacketInfos({RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kRtpTimestamp1,
309 kAudioLevel1, kReceiveTimeMs1)}));
Chen Xing9c16af72019-06-12 12:13:22 +0200310
311 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
312
313 clock.AdvanceTimeMilliseconds(SourceTracker::kTimeoutMs);
314
315 EXPECT_THAT(
316 tracker.GetSources(),
317 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
318 kAudioLevel1, kRtpTimestamp1),
319 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
320 kAudioLevel1, kRtpTimestamp1),
321 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
322 kAudioLevel1, kRtpTimestamp1)));
323}
324
325} // namespace webrtc