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/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) { | |
hubbe
2014/04/15 00:23:22
Ouch, this level of repetition hurts my brain.
imcheng
2014/04/15 01:18:36
I can't think of much that can be done here. This
miu
2014/04/15 21:29:43
Suggestion (you probably want to put this in the h
imcheng
2014/04/17 19:19:06
Honestly I am not a huge fan of macros in a situat
miu
2014/04/18 00:02:03
Thinking about this some more, the real problem is
imcheng
2014/04/18 18:20:27
Yes, it is unfortunate that we have split event ty
| |
26 if (media_type == AUDIO_EVENT) | |
27 return kAudioFrameCaptured; | |
28 else | |
29 return kVideoFrameCaptured; | |
30 } | |
31 | |
32 CastLoggingEvent GetEncodedEvent(EventMediaType media_type) { | |
33 if (media_type == AUDIO_EVENT) | |
34 return kAudioFrameEncoded; | |
35 else | |
36 return kVideoFrameEncoded; | |
37 } | |
38 | |
39 CastLoggingEvent GetDecodedEvent(EventMediaType media_type) { | |
40 if (media_type == AUDIO_EVENT) | |
41 return kAudioFrameDecoded; | |
42 else | |
43 return kVideoFrameDecoded; | |
44 } | |
45 | |
46 CastLoggingEvent GetPlayoutEvent(EventMediaType media_type) { | |
47 if (media_type == AUDIO_EVENT) | |
48 return kAudioPlayoutDelay; | |
49 else | |
50 return kVideoRenderDelay; | |
51 } | |
52 | |
53 CastLoggingEvent GetPacketSentEvent(EventMediaType media_type) { | |
54 if (media_type == AUDIO_EVENT) | |
55 return kAudioPacketSentToNetwork; | |
56 else | |
57 return kVideoPacketSentToNetwork; | |
58 } | |
59 | |
60 CastLoggingEvent GetPacketReceivedEvent(EventMediaType media_type) { | |
61 if (media_type == AUDIO_EVENT) | |
62 return kAudioPacketReceived; | |
63 else | |
64 return kVideoPacketReceived; | |
65 } | |
66 | |
67 CastLoggingEvent GetPacketRetransmittedEvent(EventMediaType media_type) { | |
68 if (media_type == AUDIO_EVENT) | |
69 return kAudioPacketRetransmitted; | |
70 else | |
71 return kVideoPacketRetransmitted; | |
72 } | |
73 | |
74 } // namespace | |
75 | |
76 StatsEventSubscriber::StatsEventSubscriber( | |
77 EventMediaType event_media_type, | |
78 base::TickClock* clock, | |
79 ReceiverTimeOffsetEstimator* offset_estimator) | |
80 : event_media_type_(event_media_type), | |
81 total_network_latency_ms_(0), | |
82 network_latency_datapoints_(0), | |
83 total_e2e_latency_ms_(0), | |
84 e2e_latency_datapoints_(0), | |
85 start_time_(clock->NowTicks()), | |
86 clock_(clock), | |
87 offset_estimator_(offset_estimator) { | |
88 DCHECK(event_media_type == AUDIO_EVENT || event_media_type == VIDEO_EVENT); | |
89 } | |
14 | 90 |
15 StatsEventSubscriber::~StatsEventSubscriber() { | 91 StatsEventSubscriber::~StatsEventSubscriber() { |
16 DCHECK(thread_checker_.CalledOnValidThread()); | 92 DCHECK(thread_checker_.CalledOnValidThread()); |
17 } | 93 } |
18 | 94 |
19 void StatsEventSubscriber::OnReceiveFrameEvent(const FrameEvent& frame_event) { | 95 void StatsEventSubscriber::OnReceiveFrameEvent(const FrameEvent& frame_event) { |
20 DCHECK(thread_checker_.CalledOnValidThread()); | 96 DCHECK(thread_checker_.CalledOnValidThread()); |
21 | 97 |
22 CastLoggingEvent type = frame_event.type; | 98 CastLoggingEvent type = frame_event.type; |
23 if (GetEventMediaType(type) != event_media_type_) | 99 if (GetEventMediaType(type) != event_media_type_) |
24 return; | 100 return; |
25 | 101 |
26 FrameStatsMap::iterator it = frame_stats_.find(type); | 102 FrameStatsMap::iterator it = frame_stats_.find(type); |
27 if (it == frame_stats_.end()) { | 103 if (it == frame_stats_.end()) { |
28 FrameLogStats stats; | 104 FrameLogStats stats; |
29 stats.first_event_time = frame_event.timestamp; | |
30 stats.last_event_time = frame_event.timestamp; | |
31 stats.event_counter = 1; | 105 stats.event_counter = 1; |
32 stats.sum_size = frame_event.size; | 106 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; | 107 stats.sum_delay = frame_event.delay_delta; |
36 frame_stats_.insert(std::make_pair(type, stats)); | 108 frame_stats_.insert(std::make_pair(type, stats)); |
37 } else { | 109 } else { |
38 ++(it->second.event_counter); | 110 ++(it->second.event_counter); |
39 it->second.last_event_time = frame_event.timestamp; | |
40 it->second.sum_size += frame_event.size; | 111 it->second.sum_size += frame_event.size; |
41 it->second.sum_delay += frame_event.delay_delta; | 112 it->second.sum_delay += frame_event.delay_delta; |
42 if (frame_event.delay_delta > it->second.max_delay) | 113 } |
43 it->second.max_delay = frame_event.delay_delta; | 114 |
44 if (frame_event.delay_delta < it->second.min_delay) | 115 if (type == GetCapturedEvent(event_media_type_)) { |
45 it->second.min_delay = frame_event.delay_delta; | 116 RecordFrameCapturedTime(frame_event); |
117 } else if (type == GetPlayoutEvent(event_media_type_)) { | |
118 RecordE2ELatency(frame_event); | |
46 } | 119 } |
47 } | 120 } |
48 | 121 |
49 void StatsEventSubscriber::OnReceivePacketEvent( | 122 void StatsEventSubscriber::OnReceivePacketEvent( |
50 const PacketEvent& packet_event) { | 123 const PacketEvent& packet_event) { |
51 DCHECK(thread_checker_.CalledOnValidThread()); | 124 DCHECK(thread_checker_.CalledOnValidThread()); |
52 | 125 |
53 CastLoggingEvent type = packet_event.type; | 126 CastLoggingEvent type = packet_event.type; |
54 if (GetEventMediaType(type) != event_media_type_) | 127 if (GetEventMediaType(type) != event_media_type_) |
55 return; | 128 return; |
56 | 129 |
57 PacketStatsMap::iterator it = packet_stats_.find(type); | 130 PacketStatsMap::iterator it = packet_stats_.find(type); |
58 if (it == packet_stats_.end()) { | 131 if (it == packet_stats_.end()) { |
59 PacketLogStats stats; | 132 PacketLogStats stats; |
60 stats.first_event_time = packet_event.timestamp; | |
61 stats.last_event_time = packet_event.timestamp; | |
62 stats.event_counter = 1; | 133 stats.event_counter = 1; |
63 stats.sum_size = packet_event.size; | 134 stats.sum_size = packet_event.size; |
64 packet_stats_.insert(std::make_pair(type, stats)); | 135 packet_stats_.insert(std::make_pair(type, stats)); |
65 } else { | 136 } else { |
66 it->second.last_event_time = packet_event.timestamp; | |
67 ++(it->second.event_counter); | 137 ++(it->second.event_counter); |
68 it->second.sum_size += packet_event.size; | 138 it->second.sum_size += packet_event.size; |
69 } | 139 } |
140 | |
141 if (type == GetPacketSentEvent(event_media_type_)) { | |
142 RecordPacketSentTime(packet_event); | |
143 } else if (type == GetPacketRetransmittedEvent(event_media_type_)) { | |
144 // We only measure network latency using packets that doesn't have to be | |
145 // retransmitted as there is precisely one sent-receive timestamp pairs. | |
146 ErasePacketSentTime(packet_event); | |
147 } else if (type == GetPacketReceivedEvent(event_media_type_)) { | |
148 RecordNetworkLatency(packet_event); | |
149 } | |
70 } | 150 } |
71 | 151 |
72 void StatsEventSubscriber::OnReceiveGenericEvent( | 152 void StatsEventSubscriber::OnReceiveGenericEvent( |
73 const GenericEvent& generic_event) { | 153 const GenericEvent& generic_event) { |
74 DCHECK(thread_checker_.CalledOnValidThread()); | 154 DCHECK(thread_checker_.CalledOnValidThread()); |
75 | 155 // Not interested in generic events. |
76 CastLoggingEvent type = generic_event.type; | 156 } |
77 if (GetEventMediaType(type) != event_media_type_) | 157 |
78 return; | 158 scoped_ptr<base::DictionaryValue> StatsEventSubscriber::GetStats() const { |
79 | 159 StatsMap stats_map; |
80 GenericStatsMap::iterator it = generic_stats_.find(type); | 160 GetStatsInternal(&stats_map); |
81 if (it == generic_stats_.end()) { | 161 scoped_ptr<base::DictionaryValue> ret(new base::DictionaryValue); |
82 GenericLogStats stats; | 162 |
83 stats.first_event_time = generic_event.timestamp; | 163 scoped_ptr<base::DictionaryValue> stats(new base::DictionaryValue); |
84 stats.last_event_time = generic_event.timestamp; | 164 for (StatsMap::const_iterator it = stats_map.begin(); it != stats_map.end(); |
85 stats.event_counter = 1; | 165 ++it) { |
86 stats.sum = generic_event.value; | 166 stats->SetDouble(CastStatToString(it->first), it->second); |
87 stats.sum_squared = generic_event.value * generic_event.value; | 167 } |
88 stats.min = generic_event.value; | 168 |
89 stats.max = generic_event.value; | 169 ret->Set(event_media_type_ == AUDIO_EVENT ? "audio" : "video", |
90 generic_stats_.insert(std::make_pair(type, stats)); | 170 stats.release()); |
91 } else { | 171 |
92 it->second.last_event_time = generic_event.timestamp; | 172 return ret.Pass(); |
93 ++(it->second.event_counter); | |
94 it->second.sum += generic_event.value; | |
95 it->second.sum_squared += generic_event.value * generic_event.value; | |
96 if (it->second.min > generic_event.value) { | |
97 it->second.min = generic_event.value; | |
98 } else if (it->second.max < generic_event.value) { | |
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 } | 173 } |
129 | 174 |
130 void StatsEventSubscriber::Reset() { | 175 void StatsEventSubscriber::Reset() { |
131 DCHECK(thread_checker_.CalledOnValidThread()); | 176 DCHECK(thread_checker_.CalledOnValidThread()); |
132 | 177 |
133 frame_stats_.clear(); | 178 frame_stats_.clear(); |
134 packet_stats_.clear(); | 179 packet_stats_.clear(); |
135 generic_stats_.clear(); | 180 total_network_latency_ms_ = 0; |
136 } | 181 network_latency_datapoints_ = 0; |
182 total_e2e_latency_ms_ = 0; | |
183 e2e_latency_datapoints_ = 0; | |
184 frame_captured_times_.clear(); | |
185 packet_sent_times_.clear(); | |
186 start_time_ = clock_->NowTicks(); | |
187 } | |
188 | |
189 // static | |
190 const char* StatsEventSubscriber::CastStatToString(CastStat stat) { | |
191 switch (stat) { | |
192 STAT_ENUM_TO_STRING(CAPTURE_FPS); | |
193 STAT_ENUM_TO_STRING(ENCODE_FPS); | |
194 STAT_ENUM_TO_STRING(DECODE_FPS); | |
195 STAT_ENUM_TO_STRING(AVG_ENCODE_TIME_MS); | |
196 STAT_ENUM_TO_STRING(AVG_PLAYOUT_DELAY_MS); | |
197 STAT_ENUM_TO_STRING(AVG_NETWORK_LATENCY_MS); | |
198 STAT_ENUM_TO_STRING(AVG_E2E_LATENCY_MS); | |
199 STAT_ENUM_TO_STRING(ENCODE_KBPS); | |
200 STAT_ENUM_TO_STRING(TRANSMISSION_KBPS); | |
201 STAT_ENUM_TO_STRING(RETRANSMISSION_KBPS); | |
202 STAT_ENUM_TO_STRING(PACKET_LOSS_PERCENTAGE); | |
203 } | |
204 NOTREACHED(); | |
205 return ""; | |
206 } | |
207 | |
208 void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const { | |
209 DCHECK(thread_checker_.CalledOnValidThread()); | |
210 | |
211 stats_map->clear(); | |
212 | |
213 base::TimeTicks end_time = clock_->NowTicks(); | |
214 | |
215 PopulateFpsStat( | |
216 end_time, GetCapturedEvent(event_media_type_), CAPTURE_FPS, stats_map); | |
217 PopulateFpsStat( | |
218 end_time, GetEncodedEvent(event_media_type_), ENCODE_FPS, stats_map); | |
219 PopulateFpsStat( | |
220 end_time, GetDecodedEvent(event_media_type_), DECODE_FPS, stats_map); | |
221 PopulatePlayoutDelayStat(stats_map); | |
222 PopulateFrameBitrateStat(end_time, stats_map); | |
223 PopulatePacketBitrateStat(end_time, | |
224 GetPacketSentEvent(event_media_type_), | |
225 TRANSMISSION_KBPS, | |
226 stats_map); | |
227 PopulatePacketBitrateStat(end_time, | |
228 GetPacketRetransmittedEvent(event_media_type_), | |
229 RETRANSMISSION_KBPS, | |
230 stats_map); | |
231 PopulatePacketLossPercentageStat(stats_map); | |
232 | |
233 if (network_latency_datapoints_ > 0) { | |
234 double avg_network_latency_ms = | |
235 static_cast<double>(total_network_latency_ms_) / | |
236 network_latency_datapoints_; | |
237 stats_map->insert( | |
238 std::make_pair(AVG_NETWORK_LATENCY_MS, avg_network_latency_ms)); | |
239 } | |
240 | |
241 if (e2e_latency_datapoints_ > 0) { | |
242 double avg_e2e_latency_ms = | |
243 static_cast<double>(total_e2e_latency_ms_) / e2e_latency_datapoints_; | |
244 stats_map->insert(std::make_pair(AVG_E2E_LATENCY_MS, avg_e2e_latency_ms)); | |
245 } | |
246 } | |
247 | |
248 bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) { | |
249 base::TimeDelta receiver_offset_lower_bound; | |
250 base::TimeDelta receiver_offset_upper_bound; | |
251 if (!offset_estimator_->GetReceiverOffsetBounds( | |
252 &receiver_offset_lower_bound, &receiver_offset_upper_bound)) { | |
253 return false; | |
254 } | |
255 | |
256 *offset = (receiver_offset_lower_bound + receiver_offset_upper_bound) / 2; | |
257 return true; | |
258 } | |
259 | |
260 void StatsEventSubscriber::RecordFrameCapturedTime( | |
261 const FrameEvent& frame_event) { | |
262 frame_captured_times_.insert( | |
263 std::make_pair(frame_event.rtp_timestamp, frame_event.timestamp)); | |
264 if (frame_captured_times_.size() > kMaxFrameEventTimeMapSize) | |
265 frame_captured_times_.erase(frame_captured_times_.begin()); | |
266 } | |
267 | |
268 void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) { | |
269 base::TimeDelta receiver_offset; | |
270 if (!GetReceiverOffset(&receiver_offset)) | |
271 return; | |
272 | |
273 FrameEventTimeMap::iterator it = | |
274 frame_captured_times_.find(frame_event.rtp_timestamp); | |
275 if (it == frame_captured_times_.end()) | |
276 return; | |
277 | |
278 // Playout time is event time + playout delay. | |
279 base::TimeTicks playout_time = | |
280 frame_event.timestamp + frame_event.delay_delta - receiver_offset; | |
281 int64 e2e_latency_ms = (playout_time - it->second).InMilliseconds(); | |
282 | |
283 // Bogus value - probably because the offset value has not stabilized enough | |
284 // yet. | |
285 if (e2e_latency_ms <= 0) | |
286 return; | |
287 | |
288 total_e2e_latency_ms_ += e2e_latency_ms; | |
289 e2e_latency_datapoints_++; | |
290 } | |
291 | |
292 void StatsEventSubscriber::RecordPacketSentTime( | |
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_.insert(std::make_pair(key, packet_event.timestamp)); | |
297 if (packet_sent_times_.size() > kMaxPacketEventTimeMapSize) | |
298 packet_sent_times_.erase(packet_sent_times_.begin()); | |
299 } | |
300 | |
301 void StatsEventSubscriber::ErasePacketSentTime( | |
302 const PacketEvent& packet_event) { | |
303 std::pair<RtpTimestamp, uint16> key( | |
304 std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id)); | |
305 packet_sent_times_.erase(key); | |
306 } | |
307 | |
308 void StatsEventSubscriber::RecordNetworkLatency( | |
309 const PacketEvent& packet_event) { | |
310 base::TimeDelta receiver_offset; | |
311 if (!GetReceiverOffset(&receiver_offset)) | |
312 return; | |
313 | |
314 base::TimeTicks packet_sent_time; | |
315 std::pair<RtpTimestamp, uint16> key( | |
316 std::make_pair(packet_event.rtp_timestamp, packet_event.packet_id)); | |
317 PacketEventTimeMap::iterator it = packet_sent_times_.find(key); | |
318 if (it == packet_sent_times_.end()) | |
319 return; | |
320 packet_sent_time = it->second; | |
321 | |
322 // Subtract by offset. | |
323 base::TimeTicks packet_received_time = | |
324 packet_event.timestamp - receiver_offset; | |
325 | |
326 int64 latency_ms = (packet_received_time - packet_sent_time).InMilliseconds(); | |
327 | |
328 // Bogus value - probably because the offset value has not stabilized enough | |
329 // yet. | |
330 if (latency_ms <= 0) | |
331 return; | |
332 | |
333 total_network_latency_ms_ += latency_ms; | |
334 network_latency_datapoints_++; | |
335 } | |
336 | |
337 void StatsEventSubscriber::PopulateFpsStat(base::TimeTicks end_time, | |
338 CastLoggingEvent event, | |
339 CastStat stat, | |
340 StatsMap* stats_map) const { | |
341 FrameStatsMap::const_iterator it = frame_stats_.find(event); | |
342 if (it != frame_stats_.end()) { | |
343 double fps = 0.0; | |
344 int64 duration_ms = (end_time - start_time_).InMilliseconds(); | |
345 int count = it->second.event_counter; | |
346 if (duration_ms != 0 && count != 0) | |
347 fps = static_cast<double>(count) / duration_ms * 1000; | |
348 stats_map->insert(std::make_pair(stat, fps)); | |
349 } | |
350 } | |
351 | |
352 void StatsEventSubscriber::PopulatePlayoutDelayStat(StatsMap* stats_map) const { | |
353 CastLoggingEvent event = GetPlayoutEvent(event_media_type_); | |
354 FrameStatsMap::const_iterator it = frame_stats_.find(event); | |
355 if (it != frame_stats_.end()) { | |
356 double avg_delay_ms = 0.0; | |
357 int64 sum_delay_ms = it->second.sum_delay.InMilliseconds(); | |
358 int count = it->second.event_counter; | |
359 if (sum_delay_ms != 0 && count != 0) | |
360 avg_delay_ms = static_cast<double>(sum_delay_ms) / count; | |
361 stats_map->insert(std::make_pair(AVG_PLAYOUT_DELAY_MS, avg_delay_ms)); | |
362 } | |
363 } | |
364 | |
365 void StatsEventSubscriber::PopulateFrameBitrateStat(base::TimeTicks end_time, | |
366 StatsMap* stats_map) const { | |
367 CastLoggingEvent event = GetEncodedEvent(event_media_type_); | |
368 FrameStatsMap::const_iterator it = frame_stats_.find(event); | |
369 if (it != frame_stats_.end()) { | |
370 double kbps = 0; | |
371 int64 duration_ms = (end_time - start_time_).InMilliseconds(); | |
372 if (it->second.sum_size != 0 && duration_ms != 0) { | |
373 kbps = static_cast<double>(it->second.sum_size) / duration_ms * 8; | |
374 } | |
375 | |
376 stats_map->insert(std::make_pair(ENCODE_KBPS, kbps)); | |
377 } | |
378 } | |
379 | |
380 void StatsEventSubscriber::PopulatePacketBitrateStat( | |
381 base::TimeTicks end_time, | |
382 CastLoggingEvent event, | |
383 CastStat stat, | |
384 StatsMap* stats_map) const { | |
385 PacketStatsMap::const_iterator it = packet_stats_.find(event); | |
386 if (it != packet_stats_.end()) { | |
387 double kbps = 0; | |
388 int64 duration_ms = (end_time - start_time_).InMilliseconds(); | |
389 if (it->second.sum_size != 0 && duration_ms != 0) { | |
390 kbps = static_cast<double>(it->second.sum_size) / duration_ms * 8; | |
391 } | |
392 | |
393 stats_map->insert(std::make_pair(stat, kbps)); | |
394 } | |
395 } | |
396 | |
397 void StatsEventSubscriber::PopulatePacketLossPercentageStat( | |
398 StatsMap* stats_map) const { | |
399 // We assume that retransmission means that the packet's previous | |
400 // (re)transmission was lost. | |
401 // This means the percentage of packet loss is | |
402 // (# of retransmit events) / (# of transmit + retransmit events). | |
403 CastLoggingEvent packet_sent_event = GetPacketSentEvent(event_media_type_); | |
404 CastLoggingEvent packet_retransmitted_event = | |
405 GetPacketRetransmittedEvent(event_media_type_); | |
406 PacketStatsMap::const_iterator sent_it = | |
407 packet_stats_.find(packet_sent_event); | |
408 if (sent_it == packet_stats_.end()) | |
409 return; | |
410 PacketStatsMap::const_iterator retransmitted_it = | |
411 packet_stats_.find(packet_retransmitted_event); | |
412 int sent_count = sent_it->second.event_counter; | |
413 int retransmitted_count = 0; | |
414 if (retransmitted_it != packet_stats_.end()) | |
415 retransmitted_count = retransmitted_it->second.event_counter; | |
416 double packet_loss_percentage = static_cast<double>(retransmitted_count) / | |
417 (sent_count + retransmitted_count) * 100; | |
418 stats_map->insert( | |
419 std::make_pair(PACKET_LOSS_PERCENTAGE, packet_loss_percentage)); | |
420 } | |
421 | |
422 StatsEventSubscriber::FrameLogStats::FrameLogStats() | |
423 : event_counter(0), sum_size(0) {} | |
424 StatsEventSubscriber::FrameLogStats::~FrameLogStats() {} | |
425 | |
426 StatsEventSubscriber::PacketLogStats::PacketLogStats() | |
427 : event_counter(0), sum_size(0) {} | |
428 StatsEventSubscriber::PacketLogStats::~PacketLogStats() {} | |
137 | 429 |
138 } // namespace cast | 430 } // namespace cast |
139 } // namespace media | 431 } // namespace media |
OLD | NEW |