1 // Copyright 2014 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 "base/memory/ref_counted.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/rand_util.h"
8 #include "base/test/simple_test_tick_clock.h"
9 #include "base/time/tick_clock.h"
10 #include "media/cast/cast_environment.h"
11 #include "media/cast/logging/logging_defines.h"
12 #include "media/cast/logging/stats_event_subscriber.h"
13 #include "media/cast/test/fake_receiver_time_offset_estimator.h"
14 #include "media/cast/test/fake_single_thread_task_runner.h"
15 #include "testing/gtest/include/gtest/gtest.h"
18 const int kReceiverOffsetSecs = 100;
24 class StatsEventSubscriberTest : public ::testing::Test {
26 StatsEventSubscriberTest()
27 : sender_clock_(new base::SimpleTestTickClock()),
28 task_runner_(new test::FakeSingleThreadTaskRunner(sender_clock_)),
29 cast_environment_(new CastEnvironment(
30 scoped_ptr<base::TickClock>(sender_clock_).Pass(),
34 fake_offset_estimator_(
35 base::TimeDelta::FromSeconds(kReceiverOffsetSecs)) {
36 receiver_clock_.Advance(base::TimeDelta::FromSeconds(kReceiverOffsetSecs));
37 cast_environment_->Logging()->AddRawEventSubscriber(
38 &fake_offset_estimator_);
41 virtual ~StatsEventSubscriberTest() {
42 if (subscriber_.get())
43 cast_environment_->Logging()->RemoveRawEventSubscriber(subscriber_.get());
44 cast_environment_->Logging()->RemoveRawEventSubscriber(
45 &fake_offset_estimator_);
48 void AdvanceClocks(base::TimeDelta delta) {
49 sender_clock_->Advance(delta);
50 receiver_clock_.Advance(delta);
53 void Init(EventMediaType event_media_type) {
54 DCHECK(!subscriber_.get());
55 subscriber_.reset(new StatsEventSubscriber(
56 event_media_type, cast_environment_->Clock(), &fake_offset_estimator_));
57 cast_environment_->Logging()->AddRawEventSubscriber(subscriber_.get());
60 base::SimpleTestTickClock* sender_clock_; // Owned by CastEnvironment.
61 base::SimpleTestTickClock receiver_clock_;
62 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
63 scoped_refptr<CastEnvironment> cast_environment_;
64 test::FakeReceiverTimeOffsetEstimator fake_offset_estimator_;
65 scoped_ptr<StatsEventSubscriber> subscriber_;
68 TEST_F(StatsEventSubscriberTest, CaptureEncode) {
71 uint32 rtp_timestamp = 0;
73 int extra_frames = 50;
74 // Only the first |extra_frames| frames logged will be taken into account
75 // when computing dropped frames.
76 int num_frames = StatsEventSubscriber::kMaxFrameInfoMapSize + 50;
77 int dropped_frames = 0;
78 base::TimeTicks start_time = sender_clock_->NowTicks();
79 // Drop half the frames during the encode step.
80 for (int i = 0; i < num_frames; i++) {
81 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
86 AdvanceClocks(base::TimeDelta::FromMicroseconds(10));
87 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
93 AdvanceClocks(base::TimeDelta::FromMicroseconds(10));
94 cast_environment_->Logging()->InsertEncodedFrameEvent(
95 sender_clock_->NowTicks(),
103 } else if (i < extra_frames) {
106 AdvanceClocks(base::TimeDelta::FromMicroseconds(34567));
111 base::TimeTicks end_time = sender_clock_->NowTicks();
113 StatsEventSubscriber::StatsMap stats_map;
114 subscriber_->GetStatsInternal(&stats_map);
116 StatsEventSubscriber::StatsMap::iterator it =
117 stats_map.find(StatsEventSubscriber::CAPTURE_FPS);
118 ASSERT_TRUE(it != stats_map.end());
120 base::TimeDelta duration = end_time - start_time;
123 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000);
125 it = stats_map.find(StatsEventSubscriber::NUM_FRAMES_CAPTURED);
126 ASSERT_TRUE(it != stats_map.end());
128 EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_frames));
130 it = stats_map.find(StatsEventSubscriber::NUM_FRAMES_DROPPED_BY_ENCODER);
131 ASSERT_TRUE(it != stats_map.end());
133 EXPECT_DOUBLE_EQ(it->second, static_cast<double>(dropped_frames));
136 TEST_F(StatsEventSubscriberTest, Encode) {
139 uint32 rtp_timestamp = 0;
142 base::TimeTicks start_time = sender_clock_->NowTicks();
143 AdvanceClocks(base::TimeDelta::FromMicroseconds(35678));
144 base::TimeTicks first_event_time = sender_clock_->NowTicks();
145 base::TimeTicks last_event_time;
147 for (int i = 0; i < num_frames; i++) {
148 int size = 1000 + base::RandInt(-100, 100);
150 cast_environment_->Logging()->InsertEncodedFrameEvent(
151 sender_clock_->NowTicks(),
152 FRAME_ENCODED, VIDEO_EVENT,
158 last_event_time = sender_clock_->NowTicks();
160 AdvanceClocks(base::TimeDelta::FromMicroseconds(35678));
165 base::TimeTicks end_time = sender_clock_->NowTicks();
167 StatsEventSubscriber::StatsMap stats_map;
168 subscriber_->GetStatsInternal(&stats_map);
170 StatsEventSubscriber::StatsMap::iterator it =
171 stats_map.find(StatsEventSubscriber::ENCODE_FPS);
172 ASSERT_TRUE(it != stats_map.end());
174 base::TimeDelta duration = end_time - start_time;
177 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000);
179 it = stats_map.find(StatsEventSubscriber::ENCODE_KBPS);
180 ASSERT_TRUE(it != stats_map.end());
182 EXPECT_DOUBLE_EQ(it->second,
183 static_cast<double>(total_size) / duration.InMillisecondsF() * 8);
185 it = stats_map.find(StatsEventSubscriber::FIRST_EVENT_TIME_MS);
186 ASSERT_TRUE(it != stats_map.end());
190 (first_event_time - base::TimeTicks::UnixEpoch()).InMillisecondsF());
192 it = stats_map.find(StatsEventSubscriber::LAST_EVENT_TIME_MS);
193 ASSERT_TRUE(it != stats_map.end());
197 (last_event_time - base::TimeTicks::UnixEpoch()).InMillisecondsF());
200 TEST_F(StatsEventSubscriberTest, Decode) {
203 uint32 rtp_timestamp = 0;
206 base::TimeTicks start_time = sender_clock_->NowTicks();
207 for (int i = 0; i < num_frames; i++) {
208 cast_environment_->Logging()->InsertFrameEvent(receiver_clock_.NowTicks(),
209 FRAME_DECODED, VIDEO_EVENT,
213 AdvanceClocks(base::TimeDelta::FromMicroseconds(36789));
218 base::TimeTicks end_time = sender_clock_->NowTicks();
220 StatsEventSubscriber::StatsMap stats_map;
221 subscriber_->GetStatsInternal(&stats_map);
223 StatsEventSubscriber::StatsMap::iterator it =
224 stats_map.find(StatsEventSubscriber::DECODE_FPS);
225 ASSERT_TRUE(it != stats_map.end());
227 base::TimeDelta duration = end_time - start_time;
230 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000);
233 TEST_F(StatsEventSubscriberTest, PlayoutDelay) {
236 uint32 rtp_timestamp = 0;
239 int total_delay_ms = 0;
241 for (int i = 0, delay_ms = -50; i < num_frames; i++, delay_ms += 10) {
242 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms);
243 total_delay_ms += delay_ms;
246 cast_environment_->Logging()->InsertFrameEventWithDelay(
247 receiver_clock_.NowTicks(),
254 AdvanceClocks(base::TimeDelta::FromMicroseconds(37890));
259 StatsEventSubscriber::StatsMap stats_map;
260 subscriber_->GetStatsInternal(&stats_map);
262 StatsEventSubscriber::StatsMap::iterator it =
263 stats_map.find(StatsEventSubscriber::AVG_PLAYOUT_DELAY_MS);
264 ASSERT_TRUE(it != stats_map.end());
267 it->second, static_cast<double>(total_delay_ms) / num_frames);
269 it = stats_map.find(StatsEventSubscriber::NUM_FRAMES_LATE);
270 ASSERT_TRUE(it != stats_map.end());
272 EXPECT_DOUBLE_EQ(it->second, late_frames);
275 TEST_F(StatsEventSubscriberTest, E2ELatency) {
278 uint32 rtp_timestamp = 0;
281 base::TimeDelta total_latency;
282 for (int i = 0; i < num_frames; i++) {
283 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
289 int latency_micros = 100000 + base::RandInt(-5000, 50000);
290 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros);
291 AdvanceClocks(latency);
293 int delay_micros = base::RandInt(-50000, 50000);
294 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_micros);
295 total_latency += latency + delay;
297 cast_environment_->Logging()->InsertFrameEventWithDelay(
298 receiver_clock_.NowTicks(),
309 StatsEventSubscriber::StatsMap stats_map;
310 subscriber_->GetStatsInternal(&stats_map);
312 StatsEventSubscriber::StatsMap::iterator it =
313 stats_map.find(StatsEventSubscriber::AVG_E2E_LATENCY_MS);
314 ASSERT_TRUE(it != stats_map.end());
317 it->second, total_latency.InMillisecondsF() / num_frames);
320 TEST_F(StatsEventSubscriberTest, Packets) {
323 uint32 rtp_timestamp = 0;
324 int num_packets = 10;
325 int num_latency_recorded_packets = 0;
326 base::TimeTicks start_time = sender_clock_->NowTicks();
328 int retransmit_total_size = 0;
329 base::TimeDelta total_latency;
330 int num_packets_transmitted = 0;
331 int num_packets_retransmitted = 0;
332 int num_packets_rtx_rejected = 0;
333 // Every 2nd packet will be retransmitted once.
334 // Every 4th packet will be retransmitted twice.
335 // Every 8th packet will be retransmitted 3 times + 1 rejected retransmission.
336 for (int i = 0; i < num_packets; i++) {
337 int size = 1000 + base::RandInt(-100, 100);
340 cast_environment_->Logging()->InsertPacketEvent(sender_clock_->NowTicks(),
341 PACKET_SENT_TO_NETWORK,
348 num_packets_transmitted++;
350 int latency_micros = 20000 + base::RandInt(-10000, 10000);
351 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros);
352 // Latency is only recorded for packets that aren't retransmitted.
354 total_latency += latency;
355 num_latency_recorded_packets++;
358 AdvanceClocks(latency);
360 base::TimeTicks received_time = receiver_clock_.NowTicks();
363 AdvanceClocks(base::TimeDelta::FromMicroseconds(12345));
365 cast_environment_->Logging()->InsertPacketEvent(
366 receiver_clock_.NowTicks(),
367 PACKET_RETRANSMITTED,
374 retransmit_total_size += size;
375 num_packets_transmitted++;
376 num_packets_retransmitted++;
380 AdvanceClocks(base::TimeDelta::FromMicroseconds(13456));
382 cast_environment_->Logging()->InsertPacketEvent(
383 receiver_clock_.NowTicks(),
384 PACKET_RETRANSMITTED,
391 retransmit_total_size += size;
392 num_packets_transmitted++;
393 num_packets_retransmitted++;
397 AdvanceClocks(base::TimeDelta::FromMicroseconds(14567));
399 cast_environment_->Logging()->InsertPacketEvent(
400 receiver_clock_.NowTicks(),
401 PACKET_RETRANSMITTED,
408 cast_environment_->Logging()->InsertPacketEvent(
409 receiver_clock_.NowTicks(),
417 retransmit_total_size += size;
418 num_packets_transmitted++;
419 num_packets_retransmitted++;
420 num_packets_rtx_rejected++;
423 cast_environment_->Logging()->InsertPacketEvent(received_time,
433 base::TimeTicks end_time = sender_clock_->NowTicks();
434 base::TimeDelta duration = end_time - start_time;
436 StatsEventSubscriber::StatsMap stats_map;
437 subscriber_->GetStatsInternal(&stats_map);
439 // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS,
440 // and PACKET_LOSS_FRACTION.
441 StatsEventSubscriber::StatsMap::iterator it =
442 stats_map.find(StatsEventSubscriber::AVG_NETWORK_LATENCY_MS);
443 ASSERT_TRUE(it != stats_map.end());
447 total_latency.InMillisecondsF() / num_latency_recorded_packets);
449 it = stats_map.find(StatsEventSubscriber::TRANSMISSION_KBPS);
450 ASSERT_TRUE(it != stats_map.end());
452 EXPECT_DOUBLE_EQ(it->second,
453 static_cast<double>(total_size) / duration.InMillisecondsF() * 8);
455 it = stats_map.find(StatsEventSubscriber::RETRANSMISSION_KBPS);
456 ASSERT_TRUE(it != stats_map.end());
458 EXPECT_DOUBLE_EQ(it->second,
459 static_cast<double>(retransmit_total_size) /
460 duration.InMillisecondsF() * 8);
462 it = stats_map.find(StatsEventSubscriber::PACKET_LOSS_FRACTION);
463 ASSERT_TRUE(it != stats_map.end());
467 static_cast<double>(num_packets_retransmitted) / num_packets_transmitted);
469 it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_SENT);
470 ASSERT_TRUE(it != stats_map.end());
472 EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets));
474 it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_RETRANSMITTED);
475 ASSERT_TRUE(it != stats_map.end());
477 EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets_retransmitted));
479 it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_RTX_REJECTED);
480 ASSERT_TRUE(it != stats_map.end());
482 EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets_rtx_rejected));