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 ~StatsEventSubscriberTest() override
{
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
));
135 it
= stats_map
.find(StatsEventSubscriber::AVG_CAPTURE_LATENCY_MS
);
136 ASSERT_TRUE(it
!= stats_map
.end());
138 EXPECT_DOUBLE_EQ(it
->second
, static_cast<double>(0.01));
141 TEST_F(StatsEventSubscriberTest
, Encode
) {
144 uint32 rtp_timestamp
= 0;
147 base::TimeTicks start_time
= sender_clock_
->NowTicks();
148 AdvanceClocks(base::TimeDelta::FromMicroseconds(35678));
149 base::TimeTicks first_event_time
= sender_clock_
->NowTicks();
150 base::TimeTicks last_event_time
;
152 for (int i
= 0; i
< num_frames
; i
++) {
153 int size
= 1000 + base::RandInt(-100, 100);
155 cast_environment_
->Logging()->InsertEncodedFrameEvent(
156 sender_clock_
->NowTicks(),
157 FRAME_ENCODED
, VIDEO_EVENT
,
163 last_event_time
= sender_clock_
->NowTicks();
165 AdvanceClocks(base::TimeDelta::FromMicroseconds(35678));
170 base::TimeTicks end_time
= sender_clock_
->NowTicks();
172 StatsEventSubscriber::StatsMap stats_map
;
173 subscriber_
->GetStatsInternal(&stats_map
);
175 StatsEventSubscriber::StatsMap::iterator it
=
176 stats_map
.find(StatsEventSubscriber::ENCODE_FPS
);
177 ASSERT_TRUE(it
!= stats_map
.end());
179 base::TimeDelta duration
= end_time
- start_time
;
182 static_cast<double>(num_frames
) / duration
.InMillisecondsF() * 1000);
184 it
= stats_map
.find(StatsEventSubscriber::ENCODE_KBPS
);
185 ASSERT_TRUE(it
!= stats_map
.end());
187 EXPECT_DOUBLE_EQ(it
->second
,
188 static_cast<double>(total_size
) / duration
.InMillisecondsF() * 8);
190 it
= stats_map
.find(StatsEventSubscriber::FIRST_EVENT_TIME_MS
);
191 ASSERT_TRUE(it
!= stats_map
.end());
195 (first_event_time
- base::TimeTicks::UnixEpoch()).InMillisecondsF());
197 it
= stats_map
.find(StatsEventSubscriber::LAST_EVENT_TIME_MS
);
198 ASSERT_TRUE(it
!= stats_map
.end());
202 (last_event_time
- base::TimeTicks::UnixEpoch()).InMillisecondsF());
205 TEST_F(StatsEventSubscriberTest
, Decode
) {
208 uint32 rtp_timestamp
= 0;
211 base::TimeTicks start_time
= sender_clock_
->NowTicks();
212 for (int i
= 0; i
< num_frames
; i
++) {
213 cast_environment_
->Logging()->InsertFrameEvent(receiver_clock_
.NowTicks(),
214 FRAME_DECODED
, VIDEO_EVENT
,
218 AdvanceClocks(base::TimeDelta::FromMicroseconds(36789));
223 base::TimeTicks end_time
= sender_clock_
->NowTicks();
225 StatsEventSubscriber::StatsMap stats_map
;
226 subscriber_
->GetStatsInternal(&stats_map
);
228 StatsEventSubscriber::StatsMap::iterator it
=
229 stats_map
.find(StatsEventSubscriber::DECODE_FPS
);
230 ASSERT_TRUE(it
!= stats_map
.end());
232 base::TimeDelta duration
= end_time
- start_time
;
235 static_cast<double>(num_frames
) / duration
.InMillisecondsF() * 1000);
238 TEST_F(StatsEventSubscriberTest
, PlayoutDelay
) {
241 uint32 rtp_timestamp
= 0;
245 for (int i
= 0, delay_ms
= -50; i
< num_frames
; i
++, delay_ms
+= 10) {
246 base::TimeDelta delay
= base::TimeDelta::FromMilliseconds(delay_ms
);
249 cast_environment_
->Logging()->InsertFrameEventWithDelay(
250 receiver_clock_
.NowTicks(),
257 AdvanceClocks(base::TimeDelta::FromMicroseconds(37890));
262 StatsEventSubscriber::StatsMap stats_map
;
263 subscriber_
->GetStatsInternal(&stats_map
);
265 StatsEventSubscriber::StatsMap::iterator it
= stats_map
.find(
266 StatsEventSubscriber::NUM_FRAMES_LATE
);
267 ASSERT_TRUE(it
!= stats_map
.end());
269 EXPECT_DOUBLE_EQ(it
->second
, late_frames
);
272 TEST_F(StatsEventSubscriberTest
, E2ELatency
) {
275 uint32 rtp_timestamp
= 0;
278 base::TimeDelta total_latency
;
279 for (int i
= 0; i
< num_frames
; i
++) {
280 cast_environment_
->Logging()->InsertFrameEvent(sender_clock_
->NowTicks(),
286 int latency_micros
= 100000 + base::RandInt(-5000, 50000);
287 base::TimeDelta latency
= base::TimeDelta::FromMicroseconds(latency_micros
);
288 AdvanceClocks(latency
);
290 int delay_micros
= base::RandInt(-50000, 50000);
291 base::TimeDelta delay
= base::TimeDelta::FromMilliseconds(delay_micros
);
292 total_latency
+= latency
;
294 cast_environment_
->Logging()->InsertFrameEventWithDelay(
295 receiver_clock_
.NowTicks(),
306 StatsEventSubscriber::StatsMap stats_map
;
307 subscriber_
->GetStatsInternal(&stats_map
);
309 StatsEventSubscriber::StatsMap::iterator it
=
310 stats_map
.find(StatsEventSubscriber::AVG_E2E_LATENCY_MS
);
311 ASSERT_TRUE(it
!= stats_map
.end());
314 it
->second
, total_latency
.InMillisecondsF() / num_frames
);
317 TEST_F(StatsEventSubscriberTest
, Packets
) {
320 uint32 rtp_timestamp
= 0;
321 int num_packets
= 10;
322 int num_latency_recorded_packets
= 0;
323 base::TimeTicks start_time
= sender_clock_
->NowTicks();
325 int retransmit_total_size
= 0;
326 base::TimeDelta total_network_latency
;
327 base::TimeDelta total_queueing_latency
;
328 base::TimeDelta total_packet_latency
;
329 int num_packets_transmitted
= 0;
330 int num_packets_received
= 0;
331 int num_packets_retransmitted
= 0;
332 int num_packets_rtx_rejected
= 0;
334 base::TimeTicks sender_encoded_time
= sender_clock_
->NowTicks();
335 base::TimeTicks receiver_encoded_time
= receiver_clock_
.NowTicks();
336 cast_environment_
->Logging()->InsertFrameEvent(sender_encoded_time
,
342 // Every 2nd packet will be retransmitted once.
343 // Every 4th packet will be retransmitted twice.
344 // Every 8th packet will be retransmitted 3 times + 1 rejected retransmission.
345 for (int i
= 0; i
< num_packets
; i
++) {
346 int size
= 1000 + base::RandInt(-100, 100);
349 cast_environment_
->Logging()->InsertPacketEvent(sender_clock_
->NowTicks(),
350 PACKET_SENT_TO_NETWORK
,
357 num_packets_transmitted
++;
358 total_queueing_latency
+= sender_clock_
->NowTicks() - sender_encoded_time
;
360 int latency_micros
= 20000 + base::RandInt(-10000, 10000);
361 base::TimeDelta latency
= base::TimeDelta::FromMicroseconds(latency_micros
);
362 // Latency is only recorded for packets that aren't retransmitted.
364 total_network_latency
+= latency
;
365 total_packet_latency
+=
366 receiver_clock_
.NowTicks() - receiver_encoded_time
+ latency
;
367 num_latency_recorded_packets
++;
370 AdvanceClocks(latency
);
372 base::TimeTicks received_time
= receiver_clock_
.NowTicks();
375 AdvanceClocks(base::TimeDelta::FromMicroseconds(12345));
377 cast_environment_
->Logging()->InsertPacketEvent(
378 receiver_clock_
.NowTicks(),
379 PACKET_RETRANSMITTED
,
386 retransmit_total_size
+= size
;
387 num_packets_transmitted
++;
388 num_packets_retransmitted
++;
392 AdvanceClocks(base::TimeDelta::FromMicroseconds(13456));
394 cast_environment_
->Logging()->InsertPacketEvent(
395 receiver_clock_
.NowTicks(),
396 PACKET_RETRANSMITTED
,
403 retransmit_total_size
+= size
;
404 num_packets_transmitted
++;
405 num_packets_retransmitted
++;
409 AdvanceClocks(base::TimeDelta::FromMicroseconds(14567));
411 cast_environment_
->Logging()->InsertPacketEvent(
412 receiver_clock_
.NowTicks(),
413 PACKET_RETRANSMITTED
,
420 cast_environment_
->Logging()->InsertPacketEvent(
421 receiver_clock_
.NowTicks(),
429 retransmit_total_size
+= size
;
430 num_packets_transmitted
++;
431 num_packets_retransmitted
++;
432 num_packets_rtx_rejected
++;
435 cast_environment_
->Logging()->InsertPacketEvent(received_time
,
443 num_packets_received
++;
446 base::TimeTicks end_time
= sender_clock_
->NowTicks();
447 base::TimeDelta duration
= end_time
- start_time
;
449 StatsEventSubscriber::StatsMap stats_map
;
450 subscriber_
->GetStatsInternal(&stats_map
);
452 // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS.
453 StatsEventSubscriber::StatsMap::iterator it
=
454 stats_map
.find(StatsEventSubscriber::AVG_NETWORK_LATENCY_MS
);
455 ASSERT_TRUE(it
!= stats_map
.end());
459 total_network_latency
.InMillisecondsF() / num_latency_recorded_packets
);
461 it
= stats_map
.find(StatsEventSubscriber::AVG_QUEUEING_LATENCY_MS
);
462 ASSERT_TRUE(it
!= stats_map
.end());
466 total_queueing_latency
.InMillisecondsF() / num_packets
);
468 it
= stats_map
.find(StatsEventSubscriber::AVG_PACKET_LATENCY_MS
);
469 ASSERT_TRUE(it
!= stats_map
.end());
473 total_packet_latency
.InMillisecondsF() / num_latency_recorded_packets
);
475 it
= stats_map
.find(StatsEventSubscriber::TRANSMISSION_KBPS
);
476 ASSERT_TRUE(it
!= stats_map
.end());
478 EXPECT_DOUBLE_EQ(it
->second
,
479 static_cast<double>(total_size
) / duration
.InMillisecondsF() * 8);
481 it
= stats_map
.find(StatsEventSubscriber::RETRANSMISSION_KBPS
);
482 ASSERT_TRUE(it
!= stats_map
.end());
484 EXPECT_DOUBLE_EQ(it
->second
,
485 static_cast<double>(retransmit_total_size
) /
486 duration
.InMillisecondsF() * 8);
488 it
= stats_map
.find(StatsEventSubscriber::NUM_PACKETS_SENT
);
489 ASSERT_TRUE(it
!= stats_map
.end());
491 EXPECT_DOUBLE_EQ(it
->second
, static_cast<double>(num_packets
));
493 it
= stats_map
.find(StatsEventSubscriber::NUM_PACKETS_RECEIVED
);
494 ASSERT_TRUE(it
!= stats_map
.end());
496 EXPECT_DOUBLE_EQ(it
->second
, static_cast<double>(num_packets_received
));
498 it
= stats_map
.find(StatsEventSubscriber::NUM_PACKETS_RETRANSMITTED
);
499 ASSERT_TRUE(it
!= stats_map
.end());
501 EXPECT_DOUBLE_EQ(it
->second
, static_cast<double>(num_packets_retransmitted
));
503 it
= stats_map
.find(StatsEventSubscriber::NUM_PACKETS_RTX_REJECTED
);
504 ASSERT_TRUE(it
!= stats_map
.end());
506 EXPECT_DOUBLE_EQ(it
->second
, static_cast<double>(num_packets_rtx_rejected
));
509 bool CheckHistogramHasValue(base::ListValue
* values
,
510 const std::string
& bucket
, int expected_count
) {
511 for (size_t i
= 0; i
< values
->GetSize(); ++i
) {
512 const base::DictionaryValue
* dict
= NULL
;
513 values
->GetDictionary(i
, &dict
);
514 if (!dict
->HasKey(bucket
))
516 int bucket_count
= 0;
517 if (!dict
->GetInteger(bucket
, &bucket_count
))
519 return bucket_count
== expected_count
;
524 TEST_F(StatsEventSubscriberTest
, Histograms
) {
526 AdvanceClocks(base::TimeDelta::FromMilliseconds(123));
528 uint32 rtp_timestamp
= 123;
531 // 10 Frames with capture latency in the bucket of "10-14"ms.
532 // 10 Frames with encode time in the bucket of "15-19"ms.
533 for (int i
= 0; i
< 10; ++i
) {
536 cast_environment_
->Logging()->InsertFrameEvent(sender_clock_
->NowTicks(),
541 AdvanceClocks(base::TimeDelta::FromMilliseconds(10));
542 cast_environment_
->Logging()->InsertFrameEvent(sender_clock_
->NowTicks(),
547 AdvanceClocks(base::TimeDelta::FromMilliseconds(15));
548 cast_environment_
->Logging()->InsertEncodedFrameEvent(
549 sender_clock_
->NowTicks(),
559 // Send 3 packets for the last frame.
560 // Queueing latencies are 100ms, 200ms and 300ms.
561 for (int i
= 0; i
< 3; ++i
) {
562 AdvanceClocks(base::TimeDelta::FromMilliseconds(100));
563 cast_environment_
->Logging()->InsertPacketEvent(sender_clock_
->NowTicks(),
564 PACKET_SENT_TO_NETWORK
,
573 // Receive 3 packets for the last frame.
574 // Network latencies are 100ms, 200ms and 300ms.
575 // Packet latencies are 400ms.
576 AdvanceClocks(base::TimeDelta::FromMilliseconds(100));
577 for (int i
= 0; i
< 3; ++i
) {
578 cast_environment_
->Logging()->InsertPacketEvent(receiver_clock_
.NowTicks(),
588 cast_environment_
->Logging()->InsertFrameEventWithDelay(
589 receiver_clock_
.NowTicks(),
594 base::TimeDelta::FromMilliseconds(100));
596 StatsEventSubscriber::SimpleHistogram
* histogram
;
597 scoped_ptr
<base::ListValue
> values
;
599 histogram
= subscriber_
->GetHistogramForTesting(
600 StatsEventSubscriber::CAPTURE_LATENCY_MS_HISTO
);
601 ASSERT_TRUE(histogram
);
602 values
= histogram
->GetHistogram().Pass();
603 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "10-14", 10));
605 histogram
= subscriber_
->GetHistogramForTesting(
606 StatsEventSubscriber::ENCODE_TIME_MS_HISTO
);
607 ASSERT_TRUE(histogram
);
608 values
= histogram
->GetHistogram().Pass();
609 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "15-19", 10));
611 histogram
= subscriber_
->GetHistogramForTesting(
612 StatsEventSubscriber::QUEUEING_LATENCY_MS_HISTO
);
613 ASSERT_TRUE(histogram
);
614 values
= histogram
->GetHistogram().Pass();
615 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "100-119", 1));
616 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "200-219", 1));
617 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "300-319", 1));
619 histogram
= subscriber_
->GetHistogramForTesting(
620 StatsEventSubscriber::NETWORK_LATENCY_MS_HISTO
);
621 ASSERT_TRUE(histogram
);
622 values
= histogram
->GetHistogram().Pass();
623 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "100-119", 1));
624 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "200-219", 1));
625 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "300-319", 1));
627 histogram
= subscriber_
->GetHistogramForTesting(
628 StatsEventSubscriber::PACKET_LATENCY_MS_HISTO
);
629 ASSERT_TRUE(histogram
);
630 values
= histogram
->GetHistogram().Pass();
631 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "400-419", 3));
633 histogram
= subscriber_
->GetHistogramForTesting(
634 StatsEventSubscriber::LATE_FRAME_MS_HISTO
);
635 ASSERT_TRUE(histogram
);
636 values
= histogram
->GetHistogram().Pass();
637 EXPECT_TRUE(CheckHistogramHasValue(values
.get(), "100-119", 1));