1// Copyright 2013 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 "base/memory/linked_ptr.h"
6#include "base/memory/scoped_ptr.h"
7#include "media/cast/logging/logging_stats.h"
8
9namespace media {
10namespace cast {
11
12LoggingStats::LoggingStats(base::TickClock* clock)
13    : frame_stats_(),
14      packet_stats_(),
15      generic_stats_(),
16      start_time_(),
17      clock_(clock) {
18  memset(counts_, 0, sizeof(counts_));
19  memset(start_time_, 0, sizeof(start_time_));
20}
21
22LoggingStats::~LoggingStats() {}
23
24void LoggingStats::Reset() {
25  frame_stats_.clear();
26  packet_stats_.clear();
27  generic_stats_.clear();
28  memset(counts_, 0, sizeof(counts_));
29}
30
31void LoggingStats::InsertFrameEvent(CastLoggingEvent event,
32                                    uint32 rtp_timestamp,
33                                    uint32 frame_id) {
34  InsertBaseFrameEvent(event, frame_id, rtp_timestamp);
35}
36
37void LoggingStats::InsertFrameEventWithSize(CastLoggingEvent event,
38                                            uint32 rtp_timestamp,
39                                            uint32 frame_id,
40                                            int frame_size) {
41  InsertBaseFrameEvent(event, frame_id, rtp_timestamp);
42  // Update size.
43  FrameStatsMap::iterator it = frame_stats_.find(event);
44  DCHECK(it != frame_stats_.end());
45  it->second->bitrate_kbps += frame_size;
46}
47
48void LoggingStats::InsertFrameEventWithDelay(CastLoggingEvent event,
49                                             uint32 rtp_timestamp,
50                                             uint32 frame_id,
51                                             base::TimeDelta delay) {
52  InsertBaseFrameEvent(event, frame_id, rtp_timestamp);
53  // Update size.
54  FrameStatsMap::iterator it = frame_stats_.find(event);
55  DCHECK(it != frame_stats_.end());
56  // Using the average delay as a counter, will divide by the counter when
57  // triggered.
58  it->second->avg_delay_ms += delay.InMilliseconds();
59  if (delay.InMilliseconds() > it->second->max_delay_ms)
60    it->second->max_delay_ms = delay.InMilliseconds();
61  if ((delay.InMilliseconds() < it->second->min_delay_ms) ||
62      (counts_[event] == 1) )
63    it->second->min_delay_ms = delay.InMilliseconds();
64}
65
66void LoggingStats::InsertBaseFrameEvent(CastLoggingEvent event,
67                                        uint32 frame_id,
68                                        uint32 rtp_timestamp) {
69  // Does this belong to an existing event?
70  FrameStatsMap::iterator it = frame_stats_.find(event);
71  if (it == frame_stats_.end()) {
72    // New event.
73    start_time_[event] = clock_->NowTicks();
74    linked_ptr<FrameLogStats> stats(new FrameLogStats());
75    frame_stats_.insert(std::make_pair(event, stats));
76  }
77
78  ++counts_[event];
79}
80
81void LoggingStats::InsertPacketEvent(CastLoggingEvent event,
82                                     uint32 rtp_timestamp,
83                                     uint32 frame_id,
84                                     uint16 packet_id,
85                                     uint16 max_packet_id,
86                                     size_t size) {
87  // Does this packet belong to an existing event?
88  PacketStatsMap::iterator it = packet_stats_.find(event);
89  if (it == packet_stats_.end()) {
90    // New event.
91    start_time_[event] = clock_->NowTicks();
92    packet_stats_.insert(std::make_pair(event, size));
93  } else {
94    // Add to existing.
95    it->second += size;
96  }
97  ++counts_[event];
98}
99
100void LoggingStats::InsertGenericEvent(CastLoggingEvent event, int value) {
101  // Does this event belong to an existing event?
102  GenericStatsMap::iterator it = generic_stats_.find(event);
103  if (it == generic_stats_.end()) {
104    // New event.
105    start_time_[event] = clock_->NowTicks();
106    generic_stats_.insert(std::make_pair(event, value));
107  } else {
108    // Add to existing (will be used to compute average).
109    it->second += value;
110  }
111   ++counts_[event];
112}
113
114const FrameStatsMap* LoggingStats::GetFrameStatsData() {
115  // Compute framerate and bitrate (when available).
116  FrameStatsMap::iterator it;
117  for (it = frame_stats_.begin(); it != frame_stats_.end(); ++it) {
118    base::TimeDelta time_diff = clock_->NowTicks() - start_time_[it->first];
119    it->second->framerate_fps = counts_[it->first] / time_diff.InSecondsF();
120    if (it->second->bitrate_kbps > 0) {
121      it->second->bitrate_kbps = (8 / 1000) *
122          it->second->bitrate_kbps / time_diff.InSecondsF();
123    }
124    if (it->second->avg_delay_ms > 0)
125      it->second->avg_delay_ms /= counts_[it->first];
126  }
127  return &frame_stats_;
128}
129
130const PacketStatsMap* LoggingStats::GetPacketStatsData() {
131  PacketStatsMap::iterator it;
132  for (it = packet_stats_.begin(); it != packet_stats_.end(); ++it) {
133    if (counts_[it->first] == 0) continue;
134    base::TimeDelta time_diff = clock_->NowTicks() - start_time_[it->first];
135    it->second = (8 / 1000) * it->second / time_diff.InSecondsF();
136  }
137  return &packet_stats_;
138}
139
140const GenericStatsMap* LoggingStats::GetGenericStatsData() {
141  // Compute averages.
142  GenericStatsMap::iterator it;
143  for (it = generic_stats_.begin(); it != generic_stats_.end(); ++it) {
144    it->second /= counts_[ it->first];
145  }
146  return &generic_stats_;
147}
148
149}  // namespace cast
150}  // namespace media
151