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 "media/cast/logging/stats_event_subscriber.h" | 5 #include "media/cast/logging/stats_event_subscriber.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/values.h" | 8 #include "base/values.h" |
9 | 9 |
10 #define STAT_ENUM_TO_STRING(enum) \ | 10 #define STAT_ENUM_TO_STRING(enum) \ |
11 case enum: \ | 11 case enum: \ |
12 return #enum | 12 return #enum |
13 | 13 |
14 namespace media { | 14 namespace media { |
15 namespace cast { | 15 namespace cast { |
16 | 16 |
17 namespace { | 17 namespace { |
18 | 18 |
19 using media::cast::CastLoggingEvent; | 19 using media::cast::CastLoggingEvent; |
20 using media::cast::EventMediaType; | 20 using media::cast::EventMediaType; |
21 | 21 |
22 const size_t kMaxFrameEventTimeMapSize = 100; | |
23 const size_t kMaxPacketEventTimeMapSize = 1000; | 22 const size_t kMaxPacketEventTimeMapSize = 1000; |
24 | 23 |
25 bool IsReceiverEvent(CastLoggingEvent event) { | 24 bool IsReceiverEvent(CastLoggingEvent event) { |
26 return event == FRAME_DECODED | 25 return event == FRAME_DECODED |
27 || event == FRAME_PLAYOUT | 26 || event == FRAME_PLAYOUT |
28 || event == FRAME_ACK_SENT | 27 || event == FRAME_ACK_SENT |
29 || event == PACKET_RECEIVED; | 28 || event == PACKET_RECEIVED; |
30 } | 29 } |
31 | 30 |
32 } // namespace | 31 } // namespace |
33 | 32 |
34 StatsEventSubscriber::StatsEventSubscriber( | 33 StatsEventSubscriber::StatsEventSubscriber( |
35 EventMediaType event_media_type, | 34 EventMediaType event_media_type, |
36 base::TickClock* clock, | 35 base::TickClock* clock, |
37 ReceiverTimeOffsetEstimator* offset_estimator) | 36 ReceiverTimeOffsetEstimator* offset_estimator) |
38 : event_media_type_(event_media_type), | 37 : event_media_type_(event_media_type), |
39 clock_(clock), | 38 clock_(clock), |
40 offset_estimator_(offset_estimator), | 39 offset_estimator_(offset_estimator), |
41 network_latency_datapoints_(0), | 40 network_latency_datapoints_(0), |
42 e2e_latency_datapoints_(0) { | 41 e2e_latency_datapoints_(0), |
| 42 num_frames_dropped_by_encoder_(0), |
| 43 num_frames_late_(0) { |
43 DCHECK(event_media_type == AUDIO_EVENT || event_media_type == VIDEO_EVENT); | 44 DCHECK(event_media_type == AUDIO_EVENT || event_media_type == VIDEO_EVENT); |
44 base::TimeTicks now = clock_->NowTicks(); | 45 base::TimeTicks now = clock_->NowTicks(); |
45 start_time_ = now; | 46 start_time_ = now; |
46 last_response_received_time_ = base::TimeTicks(); | 47 last_response_received_time_ = base::TimeTicks(); |
47 } | 48 } |
48 | 49 |
49 StatsEventSubscriber::~StatsEventSubscriber() { | 50 StatsEventSubscriber::~StatsEventSubscriber() { |
50 DCHECK(thread_checker_.CalledOnValidThread()); | 51 DCHECK(thread_checker_.CalledOnValidThread()); |
51 } | 52 } |
52 | 53 |
(...skipping 11 matching lines...) Expand all Loading... |
64 stats.sum_size = frame_event.size; | 65 stats.sum_size = frame_event.size; |
65 stats.sum_delay = frame_event.delay_delta; | 66 stats.sum_delay = frame_event.delay_delta; |
66 frame_stats_.insert(std::make_pair(type, stats)); | 67 frame_stats_.insert(std::make_pair(type, stats)); |
67 } else { | 68 } else { |
68 ++(it->second.event_counter); | 69 ++(it->second.event_counter); |
69 it->second.sum_size += frame_event.size; | 70 it->second.sum_size += frame_event.size; |
70 it->second.sum_delay += frame_event.delay_delta; | 71 it->second.sum_delay += frame_event.delay_delta; |
71 } | 72 } |
72 | 73 |
73 if (type == FRAME_CAPTURE_BEGIN) { | 74 if (type == FRAME_CAPTURE_BEGIN) { |
74 RecordFrameCapturedTime(frame_event); | 75 RecordFrameCaptureTime(frame_event); |
| 76 } else if (type == FRAME_ENCODED) { |
| 77 MarkAsEncoded(frame_event.rtp_timestamp); |
75 } else if (type == FRAME_PLAYOUT) { | 78 } else if (type == FRAME_PLAYOUT) { |
76 RecordE2ELatency(frame_event); | 79 RecordE2ELatency(frame_event); |
| 80 if (frame_event.delay_delta <= base::TimeDelta()) |
| 81 num_frames_late_++; |
77 } | 82 } |
78 | 83 |
79 if (IsReceiverEvent(type)) | 84 if (IsReceiverEvent(type)) |
80 UpdateLastResponseTime(frame_event.timestamp); | 85 UpdateLastResponseTime(frame_event.timestamp); |
81 } | 86 } |
82 | 87 |
83 void StatsEventSubscriber::OnReceivePacketEvent( | 88 void StatsEventSubscriber::OnReceivePacketEvent( |
84 const PacketEvent& packet_event) { | 89 const PacketEvent& packet_event) { |
85 DCHECK(thread_checker_.CalledOnValidThread()); | 90 DCHECK(thread_checker_.CalledOnValidThread()); |
86 | 91 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 | 136 |
132 void StatsEventSubscriber::Reset() { | 137 void StatsEventSubscriber::Reset() { |
133 DCHECK(thread_checker_.CalledOnValidThread()); | 138 DCHECK(thread_checker_.CalledOnValidThread()); |
134 | 139 |
135 frame_stats_.clear(); | 140 frame_stats_.clear(); |
136 packet_stats_.clear(); | 141 packet_stats_.clear(); |
137 total_network_latency_ = base::TimeDelta(); | 142 total_network_latency_ = base::TimeDelta(); |
138 network_latency_datapoints_ = 0; | 143 network_latency_datapoints_ = 0; |
139 total_e2e_latency_ = base::TimeDelta(); | 144 total_e2e_latency_ = base::TimeDelta(); |
140 e2e_latency_datapoints_ = 0; | 145 e2e_latency_datapoints_ = 0; |
141 frame_captured_times_.clear(); | 146 num_frames_dropped_by_encoder_ = 0; |
| 147 num_frames_late_ = 0; |
| 148 recent_captured_frames_.clear(); |
142 packet_sent_times_.clear(); | 149 packet_sent_times_.clear(); |
143 start_time_ = clock_->NowTicks(); | 150 start_time_ = clock_->NowTicks(); |
144 last_response_received_time_ = base::TimeTicks(); | 151 last_response_received_time_ = base::TimeTicks(); |
145 } | 152 } |
146 | 153 |
147 // static | 154 // static |
148 const char* StatsEventSubscriber::CastStatToString(CastStat stat) { | 155 const char* StatsEventSubscriber::CastStatToString(CastStat stat) { |
149 switch (stat) { | 156 switch (stat) { |
150 STAT_ENUM_TO_STRING(CAPTURE_FPS); | 157 STAT_ENUM_TO_STRING(CAPTURE_FPS); |
151 STAT_ENUM_TO_STRING(ENCODE_FPS); | 158 STAT_ENUM_TO_STRING(ENCODE_FPS); |
152 STAT_ENUM_TO_STRING(DECODE_FPS); | 159 STAT_ENUM_TO_STRING(DECODE_FPS); |
153 STAT_ENUM_TO_STRING(AVG_ENCODE_TIME_MS); | 160 STAT_ENUM_TO_STRING(AVG_ENCODE_TIME_MS); |
154 STAT_ENUM_TO_STRING(AVG_PLAYOUT_DELAY_MS); | 161 STAT_ENUM_TO_STRING(AVG_PLAYOUT_DELAY_MS); |
155 STAT_ENUM_TO_STRING(AVG_NETWORK_LATENCY_MS); | 162 STAT_ENUM_TO_STRING(AVG_NETWORK_LATENCY_MS); |
156 STAT_ENUM_TO_STRING(AVG_E2E_LATENCY_MS); | 163 STAT_ENUM_TO_STRING(AVG_E2E_LATENCY_MS); |
157 STAT_ENUM_TO_STRING(ENCODE_KBPS); | 164 STAT_ENUM_TO_STRING(ENCODE_KBPS); |
158 STAT_ENUM_TO_STRING(TRANSMISSION_KBPS); | 165 STAT_ENUM_TO_STRING(TRANSMISSION_KBPS); |
159 STAT_ENUM_TO_STRING(RETRANSMISSION_KBPS); | 166 STAT_ENUM_TO_STRING(RETRANSMISSION_KBPS); |
160 STAT_ENUM_TO_STRING(PACKET_LOSS_FRACTION); | 167 STAT_ENUM_TO_STRING(PACKET_LOSS_FRACTION); |
161 STAT_ENUM_TO_STRING(MS_SINCE_LAST_RECEIVER_RESPONSE); | 168 STAT_ENUM_TO_STRING(MS_SINCE_LAST_RECEIVER_RESPONSE); |
| 169 STAT_ENUM_TO_STRING(NUM_FRAMES_CAPTURED); |
| 170 STAT_ENUM_TO_STRING(NUM_FRAMES_DROPPED_BY_ENCODER); |
| 171 STAT_ENUM_TO_STRING(NUM_FRAMES_LATE); |
| 172 STAT_ENUM_TO_STRING(NUM_PACKETS_SENT); |
| 173 STAT_ENUM_TO_STRING(NUM_PACKETS_RETRANSMITTED); |
| 174 STAT_ENUM_TO_STRING(NUM_PACKETS_RTX_REJECTED); |
162 } | 175 } |
163 NOTREACHED(); | 176 NOTREACHED(); |
164 return ""; | 177 return ""; |
165 } | 178 } |
166 | 179 |
167 void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { | 180 void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { |
168 DCHECK(thread_checker_.CalledOnValidThread()); | 181 DCHECK(thread_checker_.CalledOnValidThread()); |
169 | 182 |
170 stats_map->clear(); | 183 stats_map->clear(); |
171 | 184 |
172 base::TimeTicks end_time = clock_->NowTicks(); | 185 base::TimeTicks end_time = clock_->NowTicks(); |
173 | 186 |
174 PopulateFpsStat( | 187 PopulateFpsStat( |
175 end_time, FRAME_CAPTURE_BEGIN, CAPTURE_FPS, stats_map); | 188 end_time, FRAME_CAPTURE_BEGIN, CAPTURE_FPS, stats_map); |
176 PopulateFpsStat( | 189 PopulateFpsStat( |
177 end_time, FRAME_ENCODED, ENCODE_FPS, stats_map); | 190 end_time, FRAME_ENCODED, ENCODE_FPS, stats_map); |
178 PopulateFpsStat( | 191 PopulateFpsStat( |
179 end_time, FRAME_DECODED, DECODE_FPS, stats_map); | 192 end_time, FRAME_DECODED, DECODE_FPS, stats_map); |
180 PopulatePlayoutDelayStat(stats_map); | 193 PopulatePlayoutDelayStat(stats_map); |
181 PopulateFrameBitrateStat(end_time, stats_map); | 194 PopulateFrameBitrateStat(end_time, stats_map); |
182 PopulatePacketBitrateStat(end_time, | 195 PopulatePacketBitrateStat(end_time, |
183 PACKET_SENT_TO_NETWORK, | 196 PACKET_SENT_TO_NETWORK, |
184 TRANSMISSION_KBPS, | 197 TRANSMISSION_KBPS, |
185 stats_map); | 198 stats_map); |
186 PopulatePacketBitrateStat(end_time, | 199 PopulatePacketBitrateStat(end_time, |
187 PACKET_RETRANSMITTED, | 200 PACKET_RETRANSMITTED, |
188 RETRANSMISSION_KBPS, | 201 RETRANSMISSION_KBPS, |
189 stats_map); | 202 stats_map); |
190 PopulatePacketLossPercentageStat(stats_map); | 203 PopulatePacketLossPercentageStat(stats_map); |
| 204 PopulateFrameCountStat(FRAME_CAPTURE_END, NUM_FRAMES_CAPTURED, stats_map); |
| 205 PopulatePacketCountStat(PACKET_SENT_TO_NETWORK, NUM_PACKETS_SENT, stats_map); |
| 206 PopulatePacketCountStat( |
| 207 PACKET_RETRANSMITTED, NUM_PACKETS_RETRANSMITTED, stats_map); |
| 208 PopulatePacketCountStat( |
| 209 PACKET_RTX_REJECTED, NUM_PACKETS_RTX_REJECTED, stats_map); |
191 | 210 |
192 if (network_latency_datapoints_ > 0) { | 211 if (network_latency_datapoints_ > 0) { |
193 double avg_network_latency_ms = | 212 double avg_network_latency_ms = |
194 total_network_latency_.InMillisecondsF() / | 213 total_network_latency_.InMillisecondsF() / |
195 network_latency_datapoints_; | 214 network_latency_datapoints_; |
196 stats_map->insert( | 215 stats_map->insert( |
197 std::make_pair(AVG_NETWORK_LATENCY_MS, avg_network_latency_ms)); | 216 std::make_pair(AVG_NETWORK_LATENCY_MS, avg_network_latency_ms)); |
198 } | 217 } |
199 | 218 |
200 if (e2e_latency_datapoints_ > 0) { | 219 if (e2e_latency_datapoints_ > 0) { |
201 double avg_e2e_latency_ms = | 220 double avg_e2e_latency_ms = |
202 total_e2e_latency_.InMillisecondsF() / e2e_latency_datapoints_; | 221 total_e2e_latency_.InMillisecondsF() / e2e_latency_datapoints_; |
203 stats_map->insert(std::make_pair(AVG_E2E_LATENCY_MS, avg_e2e_latency_ms)); | 222 stats_map->insert(std::make_pair(AVG_E2E_LATENCY_MS, avg_e2e_latency_ms)); |
204 } | 223 } |
205 | 224 |
206 if (!last_response_received_time_.is_null()) { | 225 if (!last_response_received_time_.is_null()) { |
207 stats_map->insert( | 226 stats_map->insert( |
208 std::make_pair(MS_SINCE_LAST_RECEIVER_RESPONSE, | 227 std::make_pair(MS_SINCE_LAST_RECEIVER_RESPONSE, |
209 (end_time - last_response_received_time_).InMillisecondsF())); | 228 (end_time - last_response_received_time_).InMillisecondsF())); |
210 } | 229 } |
| 230 |
| 231 stats_map->insert(std::make_pair(NUM_FRAMES_DROPPED_BY_ENCODER, |
| 232 num_frames_dropped_by_encoder_)); |
| 233 stats_map->insert(std::make_pair(NUM_FRAMES_LATE, num_frames_late_)); |
211 } | 234 } |
212 | 235 |
213 bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) { | 236 bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) { |
214 base::TimeDelta receiver_offset_lower_bound; | 237 base::TimeDelta receiver_offset_lower_bound; |
215 base::TimeDelta receiver_offset_upper_bound; | 238 base::TimeDelta receiver_offset_upper_bound; |
216 if (!offset_estimator_->GetReceiverOffsetBounds( | 239 if (!offset_estimator_->GetReceiverOffsetBounds( |
217 &receiver_offset_lower_bound, &receiver_offset_upper_bound)) { | 240 &receiver_offset_lower_bound, &receiver_offset_upper_bound)) { |
218 return false; | 241 return false; |
219 } | 242 } |
220 | 243 |
221 *offset = (receiver_offset_lower_bound + receiver_offset_upper_bound) / 2; | 244 *offset = (receiver_offset_lower_bound + receiver_offset_upper_bound) / 2; |
222 return true; | 245 return true; |
223 } | 246 } |
224 | 247 |
225 void StatsEventSubscriber::RecordFrameCapturedTime( | 248 void StatsEventSubscriber::RecordFrameCaptureTime( |
226 const FrameEvent& frame_event) { | 249 const FrameEvent& frame_event) { |
227 frame_captured_times_.insert( | 250 recent_captured_frames_.insert(std::make_pair( |
228 std::make_pair(frame_event.rtp_timestamp, frame_event.timestamp)); | 251 frame_event.rtp_timestamp, FrameInfo(frame_event.timestamp))); |
229 if (frame_captured_times_.size() > kMaxFrameEventTimeMapSize) | 252 if (recent_captured_frames_.size() > kMaxFrameInfoMapSize) { |
230 frame_captured_times_.erase(frame_captured_times_.begin()); | 253 FrameInfoMap::iterator erase_it = recent_captured_frames_.begin(); |
| 254 if (!erase_it->second.encoded) |
| 255 num_frames_dropped_by_encoder_++; |
| 256 recent_captured_frames_.erase(erase_it); |
| 257 } |
| 258 } |
| 259 |
| 260 void StatsEventSubscriber::MarkAsEncoded(RtpTimestamp rtp_timestamp) { |
| 261 FrameInfoMap::iterator it = recent_captured_frames_.find(rtp_timestamp); |
| 262 if (it != recent_captured_frames_.end()) |
| 263 it->second.encoded = true; |
231 } | 264 } |
232 | 265 |
233 void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { | 266 void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { |
234 base::TimeDelta receiver_offset; | 267 base::TimeDelta receiver_offset; |
235 if (!GetReceiverOffset(&receiver_offset)) | 268 if (!GetReceiverOffset(&receiver_offset)) |
236 return; | 269 return; |
237 | 270 |
238 FrameEventTimeMap::iterator it = | 271 FrameInfoMap::iterator it = |
239 frame_captured_times_.find(frame_event.rtp_timestamp); | 272 recent_captured_frames_.find(frame_event.rtp_timestamp); |
240 if (it == frame_captured_times_.end()) | 273 if (it == recent_captured_frames_.end()) |
241 return; | 274 return; |
242 | 275 |
243 // Playout time is event time + playout delay. | 276 // Playout time is event time + playout delay. |
244 base::TimeTicks playout_time = | 277 base::TimeTicks playout_time = |
245 frame_event.timestamp + frame_event.delay_delta - receiver_offset; | 278 frame_event.timestamp + frame_event.delay_delta - receiver_offset; |
246 total_e2e_latency_ += playout_time - it->second; | 279 total_e2e_latency_ += playout_time - it->second.capture_time; |
247 e2e_latency_datapoints_++; | 280 e2e_latency_datapoints_++; |
248 } | 281 } |
249 | 282 |
250 void StatsEventSubscriber::UpdateLastResponseTime( | 283 void StatsEventSubscriber::UpdateLastResponseTime( |
251 base::TimeTicks receiver_time) { | 284 base::TimeTicks receiver_time) { |
252 base::TimeDelta receiver_offset; | 285 base::TimeDelta receiver_offset; |
253 if (!GetReceiverOffset(&receiver_offset)) | 286 if (!GetReceiverOffset(&receiver_offset)) |
254 return; | 287 return; |
255 base::TimeTicks sender_time = receiver_time - receiver_offset; | 288 base::TimeTicks sender_time = receiver_time - receiver_offset; |
256 last_response_received_time_ = sender_time; | 289 last_response_received_time_ = sender_time; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 if (it != frame_stats_.end()) { | 349 if (it != frame_stats_.end()) { |
317 double fps = 0.0; | 350 double fps = 0.0; |
318 base::TimeDelta duration = (end_time - start_time_); | 351 base::TimeDelta duration = (end_time - start_time_); |
319 int count = it->second.event_counter; | 352 int count = it->second.event_counter; |
320 if (duration > base::TimeDelta()) | 353 if (duration > base::TimeDelta()) |
321 fps = count / duration.InSecondsF(); | 354 fps = count / duration.InSecondsF(); |
322 stats_map->insert(std::make_pair(stat, fps)); | 355 stats_map->insert(std::make_pair(stat, fps)); |
323 } | 356 } |
324 } | 357 } |
325 | 358 |
| 359 void StatsEventSubscriber::PopulateFrameCountStat(CastLoggingEvent event, |
| 360 CastStat stat, |
| 361 StatsMap* stats_map) const { |
| 362 FrameStatsMap::const_iterator it = frame_stats_.find(event); |
| 363 if (it != frame_stats_.end()) { |
| 364 stats_map->insert(std::make_pair(stat, it->second.event_counter)); |
| 365 } |
| 366 } |
| 367 |
| 368 void StatsEventSubscriber::PopulatePacketCountStat(CastLoggingEvent event, |
| 369 CastStat stat, |
| 370 StatsMap* stats_map) const { |
| 371 PacketStatsMap::const_iterator it = packet_stats_.find(event); |
| 372 if (it != packet_stats_.end()) { |
| 373 stats_map->insert(std::make_pair(stat, it->second.event_counter)); |
| 374 } |
| 375 } |
| 376 |
326 void StatsEventSubscriber::PopulatePlayoutDelayStat(StatsMap* stats_map) const { | 377 void StatsEventSubscriber::PopulatePlayoutDelayStat(StatsMap* stats_map) const { |
327 FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_PLAYOUT); | 378 FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_PLAYOUT); |
328 if (it != frame_stats_.end()) { | 379 if (it != frame_stats_.end()) { |
329 double avg_delay_ms = 0.0; | 380 double avg_delay_ms = 0.0; |
330 base::TimeDelta sum_delay = it->second.sum_delay; | 381 base::TimeDelta sum_delay = it->second.sum_delay; |
331 int count = it->second.event_counter; | 382 int count = it->second.event_counter; |
332 if (count != 0) | 383 if (count != 0) |
333 avg_delay_ms = sum_delay.InMillisecondsF() / count; | 384 avg_delay_ms = sum_delay.InMillisecondsF() / count; |
334 stats_map->insert(std::make_pair(AVG_PLAYOUT_DELAY_MS, avg_delay_ms)); | 385 stats_map->insert(std::make_pair(AVG_PLAYOUT_DELAY_MS, avg_delay_ms)); |
335 } | 386 } |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 } | 440 } |
390 | 441 |
391 StatsEventSubscriber::FrameLogStats::FrameLogStats() | 442 StatsEventSubscriber::FrameLogStats::FrameLogStats() |
392 : event_counter(0), sum_size(0) {} | 443 : event_counter(0), sum_size(0) {} |
393 StatsEventSubscriber::FrameLogStats::~FrameLogStats() {} | 444 StatsEventSubscriber::FrameLogStats::~FrameLogStats() {} |
394 | 445 |
395 StatsEventSubscriber::PacketLogStats::PacketLogStats() | 446 StatsEventSubscriber::PacketLogStats::PacketLogStats() |
396 : event_counter(0), sum_size(0) {} | 447 : event_counter(0), sum_size(0) {} |
397 StatsEventSubscriber::PacketLogStats::~PacketLogStats() {} | 448 StatsEventSubscriber::PacketLogStats::~PacketLogStats() {} |
398 | 449 |
| 450 StatsEventSubscriber::FrameInfo::FrameInfo(base::TimeTicks capture_time) |
| 451 : capture_time(capture_time), encoded(false) { |
| 452 } |
| 453 StatsEventSubscriber::FrameInfo::~FrameInfo() { |
| 454 } |
| 455 |
399 } // namespace cast | 456 } // namespace cast |
400 } // namespace media | 457 } // namespace media |
OLD | NEW |