Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Side by Side Diff: media/cast/logging/stats_event_subscriber.cc

Issue 236123003: Cast: Provide more meaningful stats. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed miu's comments Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/cast/logging/stats_event_subscriber.h" 5 #include "media/cast/logging/stats_event_subscriber.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/values.h"
9
10 #define STAT_ENUM_TO_STRING(enum) \
11 case enum: \
12 return #enum
8 13
9 namespace media { 14 namespace media {
10 namespace cast { 15 namespace cast {
11 16
12 StatsEventSubscriber::StatsEventSubscriber(EventMediaType event_media_type) 17 namespace {
13 : event_media_type_(event_media_type) {} 18
19 using media::cast::CastLoggingEvent;
20 using media::cast::EventMediaType;
21
22 const size_t kMaxFrameEventTimeMapSize = 100;
23 const size_t kMaxPacketEventTimeMapSize = 1000;
24
25 CastLoggingEvent GetCapturedEvent(EventMediaType media_type) {
26 return media_type == AUDIO_EVENT ? kAudioFrameCaptured : kVideoFrameCaptured;
27 }
28
29 CastLoggingEvent GetEncodedEvent(EventMediaType media_type) {
30 return media_type == AUDIO_EVENT ? kAudioFrameEncoded : kVideoFrameEncoded;
31 }
32
33 CastLoggingEvent GetDecodedEvent(EventMediaType media_type) {
34 return media_type == AUDIO_EVENT ? kAudioFrameDecoded : kVideoFrameDecoded;
35 }
36
37 CastLoggingEvent GetPlayoutEvent(EventMediaType media_type) {
38 return media_type == AUDIO_EVENT ? kAudioPlayoutDelay : kVideoRenderDelay;
39 }
40
41 CastLoggingEvent GetPacketSentEvent(EventMediaType media_type) {
42 return media_type == AUDIO_EVENT ? kAudioPacketSentToNetwork :
43 kVideoPacketSentToNetwork;
44 }
45
46 CastLoggingEvent GetPacketReceivedEvent(EventMediaType media_type) {
47 return media_type == AUDIO_EVENT ? kAudioPacketReceived :
48 kVideoPacketReceived;
49 }
50
51 CastLoggingEvent GetPacketRetransmittedEvent(EventMediaType media_type) {
52 return media_type == AUDIO_EVENT ? kAudioPacketRetransmitted :
53 kVideoPacketRetransmitted;
54 }
55
56 CastLoggingEvent GetRtcpPacketReceivedEvent(EventMediaType media_type) {
57 return media_type == AUDIO_EVENT ? kAudioRtcpPacketReceived :
58 kVideoRtcpPacketReceived;
59 }
60
61 } // namespace
62
63 StatsEventSubscriber::StatsEventSubscriber(
64 EventMediaType event_media_type,
65 base::TickClock* clock,
66 ReceiverTimeOffsetEstimator* offset_estimator)
67 : event_media_type_(event_media_type),
68 clock_(clock),
69 offset_estimator_(offset_estimator),
70 network_latency_datapoints_(0),
71 e2e_latency_datapoints_(0) {
72 DCHECK(event_media_type == AUDIO_EVENT || event_media_type == VIDEO_EVENT);
73 base::TimeTicks now = clock_->NowTicks();
74 start_time_ = now;
75 last_response_received_time_ = now;
76 }
14 77
15 StatsEventSubscriber::~StatsEventSubscriber() { 78 StatsEventSubscriber::~StatsEventSubscriber() {
16 DCHECK(thread_checker_.CalledOnValidThread()); 79 DCHECK(thread_checker_.CalledOnValidThread());
17 } 80 }
18 81
19 void StatsEventSubscriber::OnReceiveFrameEvent(const FrameEvent& frame_event) { 82 void StatsEventSubscriber::OnReceiveFrameEvent(const FrameEvent& frame_event) {
20 DCHECK(thread_checker_.CalledOnValidThread()); 83 DCHECK(thread_checker_.CalledOnValidThread());
21 84
22 CastLoggingEvent type = frame_event.type; 85 CastLoggingEvent type = frame_event.type;
23 if (GetEventMediaType(type) != event_media_type_) 86 if (GetEventMediaType(type) != event_media_type_)
24 return; 87 return;
25 88
26 FrameStatsMap::iterator it = frame_stats_.find(type); 89 FrameStatsMap::iterator it = frame_stats_.find(type);
27 if (it == frame_stats_.end()) { 90 if (it == frame_stats_.end()) {
28 FrameLogStats stats; 91 FrameLogStats stats;
29 stats.first_event_time = frame_event.timestamp;
30 stats.last_event_time = frame_event.timestamp;
31 stats.event_counter = 1; 92 stats.event_counter = 1;
32 stats.sum_size = frame_event.size; 93 stats.sum_size = frame_event.size;
33 stats.min_delay = frame_event.delay_delta;
34 stats.max_delay = frame_event.delay_delta;
35 stats.sum_delay = frame_event.delay_delta; 94 stats.sum_delay = frame_event.delay_delta;
36 frame_stats_.insert(std::make_pair(type, stats)); 95 frame_stats_.insert(std::make_pair(type, stats));
37 } else { 96 } else {
38 ++(it->second.event_counter); 97 ++(it->second.event_counter);
39 it->second.last_event_time = frame_event.timestamp;
40 it->second.sum_size += frame_event.size; 98 it->second.sum_size += frame_event.size;
41 it->second.sum_delay += frame_event.delay_delta; 99 it->second.sum_delay += frame_event.delay_delta;
42 if (frame_event.delay_delta > it->second.max_delay) 100 }
43 it->second.max_delay = frame_event.delay_delta; 101
44 if (frame_event.delay_delta < it->second.min_delay) 102 if (type == GetCapturedEvent(event_media_type_)) {
45 it->second.min_delay = frame_event.delay_delta; 103 RecordFrameCapturedTime(frame_event);
104 } else if (type == GetPlayoutEvent(event_media_type_)) {
105 RecordE2ELatency(frame_event);
46 } 106 }
47 } 107 }
48 108
49 void StatsEventSubscriber::OnReceivePacketEvent( 109 void StatsEventSubscriber::OnReceivePacketEvent(
50 const PacketEvent& packet_event) { 110 const PacketEvent& packet_event) {
51 DCHECK(thread_checker_.CalledOnValidThread()); 111 DCHECK(thread_checker_.CalledOnValidThread());
52 112
53 CastLoggingEvent type = packet_event.type; 113 CastLoggingEvent type = packet_event.type;
54 if (GetEventMediaType(type) != event_media_type_) 114 if (GetEventMediaType(type) != event_media_type_)
55 return; 115 return;
56 116
57 PacketStatsMap::iterator it = packet_stats_.find(type); 117 PacketStatsMap::iterator it = packet_stats_.find(type);
58 if (it == packet_stats_.end()) { 118 if (it == packet_stats_.end()) {
59 PacketLogStats stats; 119 PacketLogStats stats;
60 stats.first_event_time = packet_event.timestamp;
61 stats.last_event_time = packet_event.timestamp;
62 stats.event_counter = 1; 120 stats.event_counter = 1;
63 stats.sum_size = packet_event.size; 121 stats.sum_size = packet_event.size;
64 packet_stats_.insert(std::make_pair(type, stats)); 122 packet_stats_.insert(std::make_pair(type, stats));
65 } else { 123 } else {
66 it->second.last_event_time = packet_event.timestamp;
67 ++(it->second.event_counter); 124 ++(it->second.event_counter);
68 it->second.sum_size += packet_event.size; 125 it->second.sum_size += packet_event.size;
69 } 126 }
127
128 if (type == GetPacketSentEvent(event_media_type_)) {
129 RecordPacketSentTime(packet_event);
130 } else if (type == GetPacketRetransmittedEvent(event_media_type_)) {
131 // We only measure network latency using packets that doesn't have to be
132 // retransmitted as there is precisely one sent-receive timestamp pairs.
133 ErasePacketSentTime(packet_event);
134 } else if (type == GetPacketReceivedEvent(event_media_type_)) {
135 RecordNetworkLatency(packet_event);
136 }
70 } 137 }
71 138
72 void StatsEventSubscriber::OnReceiveGenericEvent( 139 void StatsEventSubscriber::OnReceiveGenericEvent(
73 const GenericEvent& generic_event) { 140 const GenericEvent& generic_event) {
74 DCHECK(thread_checker_.CalledOnValidThread()); 141 DCHECK(thread_checker_.CalledOnValidThread());
75 142
76 CastLoggingEvent type = generic_event.type; 143 CastLoggingEvent type = generic_event.type;
77 if (GetEventMediaType(type) != event_media_type_) 144 if (GetEventMediaType(type) != event_media_type_)
78 return; 145 return;
79 146
80 GenericStatsMap::iterator it = generic_stats_.find(type); 147 if (type == GetRtcpPacketReceivedEvent(event_media_type_))
81 if (it == generic_stats_.end()) { 148 last_response_received_time_ = generic_event.timestamp;
82 GenericLogStats stats; 149 }
83 stats.first_event_time = generic_event.timestamp; 150
84 stats.last_event_time = generic_event.timestamp; 151 scoped_ptr<base::DictionaryValue> StatsEventSubscriber::GetStats() const {
85 stats.event_counter = 1; 152 StatsMap stats_map;
86 stats.sum = generic_event.value; 153 GetStatsInternal(&stats_map);
87 stats.sum_squared = generic_event.value * generic_event.value; 154 scoped_ptr<base::DictionaryValue> ret(new base::DictionaryValue);
88 stats.min = generic_event.value; 155
89 stats.max = generic_event.value; 156 scoped_ptr<base::DictionaryValue> stats(new base::DictionaryValue);
90 generic_stats_.insert(std::make_pair(type, stats)); 157 for (StatsMap::const_iterator it = stats_map.begin(); it != stats_map.end();
91 } else { 158 ++it) {
92 it->second.last_event_time = generic_event.timestamp; 159 stats->SetDouble(CastStatToString(it->first), it->second);
93 ++(it->second.event_counter); 160 }
94 it->second.sum += generic_event.value; 161
95 it->second.sum_squared += generic_event.value * generic_event.value; 162 ret->Set(event_media_type_ == AUDIO_EVENT ? "audio" : "video",
96 if (it->second.min > generic_event.value) { 163 stats.release());
97 it->second.min = generic_event.value; 164
98 } else if (it->second.max < generic_event.value) { 165 return ret.Pass();
99 it->second.max = generic_event.value;
100 }
101 }
102 }
103
104 void StatsEventSubscriber::GetFrameStats(FrameStatsMap* frame_stats_map) const {
105 DCHECK(thread_checker_.CalledOnValidThread());
106 DCHECK(frame_stats_map);
107
108 frame_stats_map->clear();
109 frame_stats_map->insert(frame_stats_.begin(), frame_stats_.end());
110 }
111
112 void StatsEventSubscriber::GetPacketStats(
113 PacketStatsMap* packet_stats_map) const {
114 DCHECK(thread_checker_.CalledOnValidThread());
115 DCHECK(packet_stats_map);
116
117 packet_stats_map->clear();
118 packet_stats_map->insert(packet_stats_.begin(), packet_stats_.end());
119 }
120
121 void StatsEventSubscriber::GetGenericStats(
122 GenericStatsMap* generic_stats_map) const {
123 DCHECK(thread_checker_.CalledOnValidThread());
124 DCHECK(generic_stats_map);
125
126 generic_stats_map->clear();
127 generic_stats_map->insert(generic_stats_.begin(), generic_stats_.end());
128 } 166 }
129 167
130 void StatsEventSubscriber::Reset() { 168 void StatsEventSubscriber::Reset() {
131 DCHECK(thread_checker_.CalledOnValidThread()); 169 DCHECK(thread_checker_.CalledOnValidThread());
132 170
133 frame_stats_.clear(); 171 frame_stats_.clear();
134 packet_stats_.clear(); 172 packet_stats_.clear();
135 generic_stats_.clear(); 173 total_network_latency_ = base::TimeDelta();
136 } 174 network_latency_datapoints_ = 0;
175 total_e2e_latency_ = base::TimeDelta();
176 e2e_latency_datapoints_ = 0;
177 frame_captured_times_.clear();
178 packet_sent_times_.clear();
179 start_time_ = clock_->NowTicks();
180 }
181
182 // static
183 const char* StatsEventSubscriber::CastStatToString(CastStat stat) {
184 switch (stat) {
185 STAT_ENUM_TO_STRING(CAPTURE_FPS);
186 STAT_ENUM_TO_STRING(ENCODE_FPS);
187 STAT_ENUM_TO_STRING(DECODE_FPS);
188 STAT_ENUM_TO_STRING(AVG_ENCODE_TIME_MS);
189 STAT_ENUM_TO_STRING(AVG_PLAYOUT_DELAY_MS);
190 STAT_ENUM_TO_STRING(AVG_NETWORK_LATENCY_MS);
191 STAT_ENUM_TO_STRING(AVG_E2E_LATENCY_MS);
192 STAT_ENUM_TO_STRING(ENCODE_KBPS);
193 STAT_ENUM_TO_STRING(TRANSMISSION_KBPS);
194 STAT_ENUM_TO_STRING(RETRANSMISSION_KBPS);
195 STAT_ENUM_TO_STRING(PACKET_LOSS_FRACTION);
196 STAT_ENUM_TO_STRING(MS_SINCE_LAST_RECEIVER_RESPONSE);
197 }
198 NOTREACHED();
199 return "";
200 }
201
202 void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const {
203 DCHECK(thread_checker_.CalledOnValidThread());
204
205 stats_map->clear();
206
207 base::TimeTicks end_time = clock_->NowTicks();
208
209 PopulateFpsStat(
210 end_time, GetCapturedEvent(event_media_type_), CAPTURE_FPS, stats_map);
211 PopulateFpsStat(
212 end_time, GetEncodedEvent(event_media_type_), ENCODE_FPS, stats_map);
213 PopulateFpsStat(
214 end_time, GetDecodedEvent(event_media_type_), DECODE_FPS, stats_map);
215 PopulatePlayoutDelayStat(stats_map);
216 PopulateFrameBitrateStat(end_time, stats_map);
217 PopulatePacketBitrateStat(end_time,
218 GetPacketSentEvent(event_media_type_),
219 TRANSMISSION_KBPS,
220 stats_map);
221 PopulatePacketBitrateStat(end_time,
222 GetPacketRetransmittedEvent(event_media_type_),
223 RETRANSMISSION_KBPS,
224 stats_map);
225 PopulatePacketLossPercentageStat(stats_map);
226
227 if (network_latency_datapoints_ > 0) {
228 double avg_network_latency_ms =
229 total_network_latency_.InMillisecondsF() /
230 network_latency_datapoints_;
231 stats_map->insert(
232 std::make_pair(AVG_NETWORK_LATENCY_MS, avg_network_latency_ms));
233 }
234
235 if (e2e_latency_datapoints_ > 0) {
236 double avg_e2e_latency_ms =
237 total_e2e_latency_.InMillisecondsF() / e2e_latency_datapoints_;
238 stats_map->insert(std::make_pair(AVG_E2E_LATENCY_MS, avg_e2e_latency_ms));
239 }
240
241 stats_map->insert(
242 std::make_pair(MS_SINCE_LAST_RECEIVER_RESPONSE,
243 (end_time - last_response_received_time_).InMillisecondsF()));
244 }
245
246 bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) {
247 base::TimeDelta receiver_offset_lower_bound;
248 base::TimeDelta receiver_offset_upper_bound;
249 if (!offset_estimator_->GetReceiverOffsetBounds(
250 &receiver_offset_lower_bound, &receiver_offset_upper_bound)) {
251 return false;
252 }
253
254 *offset = (receiver_offset_lower_bound + receiver_offset_upper_bound) / 2;
255 return true;
256 }
257
258 void StatsEventSubscriber::RecordFrameCapturedTime(
259 const FrameEvent& frame_event) {
260 frame_captured_times_.insert(
261 std::make_pair(frame_event.rtp_timestamp, frame_event.timestamp));
262 if (frame_captured_times_.size() > kMaxFrameEventTimeMapSize)
263 frame_captured_times_.erase(frame_captured_times_.begin());
264 }
265
266 void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) {
267 base::TimeDelta receiver_offset;
268 if (!GetReceiverOffset(&receiver_offset))
269 return;
270
271 FrameEventTimeMap::iterator it =
272 frame_captured_times_.find(frame_event.rtp_timestamp);
273 if (it == frame_captured_times_.end())
274 return;
275
276 // Playout time is event time + playout delay.
277 base::TimeTicks playout_time =
278 frame_event.timestamp + frame_event.delay_delta - receiver_offset;
279 total_e2e_latency_ += playout_time - it->second;
280 e2e_latency_datapoints_++;
281 }
282
283 void StatsEventSubscriber::RecordPacketSentTime(
284 const PacketEvent& packet_event) {
285 std::pair<RtpTimestamp, uint16> key(
286 std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id));
287 packet_sent_times_.insert(std::make_pair(key, packet_event.timestamp));
288 if (packet_sent_times_.size() > kMaxPacketEventTimeMapSize)
289 packet_sent_times_.erase(packet_sent_times_.begin());
290 }
291
292 void StatsEventSubscriber::ErasePacketSentTime(
293 const PacketEvent& packet_event) {
294 std::pair<RtpTimestamp, uint16> key(
295 std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id));
296 packet_sent_times_.erase(key);
297 }
298
299 void StatsEventSubscriber::RecordNetworkLatency(
300 const PacketEvent& packet_event) {
301 base::TimeDelta receiver_offset;
302 if (!GetReceiverOffset(&receiver_offset))
303 return;
304
305 std::pair<RtpTimestamp, uint16> key(
306 std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id));
307 PacketEventTimeMap::iterator it = packet_sent_times_.find(key);
308 if (it == packet_sent_times_.end())
309 return;
310 base::TimeTicks packet_sent_time = it->second;
311
312 // Subtract by offset.
313 base::TimeTicks packet_received_time =
314 packet_event.timestamp - receiver_offset;
315
316 total_network_latency_ += packet_received_time - packet_sent_time;
317 network_latency_datapoints_++;
318 }
319
320 void StatsEventSubscriber::PopulateFpsStat(base::TimeTicks end_time,
321 CastLoggingEvent event,
322 CastStat stat,
323 StatsMap* stats_map) const {
324 FrameStatsMap::const_iterator it = frame_stats_.find(event);
325 if (it != frame_stats_.end()) {
326 double fps = 0.0;
327 base::TimeDelta duration = (end_time - start_time_);
328 int count = it->second.event_counter;
329 if (duration.InMicroseconds() != 0)
miu 2014/04/22 19:38:04 nit: if (duration > base::TimeDelta()) {
imcheng 2014/04/22 19:57:26 Done.
330 fps = count / duration.InSecondsF();
331 stats_map->insert(std::make_pair(stat, fps));
332 }
333 }
334
335 void StatsEventSubscriber::PopulatePlayoutDelayStat(StatsMap* stats_map) const {
336 CastLoggingEvent event = GetPlayoutEvent(event_media_type_);
337 FrameStatsMap::const_iterator it = frame_stats_.find(event);
338 if (it != frame_stats_.end()) {
339 double avg_delay_ms = 0.0;
340 base::TimeDelta sum_delay = it->second.sum_delay;
341 int count = it->second.event_counter;
342 if (count != 0)
343 avg_delay_ms = sum_delay.InMillisecondsF() / count;
344 stats_map->insert(std::make_pair(AVG_PLAYOUT_DELAY_MS, avg_delay_ms));
345 }
346 }
347
348 void StatsEventSubscriber::PopulateFrameBitrateStat(base::TimeTicks end_time,
349 StatsMap* stats_map) const {
350 CastLoggingEvent event = GetEncodedEvent(event_media_type_);
351 FrameStatsMap::const_iterator it = frame_stats_.find(event);
352 if (it != frame_stats_.end()) {
353 double kbps = 0.0;
354 base::TimeDelta duration = end_time - start_time_;
355 if (duration.InMicroseconds() != 0) {
miu 2014/04/22 19:38:04 nit: if (duration > base::TimeDelta()) {
imcheng 2014/04/22 19:57:26 Done.
356 kbps = it->second.sum_size / duration.InMillisecondsF() * 8;
357 }
358
359 stats_map->insert(std::make_pair(ENCODE_KBPS, kbps));
360 }
361 }
362
363 void StatsEventSubscriber::PopulatePacketBitrateStat(
364 base::TimeTicks end_time,
365 CastLoggingEvent event,
366 CastStat stat,
367 StatsMap* stats_map) const {
368 PacketStatsMap::const_iterator it = packet_stats_.find(event);
369 if (it != packet_stats_.end()) {
370 double kbps = 0;
371 base::TimeDelta duration = end_time - start_time_;
372 if (duration.InMicroseconds() != 0) {
miu 2014/04/22 19:38:04 nit: if (duration > base::TimeDelta()) {
imcheng 2014/04/22 19:57:26 Done.
373 kbps = it->second.sum_size / duration.InMillisecondsF() * 8;
374 }
375
376 stats_map->insert(std::make_pair(stat, kbps));
377 }
378 }
379
380 void StatsEventSubscriber::PopulatePacketLossPercentageStat(
381 StatsMap* stats_map) const {
382 // We assume that retransmission means that the packet's previous
383 // (re)transmission was lost.
384 // This means the percentage of packet loss is
385 // (# of retransmit events) / (# of transmit + retransmit events).
386 CastLoggingEvent packet_sent_event = GetPacketSentEvent(event_media_type_);
387 CastLoggingEvent packet_retransmitted_event =
388 GetPacketRetransmittedEvent(event_media_type_);
389 PacketStatsMap::const_iterator sent_it =
390 packet_stats_.find(packet_sent_event);
391 if (sent_it == packet_stats_.end())
392 return;
393 PacketStatsMap::const_iterator retransmitted_it =
394 packet_stats_.find(packet_retransmitted_event);
395 int sent_count = sent_it->second.event_counter;
396 int retransmitted_count = 0;
397 if (retransmitted_it != packet_stats_.end())
398 retransmitted_count = retransmitted_it->second.event_counter;
399 double packet_loss_fraction = static_cast<double>(retransmitted_count) /
400 (sent_count + retransmitted_count);
401 stats_map->insert(
402 std::make_pair(PACKET_LOSS_FRACTION, packet_loss_fraction));
403 }
404
405 StatsEventSubscriber::FrameLogStats::FrameLogStats()
406 : event_counter(0), sum_size(0) {}
407 StatsEventSubscriber::FrameLogStats::~FrameLogStats() {}
408
409 StatsEventSubscriber::PacketLogStats::PacketLogStats()
410 : event_counter(0), sum_size(0) {}
411 StatsEventSubscriber::PacketLogStats::~PacketLogStats() {}
137 412
138 } // namespace cast 413 } // namespace cast
139 } // namespace media 414 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/logging/stats_event_subscriber.h ('k') | media/cast/logging/stats_event_subscriber_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698