Chromium Code Reviews| 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 |