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(DURATION_MS); | |
Alpha Left Google
2014/08/22 01:49:04
This seems redundant since we have first event tim
imcheng
2014/08/22 19:14:17
Removed.
| |
281 STAT_ENUM_TO_STRING(FIRST_EVENT_TIME_MS); | |
282 STAT_ENUM_TO_STRING(LAST_EVENT_TIME_MS); | |
283 STAT_ENUM_TO_STRING(CAPTURE_LATENCY_MS_HISTO); | |
284 STAT_ENUM_TO_STRING(ENCODE_LATENCY_MS_HISTO); | |
285 STAT_ENUM_TO_STRING(PACKET_LATENCY_MS_HISTO); | |
286 STAT_ENUM_TO_STRING(FRAME_LATENCY_MS_HISTO); | |
287 STAT_ENUM_TO_STRING(PLAYOUT_DELAY_MS_HISTO); | |
175 } | 288 } |
176 NOTREACHED(); | 289 NOTREACHED(); |
177 return ""; | 290 return ""; |
178 } | 291 } |
179 | 292 |
293 const int kMaxLatencyBucketMs = 800; | |
294 const int kBucketWidthMs = 20; | |
295 | |
296 void StatsEventSubscriber::InitHistograms() { | |
297 histograms_[CAPTURE_LATENCY_MS_HISTO].reset( | |
298 new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); | |
299 histograms_[ENCODE_LATENCY_MS_HISTO].reset( | |
300 new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); | |
301 histograms_[PACKET_LATENCY_MS_HISTO].reset( | |
302 new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); | |
303 histograms_[FRAME_LATENCY_MS_HISTO].reset( | |
304 new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); | |
305 histograms_[PLAYOUT_DELAY_MS_HISTO].reset( | |
306 new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs)); | |
307 } | |
308 | |
180 void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { | 309 void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { |
181 DCHECK(thread_checker_.CalledOnValidThread()); | 310 DCHECK(thread_checker_.CalledOnValidThread()); |
182 | 311 |
183 stats_map->clear(); | 312 stats_map->clear(); |
184 | 313 |
185 base::TimeTicks end_time = clock_->NowTicks(); | 314 base::TimeTicks end_time = clock_->NowTicks(); |
315 stats_map->insert( | |
316 std::make_pair(DURATION_MS, (end_time - start_time_).InMillisecondsF())); | |
186 | 317 |
187 PopulateFpsStat( | 318 PopulateFpsStat( |
188 end_time, FRAME_CAPTURE_BEGIN, CAPTURE_FPS, stats_map); | 319 end_time, FRAME_CAPTURE_BEGIN, CAPTURE_FPS, stats_map); |
189 PopulateFpsStat( | 320 PopulateFpsStat( |
190 end_time, FRAME_ENCODED, ENCODE_FPS, stats_map); | 321 end_time, FRAME_ENCODED, ENCODE_FPS, stats_map); |
191 PopulateFpsStat( | 322 PopulateFpsStat( |
192 end_time, FRAME_DECODED, DECODE_FPS, stats_map); | 323 end_time, FRAME_DECODED, DECODE_FPS, stats_map); |
193 PopulatePlayoutDelayStat(stats_map); | 324 PopulatePlayoutDelayStat(stats_map); |
194 PopulateFrameBitrateStat(end_time, stats_map); | 325 PopulateFrameBitrateStat(end_time, stats_map); |
195 PopulatePacketBitrateStat(end_time, | 326 PopulatePacketBitrateStat(end_time, |
(...skipping 28 matching lines...) Expand all Loading... | |
224 | 355 |
225 if (!last_response_received_time_.is_null()) { | 356 if (!last_response_received_time_.is_null()) { |
226 stats_map->insert( | 357 stats_map->insert( |
227 std::make_pair(MS_SINCE_LAST_RECEIVER_RESPONSE, | 358 std::make_pair(MS_SINCE_LAST_RECEIVER_RESPONSE, |
228 (end_time - last_response_received_time_).InMillisecondsF())); | 359 (end_time - last_response_received_time_).InMillisecondsF())); |
229 } | 360 } |
230 | 361 |
231 stats_map->insert(std::make_pair(NUM_FRAMES_DROPPED_BY_ENCODER, | 362 stats_map->insert(std::make_pair(NUM_FRAMES_DROPPED_BY_ENCODER, |
232 num_frames_dropped_by_encoder_)); | 363 num_frames_dropped_by_encoder_)); |
233 stats_map->insert(std::make_pair(NUM_FRAMES_LATE, num_frames_late_)); | 364 stats_map->insert(std::make_pair(NUM_FRAMES_LATE, num_frames_late_)); |
365 stats_map->insert(std::make_pair( | |
366 FIRST_EVENT_TIME_MS, | |
367 (first_event_time_ - base::TimeTicks::UnixEpoch()).InMillisecondsF())); | |
368 stats_map->insert(std::make_pair( | |
369 LAST_EVENT_TIME_MS, | |
370 (last_event_time_ - base::TimeTicks::UnixEpoch()).InMillisecondsF())); | |
234 } | 371 } |
235 | 372 |
236 bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) { | 373 bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) { |
237 base::TimeDelta receiver_offset_lower_bound; | 374 base::TimeDelta receiver_offset_lower_bound; |
238 base::TimeDelta receiver_offset_upper_bound; | 375 base::TimeDelta receiver_offset_upper_bound; |
239 if (!offset_estimator_->GetReceiverOffsetBounds( | 376 if (!offset_estimator_->GetReceiverOffsetBounds( |
240 &receiver_offset_lower_bound, &receiver_offset_upper_bound)) { | 377 &receiver_offset_lower_bound, &receiver_offset_upper_bound)) { |
241 return false; | 378 return false; |
242 } | 379 } |
243 | 380 |
244 *offset = (receiver_offset_lower_bound + receiver_offset_upper_bound) / 2; | 381 *offset = (receiver_offset_lower_bound + receiver_offset_upper_bound) / 2; |
245 return true; | 382 return true; |
246 } | 383 } |
247 | 384 |
385 void StatsEventSubscriber::MaybeInsertFrameInfo(RtpTimestamp rtp_timestamp, | |
386 const FrameInfo& frame_info) { | |
387 // No need to insert if |rtp_timestamp| is the smaller than every key in the | |
388 // map as it is just going to get erased anyway. | |
389 if (recent_frame_infos_.size() == kMaxFrameInfoMapSize && | |
390 rtp_timestamp < recent_frame_infos_.begin()->first) { | |
391 return; | |
392 } | |
393 | |
394 recent_frame_infos_.insert(std::make_pair(rtp_timestamp, frame_info)); | |
395 | |
396 if (recent_frame_infos_.size() >= kMaxFrameInfoMapSize) { | |
397 FrameInfoMap::iterator erase_it = recent_frame_infos_.begin(); | |
398 if (erase_it->second.encode_time.is_null()) | |
399 num_frames_dropped_by_encoder_++; | |
400 recent_frame_infos_.erase(erase_it); | |
401 } | |
402 } | |
403 | |
248 void StatsEventSubscriber::RecordFrameCaptureTime( | 404 void StatsEventSubscriber::RecordFrameCaptureTime( |
249 const FrameEvent& frame_event) { | 405 const FrameEvent& frame_event) { |
250 recent_captured_frames_.insert(std::make_pair( | 406 FrameInfo frame_info; |
251 frame_event.rtp_timestamp, FrameInfo(frame_event.timestamp))); | 407 frame_info.capture_time = frame_event.timestamp; |
252 if (recent_captured_frames_.size() > kMaxFrameInfoMapSize) { | 408 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 } | 409 } |
259 | 410 |
260 void StatsEventSubscriber::MarkAsEncoded(RtpTimestamp rtp_timestamp) { | 411 void StatsEventSubscriber::RecordCaptureLatency(const FrameEvent& frame_event) { |
261 FrameInfoMap::iterator it = recent_captured_frames_.find(rtp_timestamp); | 412 FrameInfoMap::iterator it = |
262 if (it != recent_captured_frames_.end()) | 413 recent_frame_infos_.find(frame_event.rtp_timestamp); |
263 it->second.encoded = true; | 414 if (it == recent_frame_infos_.end()) |
415 return; | |
416 | |
417 if (!it->second.capture_time.is_null()) { | |
418 double capture_latency_ms = | |
419 (it->second.capture_time - frame_event.timestamp).InMillisecondsF(); | |
420 histograms_[CAPTURE_LATENCY_MS_HISTO]->Add(capture_latency_ms); | |
421 } | |
422 | |
423 it->second.capture_end_time = frame_event.timestamp; | |
424 } | |
425 | |
426 void StatsEventSubscriber::RecordEncodeLatency(const FrameEvent& frame_event) { | |
427 FrameInfoMap::iterator it = | |
428 recent_frame_infos_.find(frame_event.rtp_timestamp); | |
429 if (it == recent_frame_infos_.end()) { | |
430 FrameInfo frame_info; | |
431 frame_info.encode_time = frame_event.timestamp; | |
432 MaybeInsertFrameInfo(frame_event.rtp_timestamp, frame_info); | |
433 return; | |
434 } | |
435 | |
436 if (!it->second.capture_end_time.is_null()) { | |
437 double encode_latency_ms = | |
438 (frame_event.timestamp - it->second.capture_end_time).InMillisecondsF(); | |
439 histograms_[ENCODE_LATENCY_MS_HISTO]->Add(encode_latency_ms); | |
440 } | |
441 | |
442 it->second.encode_time = frame_event.timestamp; | |
443 } | |
444 | |
445 void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) { | |
446 FrameInfoMap::iterator it = | |
447 recent_frame_infos_.find(frame_event.rtp_timestamp); | |
448 if (it == recent_frame_infos_.end()) | |
449 return; | |
450 | |
451 if (it->second.encode_time.is_null()) | |
452 return; | |
453 | |
454 base::TimeDelta receiver_offset; | |
455 if (!GetReceiverOffset(&receiver_offset)) | |
456 return; | |
457 | |
458 base::TimeTicks sender_time = frame_event.timestamp - receiver_offset; | |
459 double frame_tx_latency_ms = | |
460 (sender_time - it->second.encode_time).InMillisecondsF(); | |
461 histograms_[FRAME_LATENCY_MS_HISTO]->Add(frame_tx_latency_ms); | |
264 } | 462 } |
265 | 463 |
266 void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { | 464 void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { |
267 base::TimeDelta receiver_offset; | 465 base::TimeDelta receiver_offset; |
268 if (!GetReceiverOffset(&receiver_offset)) | 466 if (!GetReceiverOffset(&receiver_offset)) |
269 return; | 467 return; |
270 | 468 |
271 FrameInfoMap::iterator it = | 469 FrameInfoMap::iterator it = |
272 recent_captured_frames_.find(frame_event.rtp_timestamp); | 470 recent_frame_infos_.find(frame_event.rtp_timestamp); |
273 if (it == recent_captured_frames_.end()) | 471 if (it == recent_frame_infos_.end()) |
274 return; | 472 return; |
275 | 473 |
276 // Playout time is event time + playout delay. | 474 // Playout time is event time + playout delay. |
277 base::TimeTicks playout_time = | 475 base::TimeTicks playout_time = |
278 frame_event.timestamp + frame_event.delay_delta - receiver_offset; | 476 frame_event.timestamp + frame_event.delay_delta - receiver_offset; |
279 total_e2e_latency_ += playout_time - it->second.capture_time; | 477 total_e2e_latency_ += playout_time - it->second.capture_time; |
280 e2e_latency_datapoints_++; | 478 e2e_latency_datapoints_++; |
281 } | 479 } |
282 | 480 |
283 void StatsEventSubscriber::UpdateLastResponseTime( | 481 void StatsEventSubscriber::UpdateLastResponseTime( |
(...skipping 15 matching lines...) Expand all Loading... | |
299 void StatsEventSubscriber::RecordNetworkLatency( | 497 void StatsEventSubscriber::RecordNetworkLatency( |
300 const PacketEvent& packet_event) { | 498 const PacketEvent& packet_event) { |
301 base::TimeDelta receiver_offset; | 499 base::TimeDelta receiver_offset; |
302 if (!GetReceiverOffset(&receiver_offset)) | 500 if (!GetReceiverOffset(&receiver_offset)) |
303 return; | 501 return; |
304 | 502 |
305 std::pair<RtpTimestamp, uint16> key( | 503 std::pair<RtpTimestamp, uint16> key( |
306 std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id)); | 504 std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id)); |
307 PacketEventTimeMap::iterator it = packet_sent_times_.find(key); | 505 PacketEventTimeMap::iterator it = packet_sent_times_.find(key); |
308 if (it == packet_sent_times_.end()) { | 506 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 = | 507 std::pair<base::TimeTicks, CastLoggingEvent> value = |
312 std::make_pair(packet_event.timestamp, packet_event.type); | 508 std::make_pair(packet_event.timestamp, packet_event.type); |
313 packet_sent_times_.insert(std::make_pair(key, value)); | 509 packet_sent_times_.insert(std::make_pair(key, value)); |
314 if (packet_sent_times_.size() > kMaxPacketEventTimeMapSize) | 510 if (packet_sent_times_.size() > kMaxPacketEventTimeMapSize) |
315 packet_sent_times_.erase(packet_sent_times_.begin()); | 511 packet_sent_times_.erase(packet_sent_times_.begin()); |
316 } else { | 512 } else { |
317 std::pair<base::TimeTicks, CastLoggingEvent> value = it->second; | 513 std::pair<base::TimeTicks, CastLoggingEvent> value = it->second; |
318 CastLoggingEvent recorded_type = value.second; | 514 CastLoggingEvent recorded_type = value.second; |
319 bool match = false; | 515 bool match = false; |
320 base::TimeTicks packet_sent_time; | 516 base::TimeTicks packet_sent_time; |
321 base::TimeTicks packet_received_time; | 517 base::TimeTicks packet_received_time; |
322 if (recorded_type == PACKET_SENT_TO_NETWORK && | 518 if (recorded_type == PACKET_SENT_TO_NETWORK && |
323 packet_event.type == PACKET_RECEIVED) { | 519 packet_event.type == PACKET_RECEIVED) { |
324 packet_sent_time = value.first; | 520 packet_sent_time = value.first; |
325 packet_received_time = packet_event.timestamp; | 521 packet_received_time = packet_event.timestamp; |
326 match = true; | 522 match = true; |
327 } else if (recorded_type == PACKET_RECEIVED && | 523 } else if (recorded_type == PACKET_RECEIVED && |
328 packet_event.type == PACKET_SENT_TO_NETWORK) { | 524 packet_event.type == PACKET_SENT_TO_NETWORK) { |
329 packet_sent_time = packet_event.timestamp; | 525 packet_sent_time = packet_event.timestamp; |
330 packet_received_time = value.first; | 526 packet_received_time = value.first; |
331 match = true; | 527 match = true; |
332 } | 528 } |
333 if (match) { | 529 if (match) { |
334 // Subtract by offset. | 530 // Subtract by offset. |
335 packet_received_time -= receiver_offset; | 531 packet_received_time -= receiver_offset; |
532 base::TimeDelta latency_delta = packet_received_time - packet_sent_time; | |
336 | 533 |
337 total_network_latency_ += packet_received_time - packet_sent_time; | 534 total_network_latency_ += latency_delta; |
338 network_latency_datapoints_++; | 535 network_latency_datapoints_++; |
536 | |
537 histograms_[PACKET_LATENCY_MS_HISTO]->Add( | |
538 latency_delta.InMillisecondsF()); | |
539 | |
339 packet_sent_times_.erase(it); | 540 packet_sent_times_.erase(it); |
340 } | 541 } |
341 } | 542 } |
342 } | 543 } |
343 | 544 |
344 void StatsEventSubscriber::PopulateFpsStat(base::TimeTicks end_time, | 545 void StatsEventSubscriber::PopulateFpsStat(base::TimeTicks end_time, |
345 CastLoggingEvent event, | 546 CastLoggingEvent event, |
346 CastStat stat, | 547 CastStat stat, |
347 StatsMap* stats_map) const { | 548 StatsMap* stats_map) const { |
348 FrameStatsMap::const_iterator it = frame_stats_.find(event); | 549 FrameStatsMap::const_iterator it = frame_stats_.find(event); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
440 } | 641 } |
441 | 642 |
442 StatsEventSubscriber::FrameLogStats::FrameLogStats() | 643 StatsEventSubscriber::FrameLogStats::FrameLogStats() |
443 : event_counter(0), sum_size(0) {} | 644 : event_counter(0), sum_size(0) {} |
444 StatsEventSubscriber::FrameLogStats::~FrameLogStats() {} | 645 StatsEventSubscriber::FrameLogStats::~FrameLogStats() {} |
445 | 646 |
446 StatsEventSubscriber::PacketLogStats::PacketLogStats() | 647 StatsEventSubscriber::PacketLogStats::PacketLogStats() |
447 : event_counter(0), sum_size(0) {} | 648 : event_counter(0), sum_size(0) {} |
448 StatsEventSubscriber::PacketLogStats::~PacketLogStats() {} | 649 StatsEventSubscriber::PacketLogStats::~PacketLogStats() {} |
449 | 650 |
450 StatsEventSubscriber::FrameInfo::FrameInfo(base::TimeTicks capture_time) | 651 StatsEventSubscriber::FrameInfo::FrameInfo() : encoded(false) { |
451 : capture_time(capture_time), encoded(false) { | |
452 } | 652 } |
453 StatsEventSubscriber::FrameInfo::~FrameInfo() { | 653 StatsEventSubscriber::FrameInfo::~FrameInfo() { |
454 } | 654 } |
455 | 655 |
456 } // namespace cast | 656 } // namespace cast |
457 } // namespace media | 657 } // namespace media |
OLD | NEW |