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