Ignore non-active fullscreen windows for shelf state.
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_oracle_unittest.cc
blob40c1826d95794fb0c40dd9b55c058ac34a24957d
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/media/video_capture_oracle.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/time/time.h"
9 #include "testing/gtest/include/gtest/gtest.h"
11 namespace content {
12 namespace {
14 void SteadyStateSampleAndAdvance(base::TimeDelta vsync,
15 SmoothEventSampler* sampler, base::Time* t) {
16 ASSERT_TRUE(sampler->AddEventAndConsiderSampling(*t));
17 ASSERT_TRUE(sampler->HasUnrecordedEvent());
18 sampler->RecordSample();
19 ASSERT_FALSE(sampler->HasUnrecordedEvent());
20 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
21 *t += vsync;
22 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
25 void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync,
26 SmoothEventSampler* sampler, base::Time* t) {
27 ASSERT_FALSE(sampler->AddEventAndConsiderSampling(*t));
28 ASSERT_TRUE(sampler->HasUnrecordedEvent());
29 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
30 *t += vsync;
31 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t));
34 void TestRedundantCaptureStrategy(base::TimeDelta capture_period,
35 int redundant_capture_goal,
36 SmoothEventSampler* sampler, base::Time* t) {
37 // Before any events have been considered, we're overdue for sampling.
38 ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t));
40 // Consider the first event. We want to sample that.
41 ASSERT_FALSE(sampler->HasUnrecordedEvent());
42 ASSERT_TRUE(sampler->AddEventAndConsiderSampling(*t));
43 ASSERT_TRUE(sampler->HasUnrecordedEvent());
44 sampler->RecordSample();
45 ASSERT_FALSE(sampler->HasUnrecordedEvent());
47 // After more than one capture period has passed without considering an event,
48 // we should repeatedly be overdue for sampling. However, once the redundant
49 // capture goal is achieved, we should no longer be overdue for sampling.
50 *t += capture_period * 4;
51 for (int i = 0; i < redundant_capture_goal; i++) {
52 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
53 ASSERT_FALSE(sampler->HasUnrecordedEvent());
54 ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t))
55 << "Should sample until redundant capture goal is hit";
56 sampler->RecordSample();
57 *t += capture_period; // Timer fires once every capture period.
59 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t))
60 << "Should not be overdue once redundant capture goal achieved.";
63 // 60Hz sampled at 30Hz should produce 30Hz. In addition, this test contains
64 // much more comprehensive before/after/edge-case scenarios than the others.
65 TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) {
66 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
67 const int redundant_capture_goal = 200;
68 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60;
70 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
71 base::Time t;
72 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
74 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
75 &sampler, &t);
77 // Steady state, we should capture every other vsync, indefinitely.
78 for (int i = 0; i < 100; i++) {
79 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
80 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
81 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
84 // Now pretend we're limited by backpressure in the pipeline. In this scenario
85 // case we are adding events but not sampling them.
86 for (int i = 0; i < 20; i++) {
87 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
88 ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t));
89 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
90 ASSERT_TRUE(sampler.HasUnrecordedEvent());
91 t += vsync;
94 // Now suppose we can sample again. We should be back in the steady state,
95 // but at a different phase.
96 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
97 for (int i = 0; i < 100; i++) {
98 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
99 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
100 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
104 // 50Hz sampled at 30Hz should produce a sequence where some frames are skipped.
105 TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) {
106 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
107 const int redundant_capture_goal = 2;
108 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50;
110 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
111 base::Time t;
112 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
114 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
115 &sampler, &t);
117 // Steady state, we should capture 1st, 2nd and 4th frames out of every five
118 // frames, indefinitely.
119 for (int i = 0; i < 100; i++) {
120 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
121 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
122 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
123 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
124 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
125 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
128 // Now pretend we're limited by backpressure in the pipeline. In this scenario
129 // case we are adding events but not sampling them.
130 for (int i = 0; i < 12; i++) {
131 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
132 ASSERT_EQ(i >= 5, sampler.IsOverdueForSamplingAt(t));
133 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
134 t += vsync;
137 // Now suppose we can sample again. We should be back in the steady state
138 // again.
139 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
140 for (int i = 0; i < 100; i++) {
141 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
142 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
143 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
144 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
145 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
146 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
150 // 75Hz sampled at 30Hz should produce a sequence where some frames are skipped.
151 TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) {
152 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
153 const int redundant_capture_goal = 32;
154 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75;
156 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
157 base::Time t;
158 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
160 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
161 &sampler, &t);
163 // Steady state, we should capture 1st and 3rd frames out of every five
164 // frames, indefinitely.
165 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
166 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
167 for (int i = 0; i < 100; i++) {
168 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
169 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
170 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
171 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
172 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
173 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
176 // Now pretend we're limited by backpressure in the pipeline. In this scenario
177 // case we are adding events but not sampling them.
178 for (int i = 0; i < 20; i++) {
179 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
180 ASSERT_EQ(i >= 8, sampler.IsOverdueForSamplingAt(t));
181 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
182 t += vsync;
185 // Now suppose we can sample again. We capture the next frame, and not the one
186 // after that, and then we're back in the steady state again.
187 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
188 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
189 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
190 for (int i = 0; i < 100; i++) {
191 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
192 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
193 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
194 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
195 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
196 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t);
200 // 30Hz sampled at 30Hz should produce 30Hz.
201 TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) {
202 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
203 const int redundant_capture_goal = 1;
204 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30;
206 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
207 base::Time t;
208 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
210 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
211 &sampler, &t);
213 // Steady state, we should capture every vsync, indefinitely.
214 for (int i = 0; i < 200; i++) {
215 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
216 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
219 // Now pretend we're limited by backpressure in the pipeline. In this scenario
220 // case we are adding events but not sampling them.
221 for (int i = 0; i < 7; i++) {
222 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
223 ASSERT_EQ(i >= 3, sampler.IsOverdueForSamplingAt(t));
224 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
225 t += vsync;
228 // Now suppose we can sample again. We should be back in the steady state.
229 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
230 for (int i = 0; i < 100; i++) {
231 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
232 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
236 // 24Hz sampled at 30Hz should produce 24Hz.
237 TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) {
238 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
239 const int redundant_capture_goal = 333;
240 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24;
242 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal);
243 base::Time t;
244 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
246 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal,
247 &sampler, &t);
249 // Steady state, we should capture every vsync, indefinitely.
250 for (int i = 0; i < 200; i++) {
251 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
252 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
255 // Now pretend we're limited by backpressure in the pipeline. In this scenario
256 // case we are adding events but not sampling them.
257 for (int i = 0; i < 7; i++) {
258 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
259 ASSERT_EQ(i >= 3, sampler.IsOverdueForSamplingAt(t));
260 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
261 t += vsync;
264 // Now suppose we can sample again. We should be back in the steady state.
265 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t));
266 for (int i = 0; i < 100; i++) {
267 SCOPED_TRACE(base::StringPrintf("Iteration %d", i));
268 SteadyStateSampleAndAdvance(vsync, &sampler, &t);
272 TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) {
273 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30;
274 const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1);
276 SmoothEventSampler sampler(capture_period, true, 1);
277 base::Time t;
278 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
280 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
281 sampler.RecordSample();
282 ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t))
283 << "Sampled last event; should not be dirty.";
284 t += overdue_period;
286 // Now simulate 2 events with the same clock value.
287 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t));
288 sampler.RecordSample();
289 ASSERT_FALSE(sampler.AddEventAndConsiderSampling(t))
290 << "Two events at same time -- expected second not to be sampled.";
291 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t + overdue_period))
292 << "Second event should dirty the capture state.";
293 sampler.RecordSample();
294 ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t + overdue_period));
297 TEST(SmoothEventSamplerTest, FallbackToPollingIfUpdatesUnreliable) {
298 const base::TimeDelta timer_interval = base::TimeDelta::FromSeconds(1) / 30;
300 SmoothEventSampler should_not_poll(timer_interval, true, 1);
301 SmoothEventSampler should_poll(timer_interval, false, 1);
302 base::Time t;
303 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
305 // Do one round of the "happy case" where an event was received and
306 // RecordSample() was called by the client.
307 ASSERT_TRUE(should_not_poll.AddEventAndConsiderSampling(t));
308 ASSERT_TRUE(should_poll.AddEventAndConsiderSampling(t));
309 should_not_poll.RecordSample();
310 should_poll.RecordSample();
312 // One time period ahead, neither sampler says we're overdue.
313 for (int i = 0; i < 3; i++) {
314 t += timer_interval;
315 ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
316 << "Sampled last event; should not be dirty.";
317 ASSERT_FALSE(should_poll.IsOverdueForSamplingAt(t))
318 << "Dirty interval has not elapsed yet.";
321 // Next time period ahead, both samplers say we're overdue. The non-polling
322 // sampler is returning true here because it has been configured to allow one
323 // redundant capture.
324 t += timer_interval;
325 ASSERT_TRUE(should_not_poll.IsOverdueForSamplingAt(t))
326 << "Sampled last event; is dirty one time only to meet redundancy goal.";
327 ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
328 << "If updates are unreliable, must fall back to polling when idle.";
329 should_not_poll.RecordSample();
330 should_poll.RecordSample();
332 // Forever more, the non-polling sampler returns false while the polling one
333 // returns true.
334 for (int i = 0; i < 100; ++i) {
335 t += timer_interval;
336 ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
337 << "Sampled last event; should not be dirty.";
338 ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
339 << "If updates are unreliable, must fall back to polling when idle.";
340 should_poll.RecordSample();
342 t += timer_interval / 3;
343 ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t))
344 << "Sampled last event; should not be dirty.";
345 ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t))
346 << "If updates are unreliable, must fall back to polling when idle.";
347 should_poll.RecordSample();
350 struct DataPoint {
351 bool should_capture;
352 double increment_ms;
355 void ReplayCheckingSamplerDecisions(const DataPoint* data_points,
356 size_t num_data_points,
357 SmoothEventSampler* sampler) {
358 base::Time t;
359 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t));
360 for (size_t i = 0; i < num_data_points; ++i) {
361 t += base::TimeDelta::FromMicroseconds(
362 static_cast<int64>(data_points[i].increment_ms * 1000));
363 ASSERT_EQ(data_points[i].should_capture,
364 sampler->AddEventAndConsiderSampling(t))
365 << "at data_points[" << i << ']';
366 if (data_points[i].should_capture)
367 sampler->RecordSample();
371 TEST(SmoothEventSamplerTest, DrawingAt24FpsWith60HzVsyncSampledAt30Hertz) {
372 // Actual capturing of timing data: Initial instability as a 24 FPS video was
373 // started from a still screen, then clearly followed by steady-state.
374 static const DataPoint data_points[] = {
375 { true, 1437.93 }, { true, 150.484 }, { true, 217.362 }, { true, 50.161 },
376 { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 66.88 },
377 { true, 50.161 }, { false, 0 }, { false, 0 }, { true, 50.16 },
378 { true, 33.441 }, { true, 16.72 }, { false, 16.72 }, { true, 117.041 },
379 { true, 16.72 }, { false, 16.72 }, { true, 50.161 }, { true, 50.16 },
380 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 16.72 },
381 { false, 0 }, { true, 50.161 }, { false, 0 }, { true, 33.44 },
382 { true, 16.72 }, { false, 16.721 }, { true, 66.881 }, { false, 0 },
383 { true, 33.441 }, { true, 16.72 }, { true, 50.16 }, { true, 16.72 },
384 { false, 16.721 }, { true, 50.161 }, { true, 50.16 }, { false, 0 },
385 { true, 33.441 }, { true, 50.337 }, { true, 50.183 }, { true, 16.722 },
386 { true, 50.161 }, { true, 33.441 }, { true, 50.16 }, { true, 33.441 },
387 { true, 50.16 }, { true, 33.441 }, { true, 50.16 }, { true, 33.44 },
388 { true, 50.161 }, { true, 50.16 }, { true, 33.44 }, { true, 33.441 },
389 { true, 50.16 }, { true, 50.161 }, { true, 33.44 }, { true, 33.441 },
390 { true, 50.16 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
391 { true, 50.161 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 },
392 { true, 83.601 }, { true, 16.72 }, { true, 33.44 }, { false, 0 }
395 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
396 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
399 TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) {
400 // Actual capturing of timing data: Initial instability as a 30 FPS video was
401 // started from a still screen, then followed by steady-state. Drawing
402 // framerate from the video rendering was a bit volatile, but averaged 30 FPS.
403 static const DataPoint data_points[] = {
404 { true, 2407.69 }, { true, 16.733 }, { true, 217.362 }, { true, 33.441 },
405 { true, 33.44 }, { true, 33.44 }, { true, 33.441 }, { true, 33.44 },
406 { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 },
407 { true, 16.721 }, { true, 33.44 }, { false, 0 }, { true, 50.161 },
408 { true, 50.16 }, { false, 0 }, { true, 50.161 }, { true, 33.44 },
409 { true, 16.72 }, { false, 0 }, { false, 16.72 }, { true, 66.881 },
410 { false, 0 }, { true, 33.44 }, { true, 16.72 }, { true, 50.161 },
411 { false, 0 }, { true, 33.538 }, { true, 33.526 }, { true, 33.447 },
412 { true, 33.445 }, { true, 33.441 }, { true, 16.721 }, { true, 33.44 },
413 { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, { true, 33.44 },
414 { true, 33.441 }, { true, 33.44 }, { false, 0 }, { false, 16.72 },
415 { true, 66.881 }, { true, 16.72 }, { false, 16.72 }, { true, 50.16 },
416 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 33.44 },
417 { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { false, 0 },
418 { true, 33.44 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
419 { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 66.88 },
420 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
421 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 },
422 { true, 16.72 }, { true, 50.161 }, { false, 0 }, { true, 50.16 },
423 { false, 0.001 }, { true, 16.721 }, { true, 66.88 }, { true, 33.44 },
424 { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 },
425 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 66.881 },
426 { true, 33.44 }, { true, 16.72 }, { true, 33.441 }, { false, 16.72 },
427 { true, 66.88 }, { true, 16.721 }, { true, 50.16 }, { true, 33.44 },
428 { true, 16.72 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 }
431 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
432 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
435 TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) {
436 // Actual capturing of timing data: WebGL Acquarium demo
437 // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran
438 // between 55-60 FPS in the steady-state.
439 static const DataPoint data_points[] = {
440 { true, 16.72 }, { true, 16.72 }, { true, 4163.29 }, { true, 50.193 },
441 { true, 117.041 }, { true, 50.161 }, { true, 50.16 }, { true, 33.441 },
442 { true, 50.16 }, { true, 33.44 }, { false, 0 }, { false, 0 },
443 { true, 50.161 }, { true, 83.601 }, { true, 50.16 }, { true, 16.72 },
444 { true, 33.441 }, { false, 16.72 }, { true, 50.16 }, { true, 16.72 },
445 { false, 0.001 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
446 { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
447 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
448 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
449 { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
450 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
451 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 33.44 },
452 { false, 0 }, { true, 16.721 }, { true, 50.161 }, { false, 0 },
453 { true, 33.44 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
454 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 },
455 { true, 50.16 }, { false, 0 }, { true, 16.721 }, { true, 33.44 },
456 { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 },
457 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 },
458 { false, 0 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 },
459 { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 },
460 { true, 33.44 }, { false, 0 }, { true, 33.44 }, { true, 33.441 },
461 { false, 0 }, { true, 33.44 }, { true, 33.441 }, { false, 0 },
462 { true, 33.44 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
463 { true, 16.721 }, { true, 50.161 }, { false, 0 }, { true, 16.72 },
464 { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 33.44 },
465 { true, 33.44 }, { false, 0 }, { true, 33.441 }, { false, 16.72 },
466 { true, 16.72 }, { true, 50.16 }, { false, 0 }, { true, 16.72 },
467 { true, 33.441 }, { false, 0 }, { true, 33.44 }, { false, 16.72 },
468 { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 50.161 },
469 { false, 0 }, { true, 16.72 }, { true, 33.44 }, { false, 0 },
470 { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, { true, 50.16 }
473 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3);
474 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler);
477 } // namespace
478 } // namespace content