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 base::TimeTicks now; | 75 for (int i = 0; i < num_frames; i++) { |
54 for (int i = 0; i < num_frames; i++) { | 76 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(), |
55 now = testing_clock_->NowTicks(); | 77 kVideoFrameCaptured, |
56 cast_environment_->Logging()->InsertFrameEvent( | 78 rtp_timestamp, |
57 now, kVideoFrameReceived, rtp_timestamp, frame_id); | 79 frame_id); |
58 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); | 80 |
59 | 81 AdvanceClocks(base::TimeDelta::FromMicroseconds(34567)); |
| 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; |
60 cast_environment_->Logging()->InsertEncodedFrameEvent( | 112 cast_environment_->Logging()->InsertEncodedFrameEvent( |
61 now, kVideoFrameEncoded, rtp_timestamp, i, frame_size, true); | 113 sender_clock_->NowTicks(), |
62 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); | 114 kVideoFrameEncoded, |
63 | 115 rtp_timestamp, |
| 116 frame_id, |
| 117 size, |
| 118 true); |
| 119 |
| 120 AdvanceClocks(base::TimeDelta::FromMicroseconds(35678)); |
| 121 rtp_timestamp += 90; |
| 122 frame_id++; |
| 123 } |
| 124 |
| 125 base::TimeTicks end_time = sender_clock_->NowTicks(); |
| 126 |
| 127 StatsEventSubscriber::StatsMap stats_map; |
| 128 subscriber_->GetStatsInternal(&stats_map); |
| 129 |
| 130 StatsEventSubscriber::StatsMap::iterator it = |
| 131 stats_map.find(StatsEventSubscriber::ENCODE_FPS); |
| 132 ASSERT_NE(it, stats_map.end()); |
| 133 |
| 134 base::TimeDelta duration = end_time - start_time; |
| 135 EXPECT_DOUBLE_EQ( |
| 136 it->second, |
| 137 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000); |
| 138 |
| 139 it = stats_map.find(StatsEventSubscriber::ENCODE_KBPS); |
| 140 ASSERT_NE(it, stats_map.end()); |
| 141 |
| 142 EXPECT_DOUBLE_EQ(it->second, |
| 143 static_cast<double>(total_size) / duration.InMillisecondsF() * 8); |
| 144 } |
| 145 |
| 146 TEST_F(StatsEventSubscriberTest, Decode) { |
| 147 Init(VIDEO_EVENT); |
| 148 |
| 149 uint32 rtp_timestamp = 0; |
| 150 uint32 frame_id = 0; |
| 151 int num_frames = 10; |
| 152 base::TimeTicks start_time = sender_clock_->NowTicks(); |
| 153 for (int i = 0; i < num_frames; i++) { |
| 154 cast_environment_->Logging()->InsertFrameEvent(receiver_clock_.NowTicks(), |
| 155 kVideoFrameDecoded, |
| 156 rtp_timestamp, |
| 157 frame_id); |
| 158 |
| 159 AdvanceClocks(base::TimeDelta::FromMicroseconds(36789)); |
| 160 rtp_timestamp += 90; |
| 161 frame_id++; |
| 162 } |
| 163 |
| 164 base::TimeTicks end_time = sender_clock_->NowTicks(); |
| 165 |
| 166 StatsEventSubscriber::StatsMap stats_map; |
| 167 subscriber_->GetStatsInternal(&stats_map); |
| 168 |
| 169 StatsEventSubscriber::StatsMap::iterator it = |
| 170 stats_map.find(StatsEventSubscriber::DECODE_FPS); |
| 171 ASSERT_NE(it, stats_map.end()); |
| 172 |
| 173 base::TimeDelta duration = end_time - start_time; |
| 174 EXPECT_DOUBLE_EQ( |
| 175 it->second, |
| 176 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000); |
| 177 } |
| 178 |
| 179 TEST_F(StatsEventSubscriberTest, PlayoutDelay) { |
| 180 Init(VIDEO_EVENT); |
| 181 |
| 182 uint32 rtp_timestamp = 0; |
| 183 uint32 frame_id = 0; |
| 184 int num_frames = 10; |
| 185 int total_delay_ms = 0; |
| 186 for (int i = 0; i < num_frames; i++) { |
| 187 int delay_ms = base::RandInt(-50, 50); |
| 188 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms); |
| 189 total_delay_ms += delay_ms; |
64 cast_environment_->Logging()->InsertFrameEventWithDelay( | 190 cast_environment_->Logging()->InsertFrameEventWithDelay( |
65 now, | 191 receiver_clock_.NowTicks(), |
66 kVideoRenderDelay, | 192 kVideoRenderDelay, |
67 rtp_timestamp, | 193 rtp_timestamp, |
68 i, | 194 frame_id, |
69 base::TimeDelta::FromMilliseconds(i * delay_base_ms)); | 195 delay); |
70 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); | 196 |
71 | 197 AdvanceClocks(base::TimeDelta::FromMicroseconds(37890)); |
72 rtp_timestamp += 90; | 198 rtp_timestamp += 90; |
73 } | 199 frame_id++; |
74 | 200 } |
75 // Verify stats. | 201 |
76 FrameStatsMap frame_stats; | 202 StatsEventSubscriber::StatsMap stats_map; |
77 subscriber_->GetFrameStats(&frame_stats); | 203 subscriber_->GetStatsInternal(&stats_map); |
78 | 204 |
79 // Size of stats equals the number of events. | 205 StatsEventSubscriber::StatsMap::iterator it = |
80 EXPECT_EQ(3u, frame_stats.size()); | 206 stats_map.find(StatsEventSubscriber::AVG_PLAYOUT_DELAY_MS); |
81 FrameStatsMap::const_iterator it = frame_stats.find(kVideoFrameReceived); | 207 ASSERT_NE(it, stats_map.end()); |
82 ASSERT_TRUE(it != frame_stats.end()); | 208 |
83 EXPECT_EQ(num_frames, it->second.event_counter); | 209 EXPECT_DOUBLE_EQ( |
84 | 210 it->second, static_cast<double>(total_delay_ms) / num_frames); |
85 it = frame_stats.find(kVideoFrameEncoded); | 211 } |
86 ASSERT_TRUE(it != frame_stats.end()); | 212 |
87 | 213 TEST_F(StatsEventSubscriberTest, E2ELatency) { |
88 EXPECT_EQ(num_frames * frame_size, static_cast<int>(it->second.sum_size)); | 214 Init(VIDEO_EVENT); |
89 | 215 |
90 it = frame_stats.find(kVideoRenderDelay); | 216 uint32 rtp_timestamp = 0; |
91 ASSERT_TRUE(it != frame_stats.end()); | 217 uint32 frame_id = 0; |
92 | 218 int num_frames = 10; |
93 EXPECT_EQ(0, it->second.min_delay.InMilliseconds()); | 219 base::TimeDelta total_latency; |
94 EXPECT_EQ((num_frames - 1) * delay_base_ms, | 220 for (int i = 0; i < num_frames; i++) { |
95 it->second.max_delay.InMilliseconds()); | 221 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(), |
96 EXPECT_EQ((num_frames - 1) * num_frames / 2 * delay_base_ms, | 222 kVideoFrameCaptured, |
97 it->second.sum_delay.InMilliseconds()); | 223 rtp_timestamp, |
98 } | 224 frame_id); |
99 | 225 |
100 TEST_F(StatsEventSubscriberTest, PacketStats) { | 226 int latency_micros = 100000 + base::RandInt(-5000, 50000); |
101 Init(AUDIO_EVENT); | 227 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros); |
102 uint32 rtp_timestamp = 0; | 228 AdvanceClocks(latency); |
103 uint32 frame_id = 0; | 229 |
| 230 int delay_micros = base::RandInt(-50000, 50000); |
| 231 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_micros); |
| 232 total_latency += latency + delay; |
| 233 |
| 234 cast_environment_->Logging()->InsertFrameEventWithDelay( |
| 235 receiver_clock_.NowTicks(), |
| 236 kVideoRenderDelay, |
| 237 rtp_timestamp, |
| 238 frame_id, |
| 239 delay); |
| 240 |
| 241 rtp_timestamp += 90; |
| 242 frame_id++; |
| 243 } |
| 244 |
| 245 StatsEventSubscriber::StatsMap stats_map; |
| 246 subscriber_->GetStatsInternal(&stats_map); |
| 247 |
| 248 StatsEventSubscriber::StatsMap::iterator it = |
| 249 stats_map.find(StatsEventSubscriber::AVG_E2E_LATENCY_MS); |
| 250 ASSERT_NE(it, stats_map.end()); |
| 251 |
| 252 EXPECT_DOUBLE_EQ( |
| 253 it->second, total_latency.InMillisecondsF() / num_frames); |
| 254 } |
| 255 |
| 256 TEST_F(StatsEventSubscriberTest, Packets) { |
| 257 Init(VIDEO_EVENT); |
| 258 |
| 259 uint32 rtp_timestamp = 0; |
104 int num_packets = 10; | 260 int num_packets = 10; |
105 int packet_size = 123; | 261 int num_latency_recorded_packets = 0; |
106 base::TimeTicks first_event_time = testing_clock_->NowTicks(); | 262 base::TimeTicks start_time = sender_clock_->NowTicks(); |
107 base::TimeTicks now; | 263 int total_size = 0; |
| 264 int retransmit_total_size = 0; |
| 265 base::TimeDelta total_latency; |
| 266 int num_packets_sent = 0; |
| 267 int num_packets_retransmitted = 0; |
| 268 // Every 2nd packet will be retransmitted once. |
| 269 // Every 4th packet will be retransmitted twice. |
| 270 // Every 8th packet will be retransmitted 3 times. |
108 for (int i = 0; i < num_packets; i++) { | 271 for (int i = 0; i < num_packets; i++) { |
109 now = testing_clock_->NowTicks(); | 272 int size = 1000 + base::RandInt(-100, 100); |
110 cast_environment_->Logging()->InsertPacketEvent(now, | 273 total_size += size; |
111 kAudioPacketSentToPacer, | 274 |
| 275 cast_environment_->Logging()->InsertPacketEvent(sender_clock_->NowTicks(), |
| 276 kVideoPacketSentToNetwork, |
112 rtp_timestamp, | 277 rtp_timestamp, |
113 frame_id, | |
114 0, | 278 0, |
115 10, | 279 i, |
116 packet_size); | 280 num_packets - 1, |
117 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); | 281 size); |
118 } | 282 num_packets_sent++; |
119 | 283 |
120 PacketStatsMap stats_map; | 284 int latency_micros = 20000 + base::RandInt(-10000, 10000); |
121 subscriber_->GetPacketStats(&stats_map); | 285 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros); |
122 | 286 // Latency is only recorded for packets that aren't retransmitted. |
123 // Size of stats equals the number of event types. | 287 if (i % 2 != 0) { |
124 EXPECT_EQ(1u, stats_map.size()); | 288 total_latency += latency; |
125 PacketStatsMap::const_iterator it = stats_map.find(kAudioPacketSentToPacer); | 289 num_latency_recorded_packets++; |
126 ASSERT_NE(stats_map.end(), it); | 290 } |
127 | 291 |
128 EXPECT_EQ(first_event_time, it->second.first_event_time); | 292 AdvanceClocks(latency); |
129 EXPECT_EQ(now, it->second.last_event_time); | 293 |
130 EXPECT_EQ(num_packets, it->second.event_counter); | 294 base::TimeTicks received_time = receiver_clock_.NowTicks(); |
131 EXPECT_EQ(num_packets * packet_size, static_cast<int>(it->second.sum_size)); | 295 |
132 } | 296 // Retransmission 1. |
133 | 297 AdvanceClocks(base::TimeDelta::FromMicroseconds(12345)); |
134 TEST_F(StatsEventSubscriberTest, GenericStats) { | 298 if (i % 2 == 0) { |
135 Init(OTHER_EVENT); | 299 cast_environment_->Logging()->InsertPacketEvent( |
136 int num_generic_events = 10; | 300 receiver_clock_.NowTicks(), |
137 int value = 123; | 301 kVideoPacketRetransmitted, |
138 for (int i = 0; i < num_generic_events; i++) { | 302 rtp_timestamp, |
139 cast_environment_->Logging()->InsertGenericEvent( | 303 0, |
140 testing_clock_->NowTicks(), kRttMs, value); | 304 i, |
141 } | 305 num_packets - 1, |
142 | 306 size); |
143 GenericStatsMap stats_map; | 307 retransmit_total_size += size; |
144 subscriber_->GetGenericStats(&stats_map); | 308 num_packets_sent++; |
145 | 309 num_packets_retransmitted++; |
146 EXPECT_EQ(1u, stats_map.size()); | 310 } |
147 GenericStatsMap::const_iterator it = stats_map.find(kRttMs); | 311 |
148 ASSERT_NE(stats_map.end(), it); | 312 // Retransmission 2. |
149 | 313 AdvanceClocks(base::TimeDelta::FromMicroseconds(13456)); |
150 EXPECT_EQ(num_generic_events, it->second.event_counter); | 314 if (i % 4 == 0) { |
151 EXPECT_EQ(num_generic_events * value, it->second.sum); | 315 cast_environment_->Logging()->InsertPacketEvent( |
152 EXPECT_EQ(static_cast<uint64>(num_generic_events * value * value), | 316 receiver_clock_.NowTicks(), |
153 it->second.sum_squared); | 317 kVideoPacketRetransmitted, |
154 EXPECT_LE(value, it->second.min); | 318 rtp_timestamp, |
155 EXPECT_GE(value, it->second.max); | 319 0, |
156 } | 320 i, |
157 | 321 num_packets - 1, |
158 TEST_F(StatsEventSubscriberTest, Reset) { | 322 size); |
159 Init(VIDEO_EVENT); | 323 retransmit_total_size += size; |
160 cast_environment_->Logging()->InsertFrameEvent( | 324 num_packets_sent++; |
161 testing_clock_->NowTicks(), kVideoFrameReceived, 0, 0); | 325 num_packets_retransmitted++; |
162 | 326 } |
163 FrameStatsMap frame_stats; | 327 |
164 subscriber_->GetFrameStats(&frame_stats); | 328 // Retransmission 3. |
165 EXPECT_EQ(1u, frame_stats.size()); | 329 AdvanceClocks(base::TimeDelta::FromMicroseconds(14567)); |
166 | 330 if (i % 8 == 0) { |
167 subscriber_->Reset(); | 331 cast_environment_->Logging()->InsertPacketEvent( |
168 subscriber_->GetFrameStats(&frame_stats); | 332 receiver_clock_.NowTicks(), |
169 EXPECT_TRUE(frame_stats.empty()); | 333 kVideoPacketRetransmitted, |
| 334 rtp_timestamp, |
| 335 0, |
| 336 i, |
| 337 num_packets - 1, |
| 338 size); |
| 339 retransmit_total_size += size; |
| 340 num_packets_sent++; |
| 341 num_packets_retransmitted++; |
| 342 } |
| 343 |
| 344 cast_environment_->Logging()->InsertPacketEvent(received_time, |
| 345 kVideoPacketReceived, |
| 346 rtp_timestamp, |
| 347 0, |
| 348 i, |
| 349 num_packets - 1, |
| 350 size); |
| 351 } |
| 352 |
| 353 base::TimeTicks end_time = sender_clock_->NowTicks(); |
| 354 base::TimeDelta duration = end_time - start_time; |
| 355 |
| 356 StatsEventSubscriber::StatsMap stats_map; |
| 357 subscriber_->GetStatsInternal(&stats_map); |
| 358 |
| 359 // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS, |
| 360 // and PACKET_LOSS_FRACTION. |
| 361 StatsEventSubscriber::StatsMap::iterator it = |
| 362 stats_map.find(StatsEventSubscriber::AVG_NETWORK_LATENCY_MS); |
| 363 ASSERT_NE(it, stats_map.end()); |
| 364 |
| 365 EXPECT_DOUBLE_EQ( |
| 366 it->second, |
| 367 total_latency.InMillisecondsF() / num_latency_recorded_packets); |
| 368 |
| 369 it = stats_map.find(StatsEventSubscriber::TRANSMISSION_KBPS); |
| 370 ASSERT_NE(it, stats_map.end()); |
| 371 |
| 372 EXPECT_DOUBLE_EQ(it->second, |
| 373 static_cast<double>(total_size) / duration.InMillisecondsF() * 8); |
| 374 |
| 375 it = stats_map.find(StatsEventSubscriber::RETRANSMISSION_KBPS); |
| 376 ASSERT_NE(it, stats_map.end()); |
| 377 |
| 378 EXPECT_DOUBLE_EQ(it->second, |
| 379 static_cast<double>(retransmit_total_size) / |
| 380 duration.InMillisecondsF() * 8); |
| 381 |
| 382 it = stats_map.find(StatsEventSubscriber::PACKET_LOSS_FRACTION); |
| 383 ASSERT_NE(it, stats_map.end()); |
| 384 |
| 385 EXPECT_DOUBLE_EQ( |
| 386 it->second, |
| 387 static_cast<double>(num_packets_retransmitted) / num_packets_sent); |
170 } | 388 } |
171 | 389 |
172 } // namespace cast | 390 } // namespace cast |
173 } // namespace media | 391 } // namespace media |
OLD | NEW |