Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / media / cast / logging / stats_event_subscriber.cc
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.
4
5 #include <cmath>
6
7 #include "media/cast/logging/stats_event_subscriber.h"
8
9 #include "base/format_macros.h"
10 #include "base/logging.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/values.h"
13
14 #define STAT_ENUM_TO_STRING(enum) \
15   case enum:                      \
16     return #enum
17
18 namespace media {
19 namespace cast {
20
21 namespace {
22
23 using media::cast::CastLoggingEvent;
24 using media::cast::EventMediaType;
25
26 const size_t kMaxPacketEventTimeMapSize = 1000;
27
28 bool IsReceiverEvent(CastLoggingEvent event) {
29   return event == FRAME_DECODED
30       || event == FRAME_PLAYOUT
31       || event == FRAME_ACK_SENT
32       || event == PACKET_RECEIVED;
33 }
34
35 }  // namespace
36
37 StatsEventSubscriber::SimpleHistogram::SimpleHistogram(int64 min,
38                                                        int64 max,
39                                                        int64 width)
40     : min_(min), max_(max), width_(width), buckets_((max - min) / width + 2) {
41   CHECK_GT(buckets_.size(), 2u);
42   CHECK_EQ(0, (max_ - min_) % width_);
43 }
44
45 StatsEventSubscriber::SimpleHistogram::~SimpleHistogram() {
46 }
47
48 void StatsEventSubscriber::SimpleHistogram::Add(int64 sample) {
49   if (sample < min_) {
50     ++buckets_.front();
51   } else if (sample >= max_) {
52     ++buckets_.back();
53   } else {
54     size_t index = 1 + (sample - min_) / width_;
55     DCHECK_LT(index, buckets_.size());
56     ++buckets_[index];
57   }
58 }
59
60 void StatsEventSubscriber::SimpleHistogram::Reset() {
61   buckets_.assign(buckets_.size(), 0);
62 }
63
64 scoped_ptr<base::ListValue>
65 StatsEventSubscriber::SimpleHistogram::GetHistogram() const {
66   scoped_ptr<base::ListValue> histo(new base::ListValue);
67
68   scoped_ptr<base::DictionaryValue> bucket(new base::DictionaryValue);
69
70   if (buckets_.front()) {
71     bucket->SetInteger(base::StringPrintf("<%" PRId64, min_),
72                        buckets_.front());
73     histo->Append(bucket.release());
74   }
75
76   for (size_t i = 1; i < buckets_.size() - 1; i++) {
77     if (!buckets_[i])
78       continue;
79     bucket.reset(new base::DictionaryValue);
80     int64 lower = min_ + (i - 1) * width_;
81     int64 upper = lower + width_ - 1;
82     bucket->SetInteger(
83         base::StringPrintf("%" PRId64 "-%" PRId64, lower, upper),
84         buckets_[i]);
85     histo->Append(bucket.release());
86   }
87
88   if (buckets_.back()) {
89     bucket.reset(new base::DictionaryValue);
90     bucket->SetInteger(base::StringPrintf(">=%" PRId64, max_),
91                        buckets_.back());
92     histo->Append(bucket.release());
93   }
94   return histo.Pass();
95 }
96
97 StatsEventSubscriber::StatsEventSubscriber(
98     EventMediaType event_media_type,
99     base::TickClock* clock,
100     ReceiverTimeOffsetEstimator* offset_estimator)
101     : event_media_type_(event_media_type),
102       clock_(clock),
103       offset_estimator_(offset_estimator),
104       network_latency_datapoints_(0),
105       e2e_latency_datapoints_(0),
106       num_frames_dropped_by_encoder_(0),
107       num_frames_late_(0),
108       start_time_(clock_->NowTicks()) {
109   DCHECK(event_media_type == AUDIO_EVENT || event_media_type == VIDEO_EVENT);
110
111   InitHistograms();
112 }
113
114 StatsEventSubscriber::~StatsEventSubscriber() {
115   DCHECK(thread_checker_.CalledOnValidThread());
116 }
117
118 void StatsEventSubscriber::OnReceiveFrameEvent(const FrameEvent& frame_event) {
119   DCHECK(thread_checker_.CalledOnValidThread());
120
121   CastLoggingEvent type = frame_event.type;
122   if (frame_event.media_type != event_media_type_)
123     return;
124
125   FrameStatsMap::iterator it = frame_stats_.find(type);
126   if (it == frame_stats_.end()) {
127     FrameLogStats stats;
128     stats.event_counter = 1;
129     stats.sum_size = frame_event.size;
130     stats.sum_delay = frame_event.delay_delta;
131     frame_stats_.insert(std::make_pair(type, stats));
132   } else {
133     ++(it->second.event_counter);
134     it->second.sum_size += frame_event.size;
135     it->second.sum_delay += frame_event.delay_delta;
136   }
137
138   bool is_receiver_event = IsReceiverEvent(type);
139   UpdateFirstLastEventTime(frame_event.timestamp, is_receiver_event);
140
141   if (type == FRAME_CAPTURE_BEGIN) {
142     RecordFrameCaptureTime(frame_event);
143   } else if (type == FRAME_CAPTURE_END) {
144     RecordCaptureLatency(frame_event);
145   } else if (type == FRAME_ENCODED) {
146     RecordEncodeLatency(frame_event);
147   } else if (type == FRAME_ACK_SENT) {
148     RecordFrameTxLatency(frame_event);
149   } else if (type == FRAME_PLAYOUT) {
150     RecordE2ELatency(frame_event);
151     base::TimeDelta delay_delta = frame_event.delay_delta;
152     histograms_[PLAYOUT_DELAY_MS_HISTO]->Add(delay_delta.InMillisecondsF());
153     if (delay_delta <= base::TimeDelta())
154       num_frames_late_++;
155   }
156
157   if (is_receiver_event)
158     UpdateLastResponseTime(frame_event.timestamp);
159 }
160
161 void StatsEventSubscriber::OnReceivePacketEvent(
162     const PacketEvent& packet_event) {
163   DCHECK(thread_checker_.CalledOnValidThread());
164
165   CastLoggingEvent type = packet_event.type;
166   if (packet_event.media_type != event_media_type_)
167     return;
168
169   PacketStatsMap::iterator it = packet_stats_.find(type);
170   if (it == packet_stats_.end()) {
171     PacketLogStats stats;
172     stats.event_counter = 1;
173     stats.sum_size = packet_event.size;
174     packet_stats_.insert(std::make_pair(type, stats));
175   } else {
176     ++(it->second.event_counter);
177     it->second.sum_size += packet_event.size;
178   }
179
180   bool is_receiver_event = IsReceiverEvent(type);
181   UpdateFirstLastEventTime(packet_event.timestamp, is_receiver_event);
182
183   if (type == PACKET_SENT_TO_NETWORK ||
184       type == PACKET_RECEIVED) {
185     RecordNetworkLatency(packet_event);
186   } else if (type == PACKET_RETRANSMITTED) {
187     // We only measure network latency using packets that doesn't have to be
188     // retransmitted as there is precisely one sent-receive timestamp pairs.
189     ErasePacketSentTime(packet_event);
190   }
191
192   if (is_receiver_event)
193     UpdateLastResponseTime(packet_event.timestamp);
194 }
195
196 void StatsEventSubscriber::UpdateFirstLastEventTime(base::TimeTicks timestamp,
197                                                     bool is_receiver_event) {
198   if (is_receiver_event) {
199     base::TimeDelta receiver_offset;
200     if (!GetReceiverOffset(&receiver_offset))
201       return;
202     timestamp -= receiver_offset;
203   }
204
205   if (first_event_time_.is_null()) {
206     first_event_time_ = timestamp;
207   } else {
208     first_event_time_ = std::min(first_event_time_, timestamp);
209   }
210   if (last_event_time_.is_null()) {
211     last_event_time_ = timestamp;
212   } else {
213     last_event_time_ = std::max(last_event_time_, timestamp);
214   }
215 }
216
217 scoped_ptr<base::DictionaryValue> StatsEventSubscriber::GetStats() const {
218   StatsMap stats_map;
219   GetStatsInternal(&stats_map);
220   scoped_ptr<base::DictionaryValue> ret(new base::DictionaryValue);
221
222   scoped_ptr<base::DictionaryValue> stats(new base::DictionaryValue);
223   for (StatsMap::const_iterator it = stats_map.begin(); it != stats_map.end();
224        ++it) {
225     // Round to 3 digits after the decimal point.
226     stats->SetDouble(CastStatToString(it->first),
227                      round(it->second * 1000.0) / 1000.0);
228   }
229   for (HistogramMap::const_iterator it = histograms_.begin();
230        it != histograms_.end();
231        ++it) {
232     stats->Set(CastStatToString(it->first),
233                it->second->GetHistogram().release());
234   }
235
236   ret->Set(event_media_type_ == AUDIO_EVENT ? "audio" : "video",
237            stats.release());
238
239   return ret.Pass();
240 }
241
242 void StatsEventSubscriber::Reset() {
243   DCHECK(thread_checker_.CalledOnValidThread());
244
245   frame_stats_.clear();
246   packet_stats_.clear();
247   total_network_latency_ = base::TimeDelta();
248   network_latency_datapoints_ = 0;
249   total_e2e_latency_ = base::TimeDelta();
250   e2e_latency_datapoints_ = 0;
251   num_frames_dropped_by_encoder_ = 0;
252   num_frames_late_ = 0;
253   recent_frame_infos_.clear();
254   packet_sent_times_.clear();
255   start_time_ = clock_->NowTicks();
256   last_response_received_time_ = base::TimeTicks();
257   for (HistogramMap::iterator it = histograms_.begin(); it != histograms_.end();
258        ++it) {
259     it->second->Reset();
260   }
261
262   first_event_time_ = base::TimeTicks();
263   last_event_time_ = base::TimeTicks();
264 }
265
266 // static
267 const char* StatsEventSubscriber::CastStatToString(CastStat stat) {
268   switch (stat) {
269     STAT_ENUM_TO_STRING(CAPTURE_FPS);
270     STAT_ENUM_TO_STRING(ENCODE_FPS);
271     STAT_ENUM_TO_STRING(DECODE_FPS);
272     STAT_ENUM_TO_STRING(AVG_ENCODE_TIME_MS);
273     STAT_ENUM_TO_STRING(AVG_PLAYOUT_DELAY_MS);
274     STAT_ENUM_TO_STRING(AVG_NETWORK_LATENCY_MS);
275     STAT_ENUM_TO_STRING(AVG_E2E_LATENCY_MS);
276     STAT_ENUM_TO_STRING(ENCODE_KBPS);
277     STAT_ENUM_TO_STRING(TRANSMISSION_KBPS);
278     STAT_ENUM_TO_STRING(RETRANSMISSION_KBPS);
279     STAT_ENUM_TO_STRING(PACKET_LOSS_FRACTION);
280     STAT_ENUM_TO_STRING(MS_SINCE_LAST_RECEIVER_RESPONSE);
281     STAT_ENUM_TO_STRING(NUM_FRAMES_CAPTURED);
282     STAT_ENUM_TO_STRING(NUM_FRAMES_DROPPED_BY_ENCODER);
283     STAT_ENUM_TO_STRING(NUM_FRAMES_LATE);
284     STAT_ENUM_TO_STRING(NUM_PACKETS_SENT);
285     STAT_ENUM_TO_STRING(NUM_PACKETS_RETRANSMITTED);
286     STAT_ENUM_TO_STRING(NUM_PACKETS_RTX_REJECTED);
287     STAT_ENUM_TO_STRING(FIRST_EVENT_TIME_MS);
288     STAT_ENUM_TO_STRING(LAST_EVENT_TIME_MS);
289     STAT_ENUM_TO_STRING(CAPTURE_LATENCY_MS_HISTO);
290     STAT_ENUM_TO_STRING(ENCODE_LATENCY_MS_HISTO);
291     STAT_ENUM_TO_STRING(PACKET_LATENCY_MS_HISTO);
292     STAT_ENUM_TO_STRING(FRAME_LATENCY_MS_HISTO);
293     STAT_ENUM_TO_STRING(PLAYOUT_DELAY_MS_HISTO);
294   }
295   NOTREACHED();
296   return "";
297 }
298
299 const int kMaxLatencyBucketMs = 800;
300 const int kBucketWidthMs = 20;
301
302 void StatsEventSubscriber::InitHistograms() {
303   histograms_[CAPTURE_LATENCY_MS_HISTO].reset(
304       new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
305   histograms_[ENCODE_LATENCY_MS_HISTO].reset(
306       new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
307   histograms_[PACKET_LATENCY_MS_HISTO].reset(
308       new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
309   histograms_[FRAME_LATENCY_MS_HISTO].reset(
310       new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
311   histograms_[PLAYOUT_DELAY_MS_HISTO].reset(
312       new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
313 }
314
315 void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const {
316   DCHECK(thread_checker_.CalledOnValidThread());
317
318   stats_map->clear();
319
320   base::TimeTicks end_time = clock_->NowTicks();
321
322   PopulateFpsStat(
323       end_time, FRAME_CAPTURE_BEGIN, CAPTURE_FPS, stats_map);
324   PopulateFpsStat(
325       end_time, FRAME_ENCODED, ENCODE_FPS, stats_map);
326   PopulateFpsStat(
327       end_time, FRAME_DECODED, DECODE_FPS, stats_map);
328   PopulatePlayoutDelayStat(stats_map);
329   PopulateFrameBitrateStat(end_time, stats_map);
330   PopulatePacketBitrateStat(end_time,
331                             PACKET_SENT_TO_NETWORK,
332                             TRANSMISSION_KBPS,
333                             stats_map);
334   PopulatePacketBitrateStat(end_time,
335                             PACKET_RETRANSMITTED,
336                             RETRANSMISSION_KBPS,
337                             stats_map);
338   PopulatePacketLossPercentageStat(stats_map);
339   PopulateFrameCountStat(FRAME_CAPTURE_END, NUM_FRAMES_CAPTURED, stats_map);
340   PopulatePacketCountStat(PACKET_SENT_TO_NETWORK, NUM_PACKETS_SENT, stats_map);
341   PopulatePacketCountStat(
342       PACKET_RETRANSMITTED, NUM_PACKETS_RETRANSMITTED, stats_map);
343   PopulatePacketCountStat(
344       PACKET_RTX_REJECTED, NUM_PACKETS_RTX_REJECTED, stats_map);
345
346   if (network_latency_datapoints_ > 0) {
347     double avg_network_latency_ms =
348         total_network_latency_.InMillisecondsF() /
349         network_latency_datapoints_;
350     stats_map->insert(
351         std::make_pair(AVG_NETWORK_LATENCY_MS, avg_network_latency_ms));
352   }
353
354   if (e2e_latency_datapoints_ > 0) {
355     double avg_e2e_latency_ms =
356         total_e2e_latency_.InMillisecondsF() / e2e_latency_datapoints_;
357     stats_map->insert(std::make_pair(AVG_E2E_LATENCY_MS, avg_e2e_latency_ms));
358   }
359
360   if (!last_response_received_time_.is_null()) {
361     stats_map->insert(
362         std::make_pair(MS_SINCE_LAST_RECEIVER_RESPONSE,
363         (end_time - last_response_received_time_).InMillisecondsF()));
364   }
365
366   stats_map->insert(std::make_pair(NUM_FRAMES_DROPPED_BY_ENCODER,
367                                    num_frames_dropped_by_encoder_));
368   stats_map->insert(std::make_pair(NUM_FRAMES_LATE, num_frames_late_));
369   if (!first_event_time_.is_null()) {
370     stats_map->insert(std::make_pair(
371         FIRST_EVENT_TIME_MS,
372         (first_event_time_ - base::TimeTicks::UnixEpoch()).InMillisecondsF()));
373   }
374   if (!last_event_time_.is_null()) {
375     stats_map->insert(std::make_pair(
376         LAST_EVENT_TIME_MS,
377         (last_event_time_ - base::TimeTicks::UnixEpoch()).InMillisecondsF()));
378   }
379 }
380
381 bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) {
382   base::TimeDelta receiver_offset_lower_bound;
383   base::TimeDelta receiver_offset_upper_bound;
384   if (!offset_estimator_->GetReceiverOffsetBounds(
385           &receiver_offset_lower_bound, &receiver_offset_upper_bound)) {
386     return false;
387   }
388
389   *offset = (receiver_offset_lower_bound + receiver_offset_upper_bound) / 2;
390   return true;
391 }
392
393 void StatsEventSubscriber::MaybeInsertFrameInfo(RtpTimestamp rtp_timestamp,
394                                                 const FrameInfo& frame_info) {
395   // No need to insert if |rtp_timestamp| is the smaller than every key in the
396   // map as it is just going to get erased anyway.
397   if (recent_frame_infos_.size() == kMaxFrameInfoMapSize &&
398       rtp_timestamp < recent_frame_infos_.begin()->first) {
399     return;
400   }
401
402   recent_frame_infos_.insert(std::make_pair(rtp_timestamp, frame_info));
403
404   if (recent_frame_infos_.size() >= kMaxFrameInfoMapSize) {
405     FrameInfoMap::iterator erase_it = recent_frame_infos_.begin();
406     if (erase_it->second.encode_time.is_null())
407       num_frames_dropped_by_encoder_++;
408     recent_frame_infos_.erase(erase_it);
409   }
410 }
411
412 void StatsEventSubscriber::RecordFrameCaptureTime(
413     const FrameEvent& frame_event) {
414   FrameInfo frame_info;
415   frame_info.capture_time = frame_event.timestamp;
416   MaybeInsertFrameInfo(frame_event.rtp_timestamp, frame_info);
417 }
418
419 void StatsEventSubscriber::RecordCaptureLatency(const FrameEvent& frame_event) {
420   FrameInfoMap::iterator it =
421       recent_frame_infos_.find(frame_event.rtp_timestamp);
422   if (it == recent_frame_infos_.end())
423     return;
424
425   if (!it->second.capture_time.is_null()) {
426     double capture_latency_ms =
427         (it->second.capture_time - frame_event.timestamp).InMillisecondsF();
428     histograms_[CAPTURE_LATENCY_MS_HISTO]->Add(capture_latency_ms);
429   }
430
431   it->second.capture_end_time = frame_event.timestamp;
432 }
433
434 void StatsEventSubscriber::RecordEncodeLatency(const FrameEvent& frame_event) {
435   FrameInfoMap::iterator it =
436       recent_frame_infos_.find(frame_event.rtp_timestamp);
437   if (it == recent_frame_infos_.end()) {
438     FrameInfo frame_info;
439     frame_info.encode_time = frame_event.timestamp;
440     MaybeInsertFrameInfo(frame_event.rtp_timestamp, frame_info);
441     return;
442   }
443
444   if (!it->second.capture_end_time.is_null()) {
445     double encode_latency_ms =
446         (frame_event.timestamp - it->second.capture_end_time).InMillisecondsF();
447     histograms_[ENCODE_LATENCY_MS_HISTO]->Add(encode_latency_ms);
448   }
449
450   it->second.encode_time = frame_event.timestamp;
451 }
452
453 void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) {
454   FrameInfoMap::iterator it =
455       recent_frame_infos_.find(frame_event.rtp_timestamp);
456   if (it == recent_frame_infos_.end())
457     return;
458
459   if (it->second.encode_time.is_null())
460     return;
461
462   base::TimeDelta receiver_offset;
463   if (!GetReceiverOffset(&receiver_offset))
464     return;
465
466   base::TimeTicks sender_time = frame_event.timestamp - receiver_offset;
467   double frame_tx_latency_ms =
468       (sender_time - it->second.encode_time).InMillisecondsF();
469   histograms_[FRAME_LATENCY_MS_HISTO]->Add(frame_tx_latency_ms);
470 }
471
472 void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) {
473   base::TimeDelta receiver_offset;
474   if (!GetReceiverOffset(&receiver_offset))
475     return;
476
477   FrameInfoMap::iterator it =
478       recent_frame_infos_.find(frame_event.rtp_timestamp);
479   if (it == recent_frame_infos_.end())
480     return;
481
482   // Playout time is event time + playout delay.
483   base::TimeTicks playout_time =
484       frame_event.timestamp + frame_event.delay_delta - receiver_offset;
485   total_e2e_latency_ += playout_time - it->second.capture_time;
486   e2e_latency_datapoints_++;
487 }
488
489 void StatsEventSubscriber::UpdateLastResponseTime(
490     base::TimeTicks receiver_time) {
491   base::TimeDelta receiver_offset;
492   if (!GetReceiverOffset(&receiver_offset))
493     return;
494   base::TimeTicks sender_time = receiver_time - receiver_offset;
495   last_response_received_time_ = sender_time;
496 }
497
498 void StatsEventSubscriber::ErasePacketSentTime(
499     const PacketEvent& packet_event) {
500   std::pair<RtpTimestamp, uint16> key(
501       std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id));
502   packet_sent_times_.erase(key);
503 }
504
505 void StatsEventSubscriber::RecordNetworkLatency(
506     const PacketEvent& packet_event) {
507   base::TimeDelta receiver_offset;
508   if (!GetReceiverOffset(&receiver_offset))
509     return;
510
511   std::pair<RtpTimestamp, uint16> key(
512       std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id));
513   PacketEventTimeMap::iterator it = packet_sent_times_.find(key);
514   if (it == packet_sent_times_.end()) {
515     std::pair<base::TimeTicks, CastLoggingEvent> value =
516         std::make_pair(packet_event.timestamp, packet_event.type);
517     packet_sent_times_.insert(std::make_pair(key, value));
518     if (packet_sent_times_.size() > kMaxPacketEventTimeMapSize)
519       packet_sent_times_.erase(packet_sent_times_.begin());
520   } else {
521     std::pair<base::TimeTicks, CastLoggingEvent> value = it->second;
522     CastLoggingEvent recorded_type = value.second;
523     bool match = false;
524     base::TimeTicks packet_sent_time;
525     base::TimeTicks packet_received_time;
526     if (recorded_type == PACKET_SENT_TO_NETWORK &&
527         packet_event.type == PACKET_RECEIVED) {
528       packet_sent_time = value.first;
529       packet_received_time = packet_event.timestamp;
530       match = true;
531     } else if (recorded_type == PACKET_RECEIVED &&
532         packet_event.type == PACKET_SENT_TO_NETWORK) {
533       packet_sent_time = packet_event.timestamp;
534       packet_received_time = value.first;
535       match = true;
536     }
537     if (match) {
538       // Subtract by offset.
539       packet_received_time -= receiver_offset;
540       base::TimeDelta latency_delta = packet_received_time - packet_sent_time;
541
542       total_network_latency_ += latency_delta;
543       network_latency_datapoints_++;
544
545       histograms_[PACKET_LATENCY_MS_HISTO]->Add(
546           latency_delta.InMillisecondsF());
547
548       packet_sent_times_.erase(it);
549     }
550   }
551 }
552
553 void StatsEventSubscriber::PopulateFpsStat(base::TimeTicks end_time,
554                                            CastLoggingEvent event,
555                                            CastStat stat,
556                                            StatsMap* stats_map) const {
557   FrameStatsMap::const_iterator it = frame_stats_.find(event);
558   if (it != frame_stats_.end()) {
559     double fps = 0.0;
560     base::TimeDelta duration = (end_time - start_time_);
561     int count = it->second.event_counter;
562     if (duration > base::TimeDelta())
563       fps = count / duration.InSecondsF();
564     stats_map->insert(std::make_pair(stat, fps));
565   }
566 }
567
568 void StatsEventSubscriber::PopulateFrameCountStat(CastLoggingEvent event,
569                                                   CastStat stat,
570                                                   StatsMap* stats_map) const {
571   FrameStatsMap::const_iterator it = frame_stats_.find(event);
572   if (it != frame_stats_.end()) {
573     stats_map->insert(std::make_pair(stat, it->second.event_counter));
574   }
575 }
576
577 void StatsEventSubscriber::PopulatePacketCountStat(CastLoggingEvent event,
578                                                    CastStat stat,
579                                                    StatsMap* stats_map) const {
580   PacketStatsMap::const_iterator it = packet_stats_.find(event);
581   if (it != packet_stats_.end()) {
582     stats_map->insert(std::make_pair(stat, it->second.event_counter));
583   }
584 }
585
586 void StatsEventSubscriber::PopulatePlayoutDelayStat(StatsMap* stats_map) const {
587   FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_PLAYOUT);
588   if (it != frame_stats_.end()) {
589     double avg_delay_ms = 0.0;
590     base::TimeDelta sum_delay = it->second.sum_delay;
591     int count = it->second.event_counter;
592     if (count != 0)
593       avg_delay_ms = sum_delay.InMillisecondsF() / count;
594     stats_map->insert(std::make_pair(AVG_PLAYOUT_DELAY_MS, avg_delay_ms));
595   }
596 }
597
598 void StatsEventSubscriber::PopulateFrameBitrateStat(base::TimeTicks end_time,
599                                                     StatsMap* stats_map) const {
600   FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_ENCODED);
601   if (it != frame_stats_.end()) {
602     double kbps = 0.0;
603     base::TimeDelta duration = end_time - start_time_;
604     if (duration > base::TimeDelta()) {
605       kbps = it->second.sum_size / duration.InMillisecondsF() * 8;
606     }
607
608     stats_map->insert(std::make_pair(ENCODE_KBPS, kbps));
609   }
610 }
611
612 void StatsEventSubscriber::PopulatePacketBitrateStat(
613     base::TimeTicks end_time,
614     CastLoggingEvent event,
615     CastStat stat,
616     StatsMap* stats_map) const {
617   PacketStatsMap::const_iterator it = packet_stats_.find(event);
618   if (it != packet_stats_.end()) {
619     double kbps = 0;
620     base::TimeDelta duration = end_time - start_time_;
621     if (duration > base::TimeDelta()) {
622       kbps = it->second.sum_size / duration.InMillisecondsF() * 8;
623     }
624
625     stats_map->insert(std::make_pair(stat, kbps));
626   }
627 }
628
629 void StatsEventSubscriber::PopulatePacketLossPercentageStat(
630     StatsMap* stats_map) const {
631   // We assume that retransmission means that the packet's previous
632   // (re)transmission was lost.
633   // This means the percentage of packet loss is
634   // (# of retransmit events) / (# of transmit + retransmit events).
635   PacketStatsMap::const_iterator sent_it =
636       packet_stats_.find(PACKET_SENT_TO_NETWORK);
637   if (sent_it == packet_stats_.end())
638     return;
639   PacketStatsMap::const_iterator retransmitted_it =
640       packet_stats_.find(PACKET_RETRANSMITTED);
641   int sent_count = sent_it->second.event_counter;
642   int retransmitted_count = 0;
643   if (retransmitted_it != packet_stats_.end())
644     retransmitted_count = retransmitted_it->second.event_counter;
645   double packet_loss_fraction = static_cast<double>(retransmitted_count) /
646                                 (sent_count + retransmitted_count);
647   stats_map->insert(
648       std::make_pair(PACKET_LOSS_FRACTION, packet_loss_fraction));
649 }
650
651 StatsEventSubscriber::FrameLogStats::FrameLogStats()
652     : event_counter(0), sum_size(0) {}
653 StatsEventSubscriber::FrameLogStats::~FrameLogStats() {}
654
655 StatsEventSubscriber::PacketLogStats::PacketLogStats()
656     : event_counter(0), sum_size(0) {}
657 StatsEventSubscriber::PacketLogStats::~PacketLogStats() {}
658
659 StatsEventSubscriber::FrameInfo::FrameInfo() : encoded(false) {
660 }
661 StatsEventSubscriber::FrameInfo::~FrameInfo() {
662 }
663
664 }  // namespace cast
665 }  // namespace media