&fake_offset_estimator_);
}
- virtual ~StatsEventSubscriberTest() {
+ ~StatsEventSubscriberTest() override {
if (subscriber_.get())
cast_environment_->Logging()->RemoveRawEventSubscriber(subscriber_.get());
cast_environment_->Logging()->RemoveRawEventSubscriber(
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) {
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(),
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);
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.
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++;
}
i,
num_packets - 1,
size);
+ num_packets_received++;
}
base::TimeTicks end_time = sender_clock_->NowTicks();
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());
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());
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