summaryrefslogtreecommitdiff
path: root/media/cast
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2014-11-27 15:55:08 +0000
committerTorne (Richard Coles) <torne@google.com>2014-11-27 15:55:08 +0000
commit7f11db722e2af5d4e21e711545372830ca4221d4 (patch)
treec90cc37abc1e68c2584ba0aff932369b1e7155de /media/cast
parentbe0db613a3916853a2abecc9b0bd869b7640022e (diff)
downloadchromium_org-7f11db722e2af5d4e21e711545372830ca4221d4.tar.gz
Merge from Chromium at DEPS revision 40.0.2214.10
This commit was generated by merge_to_master.py. Change-Id: I0a543d3dd13b8f5d3ca1d0a6b04cf4d1a280b98a
Diffstat (limited to 'media/cast')
-rw-r--r--media/cast/logging/logging_defines.h5
-rw-r--r--media/cast/logging/stats_event_subscriber.cc229
-rw-r--r--media/cast/logging/stats_event_subscriber.h44
-rw-r--r--media/cast/logging/stats_event_subscriber_unittest.cc185
4 files changed, 360 insertions, 103 deletions
diff --git a/media/cast/logging/logging_defines.h b/media/cast/logging/logging_defines.h
index 021a3c99a7..0f57fe982d 100644
--- a/media/cast/logging/logging_defines.h
+++ b/media/cast/logging/logging_defines.h
@@ -65,7 +65,10 @@ struct FrameEvent {
EventMediaType media_type;
- // Render / playout delay. Only set for FRAME_PLAYOUT events.
+ // Only set for FRAME_PLAYOUT events.
+ // If this value is zero the frame is rendered on time.
+ // If this value is positive it means the frame is rendered late.
+ // If this value is negative it means the frame is rendered early.
base::TimeDelta delay_delta;
// Whether the frame is a key frame. Only set for video FRAME_ENCODED event.
diff --git a/media/cast/logging/stats_event_subscriber.cc b/media/cast/logging/stats_event_subscriber.cc
index b22812e446..c42affa401 100644
--- a/media/cast/logging/stats_event_subscriber.cc
+++ b/media/cast/logging/stats_event_subscriber.cc
@@ -101,7 +101,12 @@ StatsEventSubscriber::StatsEventSubscriber(
: event_media_type_(event_media_type),
clock_(clock),
offset_estimator_(offset_estimator),
+ capture_latency_datapoints_(0),
+ encode_time_datapoints_(0),
+ queueing_latency_datapoints_(0),
network_latency_datapoints_(0),
+ packet_latency_datapoints_(0),
+ frame_latency_datapoints_(0),
e2e_latency_datapoints_(0),
num_frames_dropped_by_encoder_(0),
num_frames_late_(0),
@@ -150,7 +155,9 @@ void StatsEventSubscriber::OnReceiveFrameEvent(const FrameEvent& frame_event) {
RecordE2ELatency(frame_event);
base::TimeDelta delay_delta = frame_event.delay_delta;
histograms_[PLAYOUT_DELAY_MS_HISTO]->Add(delay_delta.InMillisecondsF());
- if (delay_delta <= base::TimeDelta())
+
+ // Positive delay_delta means the frame is late.
+ if (delay_delta > base::TimeDelta())
num_frames_late_++;
}
@@ -182,7 +189,7 @@ void StatsEventSubscriber::OnReceivePacketEvent(
if (type == PACKET_SENT_TO_NETWORK ||
type == PACKET_RECEIVED) {
- RecordNetworkLatency(packet_event);
+ RecordPacketRelatedLatencies(packet_event);
} else if (type == PACKET_RETRANSMITTED) {
// We only measure network latency using packets that doesn't have to be
// retransmitted as there is precisely one sent-receive timestamp pairs.
@@ -226,6 +233,8 @@ scoped_ptr<base::DictionaryValue> StatsEventSubscriber::GetStats() const {
stats->SetDouble(CastStatToString(it->first),
round(it->second * 1000.0) / 1000.0);
}
+
+ // Populate all histograms.
for (HistogramMap::const_iterator it = histograms_.begin();
it != histograms_.end();
++it) {
@@ -244,8 +253,18 @@ void StatsEventSubscriber::Reset() {
frame_stats_.clear();
packet_stats_.clear();
+ total_capture_latency_ = base::TimeDelta();
+ capture_latency_datapoints_ = 0;
+ total_encode_time_ = base::TimeDelta();
+ encode_time_datapoints_ = 0;
+ total_queueing_latency_ = base::TimeDelta();
+ queueing_latency_datapoints_ = 0;
total_network_latency_ = base::TimeDelta();
network_latency_datapoints_ = 0;
+ total_packet_latency_ = base::TimeDelta();
+ packet_latency_datapoints_ = 0;
+ total_frame_latency_ = base::TimeDelta();
+ frame_latency_datapoints_ = 0;
total_e2e_latency_ = base::TimeDelta();
e2e_latency_datapoints_ = 0;
num_frames_dropped_by_encoder_ = 0;
@@ -269,47 +288,75 @@ const char* StatsEventSubscriber::CastStatToString(CastStat stat) {
STAT_ENUM_TO_STRING(CAPTURE_FPS);
STAT_ENUM_TO_STRING(ENCODE_FPS);
STAT_ENUM_TO_STRING(DECODE_FPS);
+ STAT_ENUM_TO_STRING(AVG_CAPTURE_LATENCY_MS);
STAT_ENUM_TO_STRING(AVG_ENCODE_TIME_MS);
- STAT_ENUM_TO_STRING(AVG_PLAYOUT_DELAY_MS);
+ STAT_ENUM_TO_STRING(AVG_QUEUEING_LATENCY_MS);
STAT_ENUM_TO_STRING(AVG_NETWORK_LATENCY_MS);
+ STAT_ENUM_TO_STRING(AVG_PACKET_LATENCY_MS);
+ STAT_ENUM_TO_STRING(AVG_FRAME_LATENCY_MS);
STAT_ENUM_TO_STRING(AVG_E2E_LATENCY_MS);
STAT_ENUM_TO_STRING(ENCODE_KBPS);
STAT_ENUM_TO_STRING(TRANSMISSION_KBPS);
STAT_ENUM_TO_STRING(RETRANSMISSION_KBPS);
- STAT_ENUM_TO_STRING(PACKET_LOSS_FRACTION);
STAT_ENUM_TO_STRING(MS_SINCE_LAST_RECEIVER_RESPONSE);
STAT_ENUM_TO_STRING(NUM_FRAMES_CAPTURED);
STAT_ENUM_TO_STRING(NUM_FRAMES_DROPPED_BY_ENCODER);
STAT_ENUM_TO_STRING(NUM_FRAMES_LATE);
STAT_ENUM_TO_STRING(NUM_PACKETS_SENT);
STAT_ENUM_TO_STRING(NUM_PACKETS_RETRANSMITTED);
+ STAT_ENUM_TO_STRING(NUM_PACKETS_RECEIVED);
STAT_ENUM_TO_STRING(NUM_PACKETS_RTX_REJECTED);
STAT_ENUM_TO_STRING(FIRST_EVENT_TIME_MS);
STAT_ENUM_TO_STRING(LAST_EVENT_TIME_MS);
STAT_ENUM_TO_STRING(CAPTURE_LATENCY_MS_HISTO);
- STAT_ENUM_TO_STRING(ENCODE_LATENCY_MS_HISTO);
+ STAT_ENUM_TO_STRING(ENCODE_TIME_MS_HISTO);
+ STAT_ENUM_TO_STRING(QUEUEING_LATENCY_MS_HISTO);
+ STAT_ENUM_TO_STRING(NETWORK_LATENCY_MS_HISTO);
STAT_ENUM_TO_STRING(PACKET_LATENCY_MS_HISTO);
STAT_ENUM_TO_STRING(FRAME_LATENCY_MS_HISTO);
+ STAT_ENUM_TO_STRING(E2E_LATENCY_MS_HISTO);
STAT_ENUM_TO_STRING(PLAYOUT_DELAY_MS_HISTO);
}
NOTREACHED();
return "";
}
-const int kMaxLatencyBucketMs = 800;
-const int kBucketWidthMs = 20;
+const int kDefaultMaxLatencyBucketMs = 800;
+const int kDefaultBucketWidthMs = 20;
+
+// For small latency values.
+const int kSmallMaxLatencyBucketMs = 100;
+const int kSmallBucketWidthMs = 5;
+
+// For large latency values.
+const int kLargeMaxLatencyBucketMs = 1200;
+const int kLargeBucketWidthMs = 50;
void StatsEventSubscriber::InitHistograms() {
- histograms_[CAPTURE_LATENCY_MS_HISTO].reset(
- new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
- histograms_[ENCODE_LATENCY_MS_HISTO].reset(
- new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
+ histograms_[E2E_LATENCY_MS_HISTO].reset(
+ new SimpleHistogram(0, kLargeMaxLatencyBucketMs,
+ kLargeBucketWidthMs));
+ histograms_[QUEUEING_LATENCY_MS_HISTO].reset(
+ new SimpleHistogram(0, kDefaultMaxLatencyBucketMs,
+ kDefaultBucketWidthMs));
+ histograms_[NETWORK_LATENCY_MS_HISTO].reset(
+ new SimpleHistogram(0, kDefaultMaxLatencyBucketMs,
+ kDefaultBucketWidthMs));
histograms_[PACKET_LATENCY_MS_HISTO].reset(
- new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
+ new SimpleHistogram(0, kDefaultMaxLatencyBucketMs,
+ kDefaultBucketWidthMs));
histograms_[FRAME_LATENCY_MS_HISTO].reset(
- new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
+ new SimpleHistogram(0, kDefaultMaxLatencyBucketMs,
+ kDefaultBucketWidthMs));
histograms_[PLAYOUT_DELAY_MS_HISTO].reset(
- new SimpleHistogram(0, kMaxLatencyBucketMs, kBucketWidthMs));
+ new SimpleHistogram(0, kSmallMaxLatencyBucketMs,
+ kSmallBucketWidthMs));
+ histograms_[CAPTURE_LATENCY_MS_HISTO].reset(
+ new SimpleHistogram(0, kSmallMaxLatencyBucketMs,
+ kSmallBucketWidthMs));
+ histograms_[ENCODE_TIME_MS_HISTO].reset(
+ new SimpleHistogram(0, kSmallMaxLatencyBucketMs,
+ kSmallBucketWidthMs));
}
void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const {
@@ -325,7 +372,6 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const {
end_time, FRAME_ENCODED, ENCODE_FPS, stats_map);
PopulateFpsStat(
end_time, FRAME_DECODED, DECODE_FPS, stats_map);
- PopulatePlayoutDelayStat(stats_map);
PopulateFrameBitrateStat(end_time, stats_map);
PopulatePacketBitrateStat(end_time,
PACKET_SENT_TO_NETWORK,
@@ -335,14 +381,38 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const {
PACKET_RETRANSMITTED,
RETRANSMISSION_KBPS,
stats_map);
- PopulatePacketLossPercentageStat(stats_map);
PopulateFrameCountStat(FRAME_CAPTURE_END, NUM_FRAMES_CAPTURED, stats_map);
PopulatePacketCountStat(PACKET_SENT_TO_NETWORK, NUM_PACKETS_SENT, stats_map);
PopulatePacketCountStat(
PACKET_RETRANSMITTED, NUM_PACKETS_RETRANSMITTED, stats_map);
+ PopulatePacketCountStat(PACKET_RECEIVED, NUM_PACKETS_RECEIVED, stats_map);
PopulatePacketCountStat(
PACKET_RTX_REJECTED, NUM_PACKETS_RTX_REJECTED, stats_map);
+ if (capture_latency_datapoints_ > 0) {
+ double avg_capture_latency_ms =
+ total_capture_latency_.InMillisecondsF() /
+ capture_latency_datapoints_;
+ stats_map->insert(
+ std::make_pair(AVG_CAPTURE_LATENCY_MS, avg_capture_latency_ms));
+ }
+
+ if (encode_time_datapoints_ > 0) {
+ double avg_encode_time_ms =
+ total_encode_time_.InMillisecondsF() /
+ encode_time_datapoints_;
+ stats_map->insert(
+ std::make_pair(AVG_ENCODE_TIME_MS, avg_encode_time_ms));
+ }
+
+ if (queueing_latency_datapoints_ > 0) {
+ double avg_queueing_latency_ms =
+ total_queueing_latency_.InMillisecondsF() /
+ queueing_latency_datapoints_;
+ stats_map->insert(
+ std::make_pair(AVG_QUEUEING_LATENCY_MS, avg_queueing_latency_ms));
+ }
+
if (network_latency_datapoints_ > 0) {
double avg_network_latency_ms =
total_network_latency_.InMillisecondsF() /
@@ -351,6 +421,21 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const {
std::make_pair(AVG_NETWORK_LATENCY_MS, avg_network_latency_ms));
}
+ if (packet_latency_datapoints_ > 0) {
+ double avg_packet_latency_ms =
+ total_packet_latency_.InMillisecondsF() /
+ packet_latency_datapoints_;
+ stats_map->insert(
+ std::make_pair(AVG_PACKET_LATENCY_MS, avg_packet_latency_ms));
+ }
+
+ if (frame_latency_datapoints_ > 0) {
+ double avg_frame_latency_ms =
+ total_frame_latency_.InMillisecondsF() / frame_latency_datapoints_;
+ stats_map->insert(
+ std::make_pair(AVG_FRAME_LATENCY_MS, avg_frame_latency_ms));
+ }
+
if (e2e_latency_datapoints_ > 0) {
double avg_e2e_latency_ms =
total_e2e_latency_.InMillisecondsF() / e2e_latency_datapoints_;
@@ -378,6 +463,13 @@ void StatsEventSubscriber::GetStatsInternal(StatsMap* stats_map) const {
}
}
+StatsEventSubscriber::SimpleHistogram*
+StatsEventSubscriber::GetHistogramForTesting(
+ CastStat stats) const {
+ DCHECK(histograms_.find(stats) != histograms_.end());
+ return histograms_.find(stats)->second.get();
+}
+
bool StatsEventSubscriber::GetReceiverOffset(base::TimeDelta* offset) {
base::TimeDelta receiver_offset_lower_bound;
base::TimeDelta receiver_offset_upper_bound;
@@ -403,7 +495,7 @@ void StatsEventSubscriber::MaybeInsertFrameInfo(RtpTimestamp rtp_timestamp,
if (recent_frame_infos_.size() >= kMaxFrameInfoMapSize) {
FrameInfoMap::iterator erase_it = recent_frame_infos_.begin();
- if (erase_it->second.encode_time.is_null())
+ if (erase_it->second.encode_end_time.is_null())
num_frames_dropped_by_encoder_++;
recent_frame_infos_.erase(erase_it);
}
@@ -419,13 +511,15 @@ void StatsEventSubscriber::RecordFrameCaptureTime(
void StatsEventSubscriber::RecordCaptureLatency(const FrameEvent& frame_event) {
FrameInfoMap::iterator it =
recent_frame_infos_.find(frame_event.rtp_timestamp);
- if (it == recent_frame_infos_.end())
+ if (it == recent_frame_infos_.end()) {
return;
+ }
if (!it->second.capture_time.is_null()) {
- double capture_latency_ms =
- (it->second.capture_time - frame_event.timestamp).InMillisecondsF();
- histograms_[CAPTURE_LATENCY_MS_HISTO]->Add(capture_latency_ms);
+ base::TimeDelta latency = frame_event.timestamp - it->second.capture_time;
+ total_capture_latency_ += latency;
+ capture_latency_datapoints_++;
+ histograms_[CAPTURE_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF());
}
it->second.capture_end_time = frame_event.timestamp;
@@ -436,18 +530,20 @@ void StatsEventSubscriber::RecordEncodeLatency(const FrameEvent& frame_event) {
recent_frame_infos_.find(frame_event.rtp_timestamp);
if (it == recent_frame_infos_.end()) {
FrameInfo frame_info;
- frame_info.encode_time = frame_event.timestamp;
+ frame_info.encode_end_time = frame_event.timestamp;
MaybeInsertFrameInfo(frame_event.rtp_timestamp, frame_info);
return;
}
if (!it->second.capture_end_time.is_null()) {
- double encode_latency_ms =
- (frame_event.timestamp - it->second.capture_end_time).InMillisecondsF();
- histograms_[ENCODE_LATENCY_MS_HISTO]->Add(encode_latency_ms);
+ base::TimeDelta latency =
+ frame_event.timestamp - it->second.capture_end_time;
+ total_encode_time_ += latency;
+ encode_time_datapoints_++;
+ histograms_[ENCODE_TIME_MS_HISTO]->Add(latency.InMillisecondsF());
}
- it->second.encode_time = frame_event.timestamp;
+ it->second.encode_end_time = frame_event.timestamp;
}
void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) {
@@ -456,7 +552,7 @@ void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) {
if (it == recent_frame_infos_.end())
return;
- if (it->second.encode_time.is_null())
+ if (it->second.encode_end_time.is_null())
return;
base::TimeDelta receiver_offset;
@@ -464,9 +560,10 @@ void StatsEventSubscriber::RecordFrameTxLatency(const FrameEvent& frame_event) {
return;
base::TimeTicks sender_time = frame_event.timestamp - receiver_offset;
- double frame_tx_latency_ms =
- (sender_time - it->second.encode_time).InMillisecondsF();
- histograms_[FRAME_LATENCY_MS_HISTO]->Add(frame_tx_latency_ms);
+ base::TimeDelta latency = sender_time - it->second.encode_end_time;
+ total_frame_latency_ += latency;
+ frame_latency_datapoints_++;
+ histograms_[FRAME_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF());
}
void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) {
@@ -482,8 +579,10 @@ void StatsEventSubscriber::RecordE2ELatency(const FrameEvent& frame_event) {
// Playout time is event time + playout delay.
base::TimeTicks playout_time =
frame_event.timestamp + frame_event.delay_delta - receiver_offset;
- total_e2e_latency_ += playout_time - it->second.capture_time;
+ base::TimeDelta latency = playout_time - it->second.capture_time;
+ total_e2e_latency_ += latency;
e2e_latency_datapoints_++;
+ histograms_[E2E_LATENCY_MS_HISTO]->Add(latency.InMillisecondsF());
}
void StatsEventSubscriber::UpdateLastResponseTime(
@@ -502,8 +601,23 @@ void StatsEventSubscriber::ErasePacketSentTime(
packet_sent_times_.erase(key);
}
-void StatsEventSubscriber::RecordNetworkLatency(
+void StatsEventSubscriber::RecordPacketRelatedLatencies(
const PacketEvent& packet_event) {
+ // Log queueing latency.
+ if (packet_event.type == PACKET_SENT_TO_NETWORK) {
+ FrameInfoMap::iterator it =
+ recent_frame_infos_.find(packet_event.rtp_timestamp);
+ if (it != recent_frame_infos_.end()) {
+ base::TimeDelta latency =
+ packet_event.timestamp - it->second.encode_end_time;
+ total_queueing_latency_ += latency;
+ queueing_latency_datapoints_++;
+ histograms_[QUEUEING_LATENCY_MS_HISTO]->Add(
+ latency.InMillisecondsF());
+ }
+ }
+
+ // Log network latency and total packet latency;
base::TimeDelta receiver_offset;
if (!GetReceiverOffset(&receiver_offset))
return;
@@ -535,17 +649,28 @@ void StatsEventSubscriber::RecordNetworkLatency(
match = true;
}
if (match) {
+ packet_sent_times_.erase(it);
+
// Subtract by offset.
packet_received_time -= receiver_offset;
base::TimeDelta latency_delta = packet_received_time - packet_sent_time;
total_network_latency_ += latency_delta;
network_latency_datapoints_++;
-
- histograms_[PACKET_LATENCY_MS_HISTO]->Add(
+ histograms_[NETWORK_LATENCY_MS_HISTO]->Add(
latency_delta.InMillisecondsF());
- packet_sent_times_.erase(it);
+ // Log total network latency.
+ FrameInfoMap::iterator frame_it =
+ recent_frame_infos_.find(packet_event.rtp_timestamp);
+ if (frame_it != recent_frame_infos_.end()) {
+ base::TimeDelta latency =
+ packet_received_time - frame_it->second.encode_end_time;
+ total_packet_latency_ += latency;
+ packet_latency_datapoints_++;
+ histograms_[PACKET_LATENCY_MS_HISTO]->Add(
+ latency.InMillisecondsF());
+ }
}
}
}
@@ -583,18 +708,6 @@ void StatsEventSubscriber::PopulatePacketCountStat(CastLoggingEvent event,
}
}
-void StatsEventSubscriber::PopulatePlayoutDelayStat(StatsMap* stats_map) const {
- FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_PLAYOUT);
- if (it != frame_stats_.end()) {
- double avg_delay_ms = 0.0;
- base::TimeDelta sum_delay = it->second.sum_delay;
- int count = it->second.event_counter;
- if (count != 0)
- avg_delay_ms = sum_delay.InMillisecondsF() / count;
- stats_map->insert(std::make_pair(AVG_PLAYOUT_DELAY_MS, avg_delay_ms));
- }
-}
-
void StatsEventSubscriber::PopulateFrameBitrateStat(base::TimeTicks end_time,
StatsMap* stats_map) const {
FrameStatsMap::const_iterator it = frame_stats_.find(FRAME_ENCODED);
@@ -626,28 +739,6 @@ void StatsEventSubscriber::PopulatePacketBitrateStat(
}
}
-void StatsEventSubscriber::PopulatePacketLossPercentageStat(
- StatsMap* stats_map) const {
- // We assume that retransmission means that the packet's previous
- // (re)transmission was lost.
- // This means the percentage of packet loss is
- // (# of retransmit events) / (# of transmit + retransmit events).
- PacketStatsMap::const_iterator sent_it =
- packet_stats_.find(PACKET_SENT_TO_NETWORK);
- if (sent_it == packet_stats_.end())
- return;
- PacketStatsMap::const_iterator retransmitted_it =
- packet_stats_.find(PACKET_RETRANSMITTED);
- int sent_count = sent_it->second.event_counter;
- int retransmitted_count = 0;
- if (retransmitted_it != packet_stats_.end())
- retransmitted_count = retransmitted_it->second.event_counter;
- double packet_loss_fraction = static_cast<double>(retransmitted_count) /
- (sent_count + retransmitted_count);
- stats_map->insert(
- std::make_pair(PACKET_LOSS_FRACTION, packet_loss_fraction));
-}
-
StatsEventSubscriber::FrameLogStats::FrameLogStats()
: event_counter(0), sum_size(0) {}
StatsEventSubscriber::FrameLogStats::~FrameLogStats() {}
diff --git a/media/cast/logging/stats_event_subscriber.h b/media/cast/logging/stats_event_subscriber.h
index 20394021bd..3e8c83b153 100644
--- a/media/cast/logging/stats_event_subscriber.h
+++ b/media/cast/logging/stats_event_subscriber.h
@@ -57,6 +57,7 @@ class StatsEventSubscriber : public RawEventSubscriber {
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, PlayoutDelay);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, E2ELatency);
FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Packets);
+ FRIEND_TEST_ALL_PREFIXES(StatsEventSubscriberTest, Histograms);
static const size_t kMaxFrameInfoMapSize = 100;
@@ -113,15 +114,22 @@ class StatsEventSubscriber : public RawEventSubscriber {
ENCODE_FPS,
// Decode frame rate.
DECODE_FPS,
+ // Average capture latency in milliseconds.
+ AVG_CAPTURE_LATENCY_MS,
// Average encode duration in milliseconds.
- // TODO(imcheng): This stat is not populated yet because we do not have
- // the time when encode started. Record it in FRAME_ENCODED event.
AVG_ENCODE_TIME_MS,
- // Average playout delay in milliseconds.
- AVG_PLAYOUT_DELAY_MS,
+ // Duration from when a frame is encoded to when the packet is first
+ // sent.
+ AVG_QUEUEING_LATENCY_MS,
// Duration from when a packet is transmitted to when it is received.
// This measures latency from sender to receiver.
AVG_NETWORK_LATENCY_MS,
+ // Duration from when a frame is encoded to when the packet is first
+ // received.
+ AVG_PACKET_LATENCY_MS,
+ // Average latency between frame encoded and the moment when the frame
+ // is fully received.
+ AVG_FRAME_LATENCY_MS,
// Duration from when a frame is captured to when it should be played out.
AVG_E2E_LATENCY_MS,
// Encode bitrate in kbps.
@@ -130,8 +138,6 @@ class StatsEventSubscriber : public RawEventSubscriber {
TRANSMISSION_KBPS,
// Packet retransmission bitrate in kbps.
RETRANSMISSION_KBPS,
- // Fraction of packet loss.
- PACKET_LOSS_FRACTION,
// Duration in milliseconds since last receiver response.
MS_SINCE_LAST_RECEIVER_RESPONSE,
// Number of frames captured.
@@ -144,6 +150,8 @@ class StatsEventSubscriber : public RawEventSubscriber {
NUM_PACKETS_SENT,
// Number of packets that were retransmitted.
NUM_PACKETS_RETRANSMITTED,
+ // Number of packets that were received by receiver.
+ NUM_PACKETS_RECEIVED,
// Number of packets that had their retransmission cancelled.
NUM_PACKETS_RTX_REJECTED,
// Unix time in milliseconds of first event since reset.
@@ -153,9 +161,12 @@ class StatsEventSubscriber : public RawEventSubscriber {
// Histograms
CAPTURE_LATENCY_MS_HISTO,
- ENCODE_LATENCY_MS_HISTO,
+ ENCODE_TIME_MS_HISTO,
+ QUEUEING_LATENCY_MS_HISTO,
+ NETWORK_LATENCY_MS_HISTO,
PACKET_LATENCY_MS_HISTO,
FRAME_LATENCY_MS_HISTO,
+ E2E_LATENCY_MS_HISTO,
PLAYOUT_DELAY_MS_HISTO
};
@@ -165,7 +176,7 @@ class StatsEventSubscriber : public RawEventSubscriber {
base::TimeTicks capture_time;
base::TimeTicks capture_end_time;
- base::TimeTicks encode_time;
+ base::TimeTicks encode_end_time;
bool encoded;
};
@@ -186,6 +197,9 @@ class StatsEventSubscriber : public RawEventSubscriber {
// Assigns |stats_map| with stats data. Used for testing.
void GetStatsInternal(StatsMap* stats_map) const;
+ // Return a histogram of the type specified.
+ SimpleHistogram* GetHistogramForTesting(CastStat stats) const;
+
void UpdateFirstLastEventTime(base::TimeTicks timestamp,
bool is_receiver_event);
bool GetReceiverOffset(base::TimeDelta* offset);
@@ -198,7 +212,7 @@ class StatsEventSubscriber : public RawEventSubscriber {
void RecordE2ELatency(const FrameEvent& frame_event);
void RecordPacketSentTime(const PacketEvent& packet_event);
void ErasePacketSentTime(const PacketEvent& packet_event);
- void RecordNetworkLatency(const PacketEvent& packet_event);
+ void RecordPacketRelatedLatencies(const PacketEvent& packet_event);
void UpdateLastResponseTime(base::TimeTicks receiver_time);
void PopulateFpsStat(base::TimeTicks now,
@@ -211,13 +225,11 @@ class StatsEventSubscriber : public RawEventSubscriber {
void PopulatePacketCountStat(CastLoggingEvent event,
CastStat stat,
StatsMap* stats_map) const;
- void PopulatePlayoutDelayStat(StatsMap* stats_map) const;
void PopulateFrameBitrateStat(base::TimeTicks now, StatsMap* stats_map) const;
void PopulatePacketBitrateStat(base::TimeTicks now,
CastLoggingEvent event,
CastStat stat,
StatsMap* stats_map) const;
- void PopulatePacketLossPercentageStat(StatsMap* stats_map) const;
const EventMediaType event_media_type_;
@@ -230,8 +242,18 @@ class StatsEventSubscriber : public RawEventSubscriber {
FrameStatsMap frame_stats_;
PacketStatsMap packet_stats_;
+ base::TimeDelta total_capture_latency_;
+ int capture_latency_datapoints_;
+ base::TimeDelta total_encode_time_;
+ int encode_time_datapoints_;
+ base::TimeDelta total_queueing_latency_;
+ int queueing_latency_datapoints_;
base::TimeDelta total_network_latency_;
int network_latency_datapoints_;
+ base::TimeDelta total_packet_latency_;
+ int packet_latency_datapoints_;
+ base::TimeDelta total_frame_latency_;
+ int frame_latency_datapoints_;
base::TimeDelta total_e2e_latency_;
int e2e_latency_datapoints_;
diff --git a/media/cast/logging/stats_event_subscriber_unittest.cc b/media/cast/logging/stats_event_subscriber_unittest.cc
index 41388e0ade..570e2ccf3a 100644
--- a/media/cast/logging/stats_event_subscriber_unittest.cc
+++ b/media/cast/logging/stats_event_subscriber_unittest.cc
@@ -131,6 +131,11 @@ TEST_F(StatsEventSubscriberTest, CaptureEncode) {
ASSERT_TRUE(it != stats_map.end());
EXPECT_DOUBLE_EQ(it->second, static_cast<double>(dropped_frames));
+
+ it = stats_map.find(StatsEventSubscriber::AVG_CAPTURE_LATENCY_MS);
+ ASSERT_TRUE(it != stats_map.end());
+
+ EXPECT_DOUBLE_EQ(it->second, static_cast<double>(0.01));
}
TEST_F(StatsEventSubscriberTest, Encode) {
@@ -236,12 +241,10 @@ TEST_F(StatsEventSubscriberTest, PlayoutDelay) {
uint32 rtp_timestamp = 0;
uint32 frame_id = 0;
int num_frames = 10;
- int total_delay_ms = 0;
int late_frames = 0;
for (int i = 0, delay_ms = -50; i < num_frames; i++, delay_ms += 10) {
base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms);
- total_delay_ms += delay_ms;
- if (delay_ms <= 0)
+ if (delay_ms > 0)
late_frames++;
cast_environment_->Logging()->InsertFrameEventWithDelay(
receiver_clock_.NowTicks(),
@@ -259,14 +262,8 @@ TEST_F(StatsEventSubscriberTest, PlayoutDelay) {
StatsEventSubscriber::StatsMap stats_map;
subscriber_->GetStatsInternal(&stats_map);
- StatsEventSubscriber::StatsMap::iterator it =
- stats_map.find(StatsEventSubscriber::AVG_PLAYOUT_DELAY_MS);
- ASSERT_TRUE(it != stats_map.end());
-
- EXPECT_DOUBLE_EQ(
- it->second, static_cast<double>(total_delay_ms) / num_frames);
-
- it = stats_map.find(StatsEventSubscriber::NUM_FRAMES_LATE);
+ StatsEventSubscriber::StatsMap::iterator it = stats_map.find(
+ StatsEventSubscriber::NUM_FRAMES_LATE);
ASSERT_TRUE(it != stats_map.end());
EXPECT_DOUBLE_EQ(it->second, late_frames);
@@ -326,10 +323,22 @@ TEST_F(StatsEventSubscriberTest, Packets) {
base::TimeTicks start_time = sender_clock_->NowTicks();
int total_size = 0;
int retransmit_total_size = 0;
- base::TimeDelta total_latency;
+ base::TimeDelta total_network_latency;
+ base::TimeDelta total_queueing_latency;
+ base::TimeDelta total_packet_latency;
int num_packets_transmitted = 0;
+ int num_packets_received = 0;
int num_packets_retransmitted = 0;
int num_packets_rtx_rejected = 0;
+
+ base::TimeTicks sender_encoded_time = sender_clock_->NowTicks();
+ base::TimeTicks receiver_encoded_time = receiver_clock_.NowTicks();
+ cast_environment_->Logging()->InsertFrameEvent(sender_encoded_time,
+ FRAME_ENCODED,
+ VIDEO_EVENT,
+ rtp_timestamp,
+ 0);
+
// Every 2nd packet will be retransmitted once.
// Every 4th packet will be retransmitted twice.
// Every 8th packet will be retransmitted 3 times + 1 rejected retransmission.
@@ -346,12 +355,15 @@ TEST_F(StatsEventSubscriberTest, Packets) {
num_packets - 1,
size);
num_packets_transmitted++;
+ total_queueing_latency += sender_clock_->NowTicks() - sender_encoded_time;
int latency_micros = 20000 + base::RandInt(-10000, 10000);
base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros);
// Latency is only recorded for packets that aren't retransmitted.
if (i % 2 != 0) {
- total_latency += latency;
+ total_network_latency += latency;
+ total_packet_latency +=
+ receiver_clock_.NowTicks() - receiver_encoded_time + latency;
num_latency_recorded_packets++;
}
@@ -428,6 +440,7 @@ TEST_F(StatsEventSubscriberTest, Packets) {
i,
num_packets - 1,
size);
+ num_packets_received++;
}
base::TimeTicks end_time = sender_clock_->NowTicks();
@@ -436,15 +449,28 @@ TEST_F(StatsEventSubscriberTest, Packets) {
StatsEventSubscriber::StatsMap stats_map;
subscriber_->GetStatsInternal(&stats_map);
- // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS,
- // and PACKET_LOSS_FRACTION.
+ // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS.
StatsEventSubscriber::StatsMap::iterator it =
stats_map.find(StatsEventSubscriber::AVG_NETWORK_LATENCY_MS);
ASSERT_TRUE(it != stats_map.end());
EXPECT_DOUBLE_EQ(
it->second,
- total_latency.InMillisecondsF() / num_latency_recorded_packets);
+ total_network_latency.InMillisecondsF() / num_latency_recorded_packets);
+
+ it = stats_map.find(StatsEventSubscriber::AVG_QUEUEING_LATENCY_MS);
+ ASSERT_TRUE(it != stats_map.end());
+
+ EXPECT_DOUBLE_EQ(
+ it->second,
+ total_queueing_latency.InMillisecondsF() / num_packets);
+
+ it = stats_map.find(StatsEventSubscriber::AVG_PACKET_LATENCY_MS);
+ ASSERT_TRUE(it != stats_map.end());
+
+ EXPECT_DOUBLE_EQ(
+ it->second,
+ total_packet_latency.InMillisecondsF() / num_latency_recorded_packets);
it = stats_map.find(StatsEventSubscriber::TRANSMISSION_KBPS);
ASSERT_TRUE(it != stats_map.end());
@@ -459,17 +485,15 @@ TEST_F(StatsEventSubscriberTest, Packets) {
static_cast<double>(retransmit_total_size) /
duration.InMillisecondsF() * 8);
- it = stats_map.find(StatsEventSubscriber::PACKET_LOSS_FRACTION);
+ it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_SENT);
ASSERT_TRUE(it != stats_map.end());
- EXPECT_DOUBLE_EQ(
- it->second,
- static_cast<double>(num_packets_retransmitted) / num_packets_transmitted);
+ EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets));
- it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_SENT);
+ it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_RECEIVED);
ASSERT_TRUE(it != stats_map.end());
- EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets));
+ EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets_received));
it = stats_map.find(StatsEventSubscriber::NUM_PACKETS_RETRANSMITTED);
ASSERT_TRUE(it != stats_map.end());
@@ -482,5 +506,122 @@ TEST_F(StatsEventSubscriberTest, Packets) {
EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets_rtx_rejected));
}
+bool CheckHistogramHasValue(base::ListValue* values,
+ const std::string& bucket, int expected_count) {
+ for (size_t i = 0; i < values->GetSize(); ++i) {
+ const base::DictionaryValue* dict = NULL;
+ values->GetDictionary(i, &dict);
+ if (!dict->HasKey(bucket))
+ continue;
+ int bucket_count = 0;
+ if (!dict->GetInteger(bucket, &bucket_count))
+ return false;
+ return bucket_count == expected_count;
+ }
+ return false;
+}
+
+TEST_F(StatsEventSubscriberTest, Histograms) {
+ Init(VIDEO_EVENT);
+ AdvanceClocks(base::TimeDelta::FromMilliseconds(123));
+
+ uint32 rtp_timestamp = 123;
+ uint32 frame_id = 0;
+
+ // 10 Frames with capture latency in the bucket of "10-14"ms.
+ // 10 Frames with encode time in the bucket of "15-19"ms.
+ for (int i = 0; i < 10; ++i) {
+ ++frame_id;
+ ++rtp_timestamp;
+ cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
+ FRAME_CAPTURE_BEGIN,
+ VIDEO_EVENT,
+ rtp_timestamp,
+ frame_id);
+ AdvanceClocks(base::TimeDelta::FromMilliseconds(10));
+ cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
+ FRAME_CAPTURE_END,
+ VIDEO_EVENT,
+ rtp_timestamp,
+ frame_id);
+ AdvanceClocks(base::TimeDelta::FromMilliseconds(15));
+ cast_environment_->Logging()->InsertEncodedFrameEvent(
+ sender_clock_->NowTicks(),
+ FRAME_ENCODED,
+ VIDEO_EVENT,
+ rtp_timestamp,
+ frame_id,
+ 1024,
+ true,
+ 5678);
+ }
+
+ // Send 3 packets for the last frame.
+ // Queueing latencies are 100ms, 200ms and 300ms.
+ for (int i = 0; i < 3; ++i) {
+ AdvanceClocks(base::TimeDelta::FromMilliseconds(100));
+ cast_environment_->Logging()->InsertPacketEvent(sender_clock_->NowTicks(),
+ PACKET_SENT_TO_NETWORK,
+ VIDEO_EVENT,
+ rtp_timestamp,
+ 0,
+ i,
+ 2,
+ 123);
+ }
+
+ // Receive 3 packets for the last frame.
+ // Network latencies are 100ms, 200ms and 300ms.
+ // Packet latencies are 400ms.
+ AdvanceClocks(base::TimeDelta::FromMilliseconds(100));
+ for (int i = 0; i < 3; ++i) {
+ cast_environment_->Logging()->InsertPacketEvent(receiver_clock_.NowTicks(),
+ PACKET_RECEIVED,
+ VIDEO_EVENT,
+ rtp_timestamp,
+ 0,
+ i,
+ 2,
+ 123);
+ }
+
+ StatsEventSubscriber::SimpleHistogram* histogram;
+ scoped_ptr<base::ListValue> values;
+
+ histogram = subscriber_->GetHistogramForTesting(
+ StatsEventSubscriber::CAPTURE_LATENCY_MS_HISTO);
+ ASSERT_TRUE(histogram);
+ values = histogram->GetHistogram().Pass();
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "10-14", 10));
+
+ histogram = subscriber_->GetHistogramForTesting(
+ StatsEventSubscriber::ENCODE_TIME_MS_HISTO);
+ ASSERT_TRUE(histogram);
+ values = histogram->GetHistogram().Pass();
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "15-19", 10));
+
+ histogram = subscriber_->GetHistogramForTesting(
+ StatsEventSubscriber::QUEUEING_LATENCY_MS_HISTO);
+ ASSERT_TRUE(histogram);
+ values = histogram->GetHistogram().Pass();
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1));
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "200-219", 1));
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "300-319", 1));
+
+ histogram = subscriber_->GetHistogramForTesting(
+ StatsEventSubscriber::NETWORK_LATENCY_MS_HISTO);
+ ASSERT_TRUE(histogram);
+ values = histogram->GetHistogram().Pass();
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1));
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "200-219", 1));
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "300-319", 1));
+
+ histogram = subscriber_->GetHistogramForTesting(
+ StatsEventSubscriber::PACKET_LATENCY_MS_HISTO);
+ ASSERT_TRUE(histogram);
+ values = histogram->GetHistogram().Pass();
+ EXPECT_TRUE(CheckHistogramHasValue(values.get(), "400-419", 3));
+}
+
} // namespace cast
} // namespace media