blob: d48785411b77f727dd5633d4f420dffaf2ffb409 [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(),
111 GenerateSequenceNumber(),
112 GenerateRtpTimestamp(), GenerateAudioLevel(),
113 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
160 uint16_t GenerateSequenceNumber() {
161 return std::uniform_int_distribution<uint16_t>()(generator_);
162 }
163
164 uint32_t GenerateRtpTimestamp() {
165 return std::uniform_int_distribution<uint32_t>()(generator_);
166 }
167
168 absl::optional<uint8_t> GenerateAudioLevel() {
169 if (std::bernoulli_distribution(0.25)(generator_)) {
170 return absl::nullopt;
171 }
172
173 // Workaround for std::uniform_int_distribution<uint8_t> not being allowed.
174 return static_cast<uint8_t>(
175 std::uniform_int_distribution<uint16_t>()(generator_));
176 }
177
178 int64_t GenerateReceiveTimeMs() {
179 return std::uniform_int_distribution<int64_t>()(generator_);
180 }
181
182 const uint32_t ssrcs_count_;
183 const uint32_t csrcs_count_;
184
185 std::mt19937 generator_;
186};
187
188} // namespace
189
190TEST_P(SourceTrackerRandomTest, RandomOperations) {
191 constexpr size_t kIterationsCount = 200;
192
193 SimulatedClock clock(1000000000000ULL);
194 SourceTracker actual_tracker(&clock);
195 ExpectedSourceTracker expected_tracker(&clock);
196
197 ASSERT_THAT(actual_tracker.GetSources(), IsEmpty());
198 ASSERT_THAT(expected_tracker.GetSources(), IsEmpty());
199
200 for (size_t i = 0; i < kIterationsCount; ++i) {
201 RtpPacketInfos packet_infos = GeneratePacketInfos();
202
203 actual_tracker.OnFrameDelivered(packet_infos);
204 expected_tracker.OnFrameDelivered(packet_infos);
205
206 clock.AdvanceTimeMilliseconds(GenerateClockAdvanceTimeMilliseconds());
207
208 ASSERT_THAT(actual_tracker.GetSources(),
209 ElementsAreArray(expected_tracker.GetSources()));
210 }
211}
212
213INSTANTIATE_TEST_SUITE_P(,
214 SourceTrackerRandomTest,
215 Combine(/*ssrcs_count_=*/Values(1, 2, 4),
216 /*csrcs_count_=*/Values(0, 1, 3, 7)));
217
218TEST(SourceTrackerTest, StartEmpty) {
219 SimulatedClock clock(1000000000000ULL);
220 SourceTracker tracker(&clock);
221
222 EXPECT_THAT(tracker.GetSources(), IsEmpty());
223}
224
225TEST(SourceTrackerTest, OnFrameDeliveredRecordsSources) {
226 constexpr uint32_t kSsrc = 10;
227 constexpr uint32_t kCsrcs[] = {20, 21};
228 constexpr uint16_t kSequenceNumber = 30;
229 constexpr uint32_t kRtpTimestamp = 40;
230 constexpr absl::optional<uint8_t> kAudioLevel = 50;
231 constexpr int64_t kReceiveTimeMs = 60;
232
233 SimulatedClock clock(1000000000000ULL);
234 SourceTracker tracker(&clock);
235
236 tracker.OnFrameDelivered(RtpPacketInfos(
237 {RtpPacketInfo(kSsrc, {kCsrcs[0], kCsrcs[1]}, kSequenceNumber,
238 kRtpTimestamp, kAudioLevel, kReceiveTimeMs)}));
239
240 int64_t timestamp_ms = clock.TimeInMilliseconds();
241
242 EXPECT_THAT(
243 tracker.GetSources(),
244 ElementsAre(RtpSource(timestamp_ms, kSsrc, RtpSourceType::SSRC,
245 kAudioLevel, kRtpTimestamp),
246 RtpSource(timestamp_ms, kCsrcs[1], RtpSourceType::CSRC,
247 kAudioLevel, kRtpTimestamp),
248 RtpSource(timestamp_ms, kCsrcs[0], RtpSourceType::CSRC,
249 kAudioLevel, kRtpTimestamp)));
250}
251
252TEST(SourceTrackerTest, OnFrameDeliveredUpdatesSources) {
253 constexpr uint32_t kSsrc = 10;
254 constexpr uint32_t kCsrcs0 = 20;
255 constexpr uint32_t kCsrcs1 = 21;
256 constexpr uint32_t kCsrcs2 = 22;
257 constexpr uint16_t kSequenceNumber0 = 30;
258 constexpr uint16_t kSequenceNumber1 = 31;
259 constexpr uint32_t kRtpTimestamp0 = 40;
260 constexpr uint32_t kRtpTimestamp1 = 41;
261 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
262 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
263 constexpr int64_t kReceiveTimeMs0 = 60;
264 constexpr int64_t kReceiveTimeMs1 = 61;
265
266 SimulatedClock clock(1000000000000ULL);
267 SourceTracker tracker(&clock);
268
269 tracker.OnFrameDelivered(RtpPacketInfos(
270 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kSequenceNumber0,
271 kRtpTimestamp0, kAudioLevel0, kReceiveTimeMs0)}));
272
273 int64_t timestamp_ms_0 = clock.TimeInMilliseconds();
274
275 clock.AdvanceTimeMilliseconds(17);
276
277 tracker.OnFrameDelivered(RtpPacketInfos(
278 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kSequenceNumber1,
279 kRtpTimestamp1, kAudioLevel1, kReceiveTimeMs1)}));
280
281 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
282
283 EXPECT_THAT(
284 tracker.GetSources(),
285 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
286 kAudioLevel1, kRtpTimestamp1),
287 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
288 kAudioLevel1, kRtpTimestamp1),
289 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
290 kAudioLevel1, kRtpTimestamp1),
291 RtpSource(timestamp_ms_0, kCsrcs1, RtpSourceType::CSRC,
292 kAudioLevel0, kRtpTimestamp0)));
293}
294
295TEST(SourceTrackerTest, TimedOutSourcesAreRemoved) {
296 constexpr uint32_t kSsrc = 10;
297 constexpr uint32_t kCsrcs0 = 20;
298 constexpr uint32_t kCsrcs1 = 21;
299 constexpr uint32_t kCsrcs2 = 22;
300 constexpr uint16_t kSequenceNumber0 = 30;
301 constexpr uint16_t kSequenceNumber1 = 31;
302 constexpr uint32_t kRtpTimestamp0 = 40;
303 constexpr uint32_t kRtpTimestamp1 = 41;
304 constexpr absl::optional<uint8_t> kAudioLevel0 = 50;
305 constexpr absl::optional<uint8_t> kAudioLevel1 = absl::nullopt;
306 constexpr int64_t kReceiveTimeMs0 = 60;
307 constexpr int64_t kReceiveTimeMs1 = 61;
308
309 SimulatedClock clock(1000000000000ULL);
310 SourceTracker tracker(&clock);
311
312 tracker.OnFrameDelivered(RtpPacketInfos(
313 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs1}, kSequenceNumber0,
314 kRtpTimestamp0, kAudioLevel0, kReceiveTimeMs0)}));
315
316 clock.AdvanceTimeMilliseconds(17);
317
318 tracker.OnFrameDelivered(RtpPacketInfos(
319 {RtpPacketInfo(kSsrc, {kCsrcs0, kCsrcs2}, kSequenceNumber1,
320 kRtpTimestamp1, kAudioLevel1, kReceiveTimeMs1)}));
321
322 int64_t timestamp_ms_1 = clock.TimeInMilliseconds();
323
324 clock.AdvanceTimeMilliseconds(SourceTracker::kTimeoutMs);
325
326 EXPECT_THAT(
327 tracker.GetSources(),
328 ElementsAre(RtpSource(timestamp_ms_1, kSsrc, RtpSourceType::SSRC,
329 kAudioLevel1, kRtpTimestamp1),
330 RtpSource(timestamp_ms_1, kCsrcs2, RtpSourceType::CSRC,
331 kAudioLevel1, kRtpTimestamp1),
332 RtpSource(timestamp_ms_1, kCsrcs0, RtpSourceType::CSRC,
333 kAudioLevel1, kRtpTimestamp1)));
334}
335
336} // namespace webrtc