OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/memory/ref_counted.h" | 5 #include "base/memory/ref_counted.h" |
6 #include "base/memory/scoped_ptr.h" | 6 #include "base/memory/scoped_ptr.h" |
| 7 #include "base/rand_util.h" |
7 #include "base/test/simple_test_tick_clock.h" | 8 #include "base/test/simple_test_tick_clock.h" |
8 #include "base/time/tick_clock.h" | 9 #include "base/time/tick_clock.h" |
9 #include "media/cast/cast_environment.h" | 10 #include "media/cast/cast_environment.h" |
10 #include "media/cast/logging/logging_defines.h" | 11 #include "media/cast/logging/logging_defines.h" |
11 #include "media/cast/logging/stats_event_subscriber.h" | 12 #include "media/cast/logging/stats_event_subscriber.h" |
| 13 #include "media/cast/test/fake_receiver_time_offset_estimator.h" |
12 #include "media/cast/test/fake_single_thread_task_runner.h" | 14 #include "media/cast/test/fake_single_thread_task_runner.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
14 | 16 |
| 17 namespace { |
| 18 const int kReceiverOffsetSecs = 100; |
| 19 } |
| 20 |
15 namespace media { | 21 namespace media { |
16 namespace cast { | 22 namespace cast { |
17 | 23 |
18 class StatsEventSubscriberTest : public ::testing::Test { | 24 class StatsEventSubscriberTest : public ::testing::Test { |
19 protected: | 25 protected: |
20 StatsEventSubscriberTest() | 26 StatsEventSubscriberTest() |
21 : testing_clock_(new base::SimpleTestTickClock()), | 27 : sender_clock_(new base::SimpleTestTickClock()), |
22 task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)), | 28 task_runner_(new test::FakeSingleThreadTaskRunner(sender_clock_)), |
23 cast_environment_(new CastEnvironment( | 29 cast_environment_(new CastEnvironment( |
24 scoped_ptr<base::TickClock>(testing_clock_).Pass(), | 30 scoped_ptr<base::TickClock>(sender_clock_).Pass(), |
25 task_runner_, | 31 task_runner_, |
26 task_runner_, | 32 task_runner_, |
27 task_runner_)) {} | 33 task_runner_)), |
| 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_); |
| 39 } |
28 | 40 |
29 virtual ~StatsEventSubscriberTest() { | 41 virtual ~StatsEventSubscriberTest() { |
30 if (subscriber_.get()) | 42 if (subscriber_.get()) |
31 cast_environment_->Logging()->RemoveRawEventSubscriber(subscriber_.get()); | 43 cast_environment_->Logging()->RemoveRawEventSubscriber(subscriber_.get()); |
| 44 cast_environment_->Logging()->RemoveRawEventSubscriber( |
| 45 &fake_offset_estimator_); |
| 46 } |
| 47 |
| 48 void AdvanceClocks(base::TimeDelta delta) { |
| 49 sender_clock_->Advance(delta); |
| 50 receiver_clock_.Advance(delta); |
32 } | 51 } |
33 | 52 |
34 void Init(EventMediaType event_media_type) { | 53 void Init(EventMediaType event_media_type) { |
35 DCHECK(!subscriber_.get()); | 54 DCHECK(!subscriber_.get()); |
36 subscriber_.reset(new StatsEventSubscriber(event_media_type)); | 55 subscriber_.reset(new StatsEventSubscriber( |
| 56 event_media_type, cast_environment_->Clock(), &fake_offset_estimator_)); |
37 cast_environment_->Logging()->AddRawEventSubscriber(subscriber_.get()); | 57 cast_environment_->Logging()->AddRawEventSubscriber(subscriber_.get()); |
38 } | 58 } |
39 | 59 |
40 base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment. | 60 base::SimpleTestTickClock* sender_clock_; // Owned by CastEnvironment. |
| 61 base::SimpleTestTickClock receiver_clock_; |
41 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; | 62 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; |
42 scoped_refptr<CastEnvironment> cast_environment_; | 63 scoped_refptr<CastEnvironment> cast_environment_; |
| 64 test::FakeReceiverTimeOffsetEstimator fake_offset_estimator_; |
43 scoped_ptr<StatsEventSubscriber> subscriber_; | 65 scoped_ptr<StatsEventSubscriber> subscriber_; |
44 }; | 66 }; |
45 | 67 |
46 TEST_F(StatsEventSubscriberTest, FrameStats) { | 68 TEST_F(StatsEventSubscriberTest, Capture) { |
47 Init(VIDEO_EVENT); | 69 Init(VIDEO_EVENT); |
48 uint32 rtp_timestamp = 0; | 70 |
49 uint32 frame_id = 0; | 71 uint32 rtp_timestamp = 0; |
50 int num_frames = 10; | 72 uint32 frame_id = 0; |
51 int frame_size = 123; | 73 int num_frames = 10; |
52 int delay_base_ms = 10; | 74 base::TimeTicks start_time = sender_clock_->NowTicks(); |
53 int target_bitrate = 1234; | 75 for (int i = 0; i < num_frames; i++) { |
54 base::TimeTicks now; | 76 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(), |
55 for (int i = 0; i < num_frames; i++) { | 77 kVideoFrameCaptured, |
56 now = testing_clock_->NowTicks(); | 78 rtp_timestamp, |
57 cast_environment_->Logging()->InsertFrameEvent( | 79 frame_id); |
58 now, kVideoFrameReceived, rtp_timestamp, frame_id); | 80 |
59 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); | 81 AdvanceClocks(base::TimeDelta::FromMicroseconds(34567)); |
60 | 82 rtp_timestamp += 90; |
| 83 frame_id++; |
| 84 } |
| 85 |
| 86 base::TimeTicks end_time = sender_clock_->NowTicks(); |
| 87 |
| 88 StatsEventSubscriber::StatsMap stats_map; |
| 89 subscriber_->GetStatsInternal(&stats_map); |
| 90 |
| 91 StatsEventSubscriber::StatsMap::iterator it = |
| 92 stats_map.find(StatsEventSubscriber::CAPTURE_FPS); |
| 93 ASSERT_NE(it, stats_map.end()); |
| 94 |
| 95 base::TimeDelta duration = end_time - start_time; |
| 96 EXPECT_DOUBLE_EQ( |
| 97 it->second, |
| 98 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000); |
| 99 } |
| 100 |
| 101 TEST_F(StatsEventSubscriberTest, Encode) { |
| 102 Init(VIDEO_EVENT); |
| 103 |
| 104 uint32 rtp_timestamp = 0; |
| 105 uint32 frame_id = 0; |
| 106 int num_frames = 10; |
| 107 base::TimeTicks start_time = sender_clock_->NowTicks(); |
| 108 int total_size = 0; |
| 109 for (int i = 0; i < num_frames; i++) { |
| 110 int size = 1000 + base::RandInt(-100, 100); |
| 111 total_size += size; |
61 cast_environment_->Logging()->InsertEncodedFrameEvent( | 112 cast_environment_->Logging()->InsertEncodedFrameEvent( |
62 now, kVideoFrameEncoded, rtp_timestamp, i, frame_size, true, | 113 sender_clock_->NowTicks(), |
63 target_bitrate); | 114 kVideoFrameEncoded, |
64 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); | 115 rtp_timestamp, |
65 | 116 frame_id, |
| 117 size, |
| 118 true, |
| 119 5678); |
| 120 |
| 121 AdvanceClocks(base::TimeDelta::FromMicroseconds(35678)); |
| 122 rtp_timestamp += 90; |
| 123 frame_id++; |
| 124 } |
| 125 |
| 126 base::TimeTicks end_time = sender_clock_->NowTicks(); |
| 127 |
| 128 StatsEventSubscriber::StatsMap stats_map; |
| 129 subscriber_->GetStatsInternal(&stats_map); |
| 130 |
| 131 StatsEventSubscriber::StatsMap::iterator it = |
| 132 stats_map.find(StatsEventSubscriber::ENCODE_FPS); |
| 133 ASSERT_NE(it, stats_map.end()); |
| 134 |
| 135 base::TimeDelta duration = end_time - start_time; |
| 136 EXPECT_DOUBLE_EQ( |
| 137 it->second, |
| 138 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000); |
| 139 |
| 140 it = stats_map.find(StatsEventSubscriber::ENCODE_KBPS); |
| 141 ASSERT_NE(it, stats_map.end()); |
| 142 |
| 143 EXPECT_DOUBLE_EQ(it->second, |
| 144 static_cast<double>(total_size) / duration.InMillisecondsF() * 8); |
| 145 } |
| 146 |
| 147 TEST_F(StatsEventSubscriberTest, Decode) { |
| 148 Init(VIDEO_EVENT); |
| 149 |
| 150 uint32 rtp_timestamp = 0; |
| 151 uint32 frame_id = 0; |
| 152 int num_frames = 10; |
| 153 base::TimeTicks start_time = sender_clock_->NowTicks(); |
| 154 for (int i = 0; i < num_frames; i++) { |
| 155 cast_environment_->Logging()->InsertFrameEvent(receiver_clock_.NowTicks(), |
| 156 kVideoFrameDecoded, |
| 157 rtp_timestamp, |
| 158 frame_id); |
| 159 |
| 160 AdvanceClocks(base::TimeDelta::FromMicroseconds(36789)); |
| 161 rtp_timestamp += 90; |
| 162 frame_id++; |
| 163 } |
| 164 |
| 165 base::TimeTicks end_time = sender_clock_->NowTicks(); |
| 166 |
| 167 StatsEventSubscriber::StatsMap stats_map; |
| 168 subscriber_->GetStatsInternal(&stats_map); |
| 169 |
| 170 StatsEventSubscriber::StatsMap::iterator it = |
| 171 stats_map.find(StatsEventSubscriber::DECODE_FPS); |
| 172 ASSERT_NE(it, stats_map.end()); |
| 173 |
| 174 base::TimeDelta duration = end_time - start_time; |
| 175 EXPECT_DOUBLE_EQ( |
| 176 it->second, |
| 177 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000); |
| 178 } |
| 179 |
| 180 TEST_F(StatsEventSubscriberTest, PlayoutDelay) { |
| 181 Init(VIDEO_EVENT); |
| 182 |
| 183 uint32 rtp_timestamp = 0; |
| 184 uint32 frame_id = 0; |
| 185 int num_frames = 10; |
| 186 int total_delay_ms = 0; |
| 187 for (int i = 0; i < num_frames; i++) { |
| 188 int delay_ms = base::RandInt(-50, 50); |
| 189 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms); |
| 190 total_delay_ms += delay_ms; |
66 cast_environment_->Logging()->InsertFrameEventWithDelay( | 191 cast_environment_->Logging()->InsertFrameEventWithDelay( |
67 now, | 192 receiver_clock_.NowTicks(), |
68 kVideoRenderDelay, | 193 kVideoRenderDelay, |
69 rtp_timestamp, | 194 rtp_timestamp, |
70 i, | 195 frame_id, |
71 base::TimeDelta::FromMilliseconds(i * delay_base_ms)); | 196 delay); |
72 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); | 197 |
73 | 198 AdvanceClocks(base::TimeDelta::FromMicroseconds(37890)); |
74 rtp_timestamp += 90; | 199 rtp_timestamp += 90; |
75 } | 200 frame_id++; |
76 | 201 } |
77 // Verify stats. | 202 |
78 FrameStatsMap frame_stats; | 203 StatsEventSubscriber::StatsMap stats_map; |
79 subscriber_->GetFrameStats(&frame_stats); | 204 subscriber_->GetStatsInternal(&stats_map); |
80 | 205 |
81 // Size of stats equals the number of events. | 206 StatsEventSubscriber::StatsMap::iterator it = |
82 EXPECT_EQ(3u, frame_stats.size()); | 207 stats_map.find(StatsEventSubscriber::AVG_PLAYOUT_DELAY_MS); |
83 FrameStatsMap::const_iterator it = frame_stats.find(kVideoFrameReceived); | 208 ASSERT_NE(it, stats_map.end()); |
84 ASSERT_TRUE(it != frame_stats.end()); | 209 |
85 EXPECT_EQ(num_frames, it->second.event_counter); | 210 EXPECT_DOUBLE_EQ( |
86 | 211 it->second, static_cast<double>(total_delay_ms) / num_frames); |
87 it = frame_stats.find(kVideoFrameEncoded); | 212 } |
88 ASSERT_TRUE(it != frame_stats.end()); | 213 |
89 | 214 TEST_F(StatsEventSubscriberTest, E2ELatency) { |
90 EXPECT_EQ(num_frames * frame_size, static_cast<int>(it->second.sum_size)); | 215 Init(VIDEO_EVENT); |
91 | 216 |
92 it = frame_stats.find(kVideoRenderDelay); | 217 uint32 rtp_timestamp = 0; |
93 ASSERT_TRUE(it != frame_stats.end()); | 218 uint32 frame_id = 0; |
94 | 219 int num_frames = 10; |
95 EXPECT_EQ(0, it->second.min_delay.InMilliseconds()); | 220 base::TimeDelta total_latency; |
96 EXPECT_EQ((num_frames - 1) * delay_base_ms, | 221 for (int i = 0; i < num_frames; i++) { |
97 it->second.max_delay.InMilliseconds()); | 222 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(), |
98 EXPECT_EQ((num_frames - 1) * num_frames / 2 * delay_base_ms, | 223 kVideoFrameCaptured, |
99 it->second.sum_delay.InMilliseconds()); | 224 rtp_timestamp, |
100 } | 225 frame_id); |
101 | 226 |
102 TEST_F(StatsEventSubscriberTest, PacketStats) { | 227 int latency_micros = 100000 + base::RandInt(-5000, 50000); |
103 Init(AUDIO_EVENT); | 228 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros); |
104 uint32 rtp_timestamp = 0; | 229 AdvanceClocks(latency); |
105 uint32 frame_id = 0; | 230 |
| 231 int delay_micros = base::RandInt(-50000, 50000); |
| 232 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_micros); |
| 233 total_latency += latency + delay; |
| 234 |
| 235 cast_environment_->Logging()->InsertFrameEventWithDelay( |
| 236 receiver_clock_.NowTicks(), |
| 237 kVideoRenderDelay, |
| 238 rtp_timestamp, |
| 239 frame_id, |
| 240 delay); |
| 241 |
| 242 rtp_timestamp += 90; |
| 243 frame_id++; |
| 244 } |
| 245 |
| 246 StatsEventSubscriber::StatsMap stats_map; |
| 247 subscriber_->GetStatsInternal(&stats_map); |
| 248 |
| 249 StatsEventSubscriber::StatsMap::iterator it = |
| 250 stats_map.find(StatsEventSubscriber::AVG_E2E_LATENCY_MS); |
| 251 ASSERT_NE(it, stats_map.end()); |
| 252 |
| 253 EXPECT_DOUBLE_EQ( |
| 254 it->second, total_latency.InMillisecondsF() / num_frames); |
| 255 } |
| 256 |
| 257 TEST_F(StatsEventSubscriberTest, Packets) { |
| 258 Init(VIDEO_EVENT); |
| 259 |
| 260 uint32 rtp_timestamp = 0; |
106 int num_packets = 10; | 261 int num_packets = 10; |
107 int packet_size = 123; | 262 int num_latency_recorded_packets = 0; |
108 base::TimeTicks first_event_time = testing_clock_->NowTicks(); | 263 base::TimeTicks start_time = sender_clock_->NowTicks(); |
109 base::TimeTicks now; | 264 int total_size = 0; |
| 265 int retransmit_total_size = 0; |
| 266 base::TimeDelta total_latency; |
| 267 int num_packets_sent = 0; |
| 268 int num_packets_retransmitted = 0; |
| 269 // Every 2nd packet will be retransmitted once. |
| 270 // Every 4th packet will be retransmitted twice. |
| 271 // Every 8th packet will be retransmitted 3 times. |
110 for (int i = 0; i < num_packets; i++) { | 272 for (int i = 0; i < num_packets; i++) { |
111 now = testing_clock_->NowTicks(); | 273 int size = 1000 + base::RandInt(-100, 100); |
112 cast_environment_->Logging()->InsertPacketEvent(now, | 274 total_size += size; |
113 kAudioPacketSentToPacer, | 275 |
| 276 cast_environment_->Logging()->InsertPacketEvent(sender_clock_->NowTicks(), |
| 277 kVideoPacketSentToNetwork, |
114 rtp_timestamp, | 278 rtp_timestamp, |
115 frame_id, | |
116 0, | 279 0, |
117 10, | 280 i, |
118 packet_size); | 281 num_packets - 1, |
119 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); | 282 size); |
120 } | 283 num_packets_sent++; |
121 | 284 |
122 PacketStatsMap stats_map; | 285 int latency_micros = 20000 + base::RandInt(-10000, 10000); |
123 subscriber_->GetPacketStats(&stats_map); | 286 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros); |
124 | 287 // Latency is only recorded for packets that aren't retransmitted. |
125 // Size of stats equals the number of event types. | 288 if (i % 2 != 0) { |
126 EXPECT_EQ(1u, stats_map.size()); | 289 total_latency += latency; |
127 PacketStatsMap::const_iterator it = stats_map.find(kAudioPacketSentToPacer); | 290 num_latency_recorded_packets++; |
128 ASSERT_NE(stats_map.end(), it); | 291 } |
129 | 292 |
130 EXPECT_EQ(first_event_time, it->second.first_event_time); | 293 AdvanceClocks(latency); |
131 EXPECT_EQ(now, it->second.last_event_time); | 294 |
132 EXPECT_EQ(num_packets, it->second.event_counter); | 295 base::TimeTicks received_time = receiver_clock_.NowTicks(); |
133 EXPECT_EQ(num_packets * packet_size, static_cast<int>(it->second.sum_size)); | 296 |
134 } | 297 // Retransmission 1. |
135 | 298 AdvanceClocks(base::TimeDelta::FromMicroseconds(12345)); |
136 TEST_F(StatsEventSubscriberTest, Reset) { | 299 if (i % 2 == 0) { |
137 Init(VIDEO_EVENT); | 300 cast_environment_->Logging()->InsertPacketEvent( |
138 cast_environment_->Logging()->InsertFrameEvent( | 301 receiver_clock_.NowTicks(), |
139 testing_clock_->NowTicks(), kVideoFrameReceived, 0, 0); | 302 kVideoPacketRetransmitted, |
140 | 303 rtp_timestamp, |
141 FrameStatsMap frame_stats; | 304 0, |
142 subscriber_->GetFrameStats(&frame_stats); | 305 i, |
143 EXPECT_EQ(1u, frame_stats.size()); | 306 num_packets - 1, |
144 | 307 size); |
145 subscriber_->Reset(); | 308 retransmit_total_size += size; |
146 subscriber_->GetFrameStats(&frame_stats); | 309 num_packets_sent++; |
147 EXPECT_TRUE(frame_stats.empty()); | 310 num_packets_retransmitted++; |
| 311 } |
| 312 |
| 313 // Retransmission 2. |
| 314 AdvanceClocks(base::TimeDelta::FromMicroseconds(13456)); |
| 315 if (i % 4 == 0) { |
| 316 cast_environment_->Logging()->InsertPacketEvent( |
| 317 receiver_clock_.NowTicks(), |
| 318 kVideoPacketRetransmitted, |
| 319 rtp_timestamp, |
| 320 0, |
| 321 i, |
| 322 num_packets - 1, |
| 323 size); |
| 324 retransmit_total_size += size; |
| 325 num_packets_sent++; |
| 326 num_packets_retransmitted++; |
| 327 } |
| 328 |
| 329 // Retransmission 3. |
| 330 AdvanceClocks(base::TimeDelta::FromMicroseconds(14567)); |
| 331 if (i % 8 == 0) { |
| 332 cast_environment_->Logging()->InsertPacketEvent( |
| 333 receiver_clock_.NowTicks(), |
| 334 kVideoPacketRetransmitted, |
| 335 rtp_timestamp, |
| 336 0, |
| 337 i, |
| 338 num_packets - 1, |
| 339 size); |
| 340 retransmit_total_size += size; |
| 341 num_packets_sent++; |
| 342 num_packets_retransmitted++; |
| 343 } |
| 344 |
| 345 cast_environment_->Logging()->InsertPacketEvent(received_time, |
| 346 kVideoPacketReceived, |
| 347 rtp_timestamp, |
| 348 0, |
| 349 i, |
| 350 num_packets - 1, |
| 351 size); |
| 352 } |
| 353 |
| 354 base::TimeTicks end_time = sender_clock_->NowTicks(); |
| 355 base::TimeDelta duration = end_time - start_time; |
| 356 |
| 357 StatsEventSubscriber::StatsMap stats_map; |
| 358 subscriber_->GetStatsInternal(&stats_map); |
| 359 |
| 360 // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS, |
| 361 // and PACKET_LOSS_FRACTION. |
| 362 StatsEventSubscriber::StatsMap::iterator it = |
| 363 stats_map.find(StatsEventSubscriber::AVG_NETWORK_LATENCY_MS); |
| 364 ASSERT_NE(it, stats_map.end()); |
| 365 |
| 366 EXPECT_DOUBLE_EQ( |
| 367 it->second, |
| 368 total_latency.InMillisecondsF() / num_latency_recorded_packets); |
| 369 |
| 370 it = stats_map.find(StatsEventSubscriber::TRANSMISSION_KBPS); |
| 371 ASSERT_NE(it, stats_map.end()); |
| 372 |
| 373 EXPECT_DOUBLE_EQ(it->second, |
| 374 static_cast<double>(total_size) / duration.InMillisecondsF() * 8); |
| 375 |
| 376 it = stats_map.find(StatsEventSubscriber::RETRANSMISSION_KBPS); |
| 377 ASSERT_NE(it, stats_map.end()); |
| 378 |
| 379 EXPECT_DOUBLE_EQ(it->second, |
| 380 static_cast<double>(retransmit_total_size) / |
| 381 duration.InMillisecondsF() * 8); |
| 382 |
| 383 it = stats_map.find(StatsEventSubscriber::PACKET_LOSS_FRACTION); |
| 384 ASSERT_NE(it, stats_map.end()); |
| 385 |
| 386 EXPECT_DOUBLE_EQ( |
| 387 it->second, |
| 388 static_cast<double>(num_packets_retransmitted) / num_packets_sent); |
148 } | 389 } |
149 | 390 |
150 } // namespace cast | 391 } // namespace cast |
151 } // namespace media | 392 } // namespace media |
OLD | NEW |