Add histogram stats for average send delay of sent packets for a sent video stream. The delay is measured from a packet is sent to the transport until leaving the socket.
- "WebRTC.Video.SendDelayInMs"
Change so that PacketOption packet id is always set in RtpSender (if having a TransportSequenceNumberAllocator).
Add SendDelayStats class for computing delays.
Add SendPacketObserver to RtpRtcp config and register SendDelayStats as observer.
Wire up OnSentPacket to SendDelayStats.
BUG=webrtc:5215
Review-Url: https://codereview.webrtc.org/1478253002
Cr-Commit-Position: refs/heads/master@{#12600}
diff --git a/webrtc/video/BUILD.gn b/webrtc/video/BUILD.gn
index 0bc5a12..74fad84 100644
--- a/webrtc/video/BUILD.gn
+++ b/webrtc/video/BUILD.gn
@@ -26,6 +26,8 @@
"report_block_stats.h",
"rtp_stream_receiver.cc",
"rtp_stream_receiver.h",
+ "send_delay_stats.cc",
+ "send_delay_stats.h",
"send_statistics_proxy.cc",
"send_statistics_proxy.h",
"stream_synchronization.cc",
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index 0e02ff8..f59044c 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -2176,6 +2176,7 @@
EXPECT_EQ(1, test::NumHistogramSamples(video_prefix + "SendSideDelayInMs"));
EXPECT_EQ(1,
test::NumHistogramSamples(video_prefix + "SendSideDelayMaxInMs"));
+ EXPECT_EQ(1, test::NumHistogramSamples("WebRTC.Video.SendDelayInMs"));
int num_rtx_samples = use_rtx ? 1 : 0;
EXPECT_EQ(num_rtx_samples, test::NumHistogramSamples(
diff --git a/webrtc/video/rtp_stream_receiver.cc b/webrtc/video/rtp_stream_receiver.cc
index 6421190..6def90f 100644
--- a/webrtc/video/rtp_stream_receiver.cc
+++ b/webrtc/video/rtp_stream_receiver.cc
@@ -53,6 +53,7 @@
configuration.send_bitrate_observer = nullptr;
configuration.send_frame_count_observer = nullptr;
configuration.send_side_delay_observer = nullptr;
+ configuration.send_packet_observer = nullptr;
configuration.bandwidth_callback = nullptr;
configuration.transport_feedback_callback = nullptr;
diff --git a/webrtc/video/send_delay_stats.cc b/webrtc/video/send_delay_stats.cc
new file mode 100644
index 0000000..8701066
--- /dev/null
+++ b/webrtc/video/send_delay_stats.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/video/send_delay_stats.h"
+
+#include "webrtc/base/logging.h"
+#include "webrtc/system_wrappers/include/metrics.h"
+
+namespace webrtc {
+namespace {
+// Packet with a larger delay are removed and excluded from the delay stats.
+// Set to larger than max histogram delay which is 10000.
+const int64_t kMaxSentPacketDelayMs = 11000;
+const size_t kMaxPacketMapSize = 2000;
+
+// Limit for the maximum number of streams to calculate stats for.
+const size_t kMaxSsrcMapSize = 50;
+const int kMinRequiredSamples = 200;
+} // namespace
+
+SendDelayStats::SendDelayStats(Clock* clock)
+ : clock_(clock), num_old_packets_(0), num_skipped_packets_(0) {}
+
+SendDelayStats::~SendDelayStats() {
+ if (num_old_packets_ > 0 || num_skipped_packets_ > 0) {
+ LOG(LS_WARNING) << "Delay stats: number of old packets " << num_old_packets_
+ << ", skipped packets " << num_skipped_packets_
+ << ". Number of streams " << send_delay_counters_.size();
+ }
+ UpdateHistograms();
+}
+
+void SendDelayStats::UpdateHistograms() {
+ rtc::CritScope lock(&crit_);
+ for (const auto& it : send_delay_counters_) {
+ int send_delay_ms = it.second.Avg(kMinRequiredSamples);
+ if (send_delay_ms != -1) {
+ RTC_LOGGED_HISTOGRAM_COUNTS_10000("WebRTC.Video.SendDelayInMs",
+ send_delay_ms);
+ }
+ }
+}
+
+void SendDelayStats::AddSsrcs(const VideoSendStream::Config& config) {
+ rtc::CritScope lock(&crit_);
+ if (ssrcs_.size() > kMaxSsrcMapSize)
+ return;
+ for (const auto& ssrc : config.rtp.ssrcs)
+ ssrcs_.insert(ssrc);
+}
+
+void SendDelayStats::OnSendPacket(uint16_t packet_id,
+ int64_t capture_time_ms,
+ uint32_t ssrc) {
+ // Packet sent to transport.
+ rtc::CritScope lock(&crit_);
+ if (ssrcs_.find(ssrc) == ssrcs_.end())
+ return;
+
+ int64_t now = clock_->TimeInMilliseconds();
+ RemoveOld(now, &packets_);
+
+ if (packets_.size() > kMaxPacketMapSize) {
+ ++num_skipped_packets_;
+ return;
+ }
+ packets_.insert(
+ std::make_pair(packet_id, Packet(ssrc, capture_time_ms, now)));
+}
+
+bool SendDelayStats::OnSentPacket(int packet_id, int64_t time_ms) {
+ // Packet leaving socket.
+ if (packet_id == -1)
+ return false;
+
+ rtc::CritScope lock(&crit_);
+ auto it = packets_.find(packet_id);
+ if (it == packets_.end())
+ return false;
+
+ // TODO(asapersson): Remove SendSideDelayUpdated(), use capture -> sent.
+ // Elapsed time from send (to transport) -> sent (leaving socket).
+ int diff_ms = time_ms - it->second.send_time_ms;
+ send_delay_counters_[it->second.ssrc].Add(diff_ms);
+ packets_.erase(it);
+ return true;
+}
+
+void SendDelayStats::RemoveOld(int64_t now, PacketMap* packets) {
+ while (!packets->empty()) {
+ auto it = packets->begin();
+ if (now - it->second.capture_time_ms < kMaxSentPacketDelayMs)
+ break;
+
+ packets->erase(it);
+ ++num_old_packets_;
+ }
+}
+
+void SendDelayStats::SampleCounter::Add(int sample) {
+ sum += sample;
+ ++num_samples;
+}
+
+int SendDelayStats::SampleCounter::Avg(int min_required_samples) const {
+ if (num_samples < min_required_samples || num_samples == 0)
+ return -1;
+ return (sum + (num_samples / 2)) / num_samples;
+}
+
+} // namespace webrtc
diff --git a/webrtc/video/send_delay_stats.h b/webrtc/video/send_delay_stats.h
new file mode 100644
index 0000000..20a9781
--- /dev/null
+++ b/webrtc/video/send_delay_stats.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_VIDEO_SEND_DELAY_STATS_H_
+#define WEBRTC_VIDEO_SEND_DELAY_STATS_H_
+
+#include <map>
+#include <memory>
+#include <set>
+
+#include "webrtc/base/criticalsection.h"
+#include "webrtc/base/thread_annotations.h"
+#include "webrtc/common_types.h"
+#include "webrtc/modules/include/module_common_types.h"
+#include "webrtc/system_wrappers/include/clock.h"
+#include "webrtc/video_send_stream.h"
+
+namespace webrtc {
+
+class SendDelayStats : public SendPacketObserver {
+ public:
+ explicit SendDelayStats(Clock* clock);
+ virtual ~SendDelayStats();
+
+ // Adds the configured ssrcs for the rtp streams.
+ // Stats will be calculated for these streams.
+ void AddSsrcs(const VideoSendStream::Config& config);
+
+ // Called when a packet is sent (leaving socket).
+ bool OnSentPacket(int packet_id, int64_t time_ms);
+
+ protected:
+ // From SendPacketObserver.
+ // Called when a packet is sent to the transport.
+ void OnSendPacket(uint16_t packet_id,
+ int64_t capture_time_ms,
+ uint32_t ssrc) override;
+
+ private:
+ // Map holding sent packets (mapped by sequence number).
+ struct SequenceNumberOlderThan {
+ bool operator()(uint16_t seq1, uint16_t seq2) const {
+ return IsNewerSequenceNumber(seq2, seq1);
+ }
+ };
+ struct Packet {
+ Packet(uint32_t ssrc, int64_t capture_time_ms, int64_t send_time_ms)
+ : ssrc(ssrc),
+ capture_time_ms(capture_time_ms),
+ send_time_ms(send_time_ms) {}
+ uint32_t ssrc;
+ int64_t capture_time_ms;
+ int64_t send_time_ms;
+ };
+ typedef std::map<uint16_t, Packet, SequenceNumberOlderThan> PacketMap;
+
+ class SampleCounter {
+ public:
+ SampleCounter() : sum(0), num_samples(0) {}
+ ~SampleCounter() {}
+ void Add(int sample);
+ int Avg(int min_required_samples) const;
+
+ private:
+ int sum;
+ int num_samples;
+ };
+
+ void UpdateHistograms();
+ void RemoveOld(int64_t now, PacketMap* packets)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_);
+
+ Clock* const clock_;
+ rtc::CriticalSection crit_;
+
+ PacketMap packets_ GUARDED_BY(crit_);
+ size_t num_old_packets_ GUARDED_BY(crit_);
+ size_t num_skipped_packets_ GUARDED_BY(crit_);
+
+ std::set<uint32_t> ssrcs_ GUARDED_BY(crit_);
+ std::map<uint32_t, SampleCounter> send_delay_counters_
+ GUARDED_BY(crit_); // Mapped by SSRC.
+};
+
+} // namespace webrtc
+#endif // WEBRTC_VIDEO_SEND_DELAY_STATS_H_
diff --git a/webrtc/video/send_delay_stats_unittest.cc b/webrtc/video/send_delay_stats_unittest.cc
new file mode 100644
index 0000000..44c62c3
--- /dev/null
+++ b/webrtc/video/send_delay_stats_unittest.cc
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/video/send_delay_stats.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/system_wrappers/include/metrics.h"
+#include "webrtc/test/histogram.h"
+
+namespace webrtc {
+namespace {
+const uint32_t kSsrc1 = 17;
+const uint32_t kSsrc2 = 42;
+const uint32_t kRtxSsrc1 = 18;
+const uint32_t kRtxSsrc2 = 43;
+const uint16_t kPacketId = 2345;
+const int64_t kMaxPacketDelayMs = 11000;
+const int kMinRequiredSamples = 200;
+} // namespace
+
+class SendDelayStatsTest : public ::testing::Test {
+ public:
+ SendDelayStatsTest() : clock_(1234), config_(CreateConfig()) {}
+ virtual ~SendDelayStatsTest() {}
+
+ protected:
+ virtual void SetUp() {
+ stats_.reset(new SendDelayStats(&clock_));
+ stats_->AddSsrcs(config_);
+ }
+
+ VideoSendStream::Config CreateConfig() {
+ VideoSendStream::Config config(nullptr);
+ config.rtp.ssrcs.push_back(kSsrc1);
+ config.rtp.ssrcs.push_back(kSsrc2);
+ config.rtp.rtx.ssrcs.push_back(kRtxSsrc1);
+ config.rtp.rtx.ssrcs.push_back(kRtxSsrc2);
+ return config;
+ }
+
+ void OnSendPacket(uint16_t id, uint32_t ssrc) {
+ OnSendPacket(id, ssrc, clock_.TimeInMilliseconds());
+ }
+
+ void OnSendPacket(uint16_t id, uint32_t ssrc, int64_t capture_ms) {
+ SendPacketObserver* observer = stats_.get();
+ observer->OnSendPacket(id, capture_ms, ssrc);
+ }
+
+ bool OnSentPacket(uint16_t id) {
+ return stats_->OnSentPacket(id, clock_.TimeInMilliseconds());
+ }
+
+ SimulatedClock clock_;
+ VideoSendStream::Config config_;
+ std::unique_ptr<SendDelayStats> stats_;
+};
+
+TEST_F(SendDelayStatsTest, SentPacketFound) {
+ EXPECT_FALSE(OnSentPacket(kPacketId));
+ OnSendPacket(kPacketId, kSsrc1);
+ EXPECT_TRUE(OnSentPacket(kPacketId)); // Packet found.
+ EXPECT_FALSE(OnSentPacket(kPacketId)); // Packet removed when found.
+}
+
+TEST_F(SendDelayStatsTest, SentPacketNotFoundForNonRegisteredSsrc) {
+ OnSendPacket(kPacketId, kSsrc1);
+ EXPECT_TRUE(OnSentPacket(kPacketId));
+ OnSendPacket(kPacketId + 1, kSsrc2);
+ EXPECT_TRUE(OnSentPacket(kPacketId + 1));
+ OnSendPacket(kPacketId + 2, kRtxSsrc1); // RTX SSRC not registered.
+ EXPECT_FALSE(OnSentPacket(kPacketId + 2));
+}
+
+TEST_F(SendDelayStatsTest, SentPacketFoundWithMaxSendDelay) {
+ OnSendPacket(kPacketId, kSsrc1);
+ clock_.AdvanceTimeMilliseconds(kMaxPacketDelayMs - 1);
+ OnSendPacket(kPacketId + 1, kSsrc1); // kPacketId -> not old/removed.
+ EXPECT_TRUE(OnSentPacket(kPacketId)); // Packet found.
+ EXPECT_TRUE(OnSentPacket(kPacketId + 1)); // Packet found.
+}
+
+TEST_F(SendDelayStatsTest, OldPacketsRemoved) {
+ const int64_t kCaptureTimeMs = clock_.TimeInMilliseconds();
+ OnSendPacket(0xffffu, kSsrc1, kCaptureTimeMs);
+ OnSendPacket(0u, kSsrc1, kCaptureTimeMs);
+ OnSendPacket(1u, kSsrc1, kCaptureTimeMs + 1);
+ clock_.AdvanceTimeMilliseconds(kMaxPacketDelayMs); // 0xffff, 0 -> old.
+ OnSendPacket(2u, kSsrc1, kCaptureTimeMs + 2);
+
+ EXPECT_FALSE(OnSentPacket(0xffffu)); // Old removed.
+ EXPECT_FALSE(OnSentPacket(0u)); // Old removed.
+ EXPECT_TRUE(OnSentPacket(1u));
+ EXPECT_TRUE(OnSentPacket(2u));
+}
+
+TEST_F(SendDelayStatsTest, HistogramsAreUpdated) {
+ test::ClearHistograms();
+ const int64_t kDelayMs1 = 5;
+ const int64_t kDelayMs2 = 10;
+ uint16_t id = 0;
+ for (int i = 0; i < kMinRequiredSamples; ++i) {
+ OnSendPacket(++id, kSsrc1);
+ clock_.AdvanceTimeMilliseconds(kDelayMs1);
+ EXPECT_TRUE(OnSentPacket(id));
+ OnSendPacket(++id, kSsrc2);
+ clock_.AdvanceTimeMilliseconds(kDelayMs2);
+ EXPECT_TRUE(OnSentPacket(id));
+ }
+ stats_.reset();
+ EXPECT_EQ(2, test::NumHistogramSamples("WebRTC.Video.SendDelayInMs"));
+ EXPECT_EQ(kDelayMs2, test::LastHistogramSample("WebRTC.Video.SendDelayInMs"));
+}
+
+} // namespace webrtc
diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc
index d7f4a62..636b9dc 100644
--- a/webrtc/video/send_statistics_proxy_unittest.cc
+++ b/webrtc/video/send_statistics_proxy_unittest.cc
@@ -110,10 +110,7 @@
TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
RtcpStatisticsCallback* callback = statistics_proxy_.get();
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
- it != config_.rtp.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.ssrcs) {
VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
// Add statistics with some arbitrary, but unique, numbers.
@@ -124,10 +121,7 @@
ssrc_stats.rtcp_stats.jitter = offset + 3;
callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc);
}
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
- it != config_.rtp.rtx.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
// Add statistics with some arbitrary, but unique, numbers.
@@ -170,10 +164,7 @@
TEST_F(SendStatisticsProxyTest, FrameCounts) {
FrameCountObserver* observer = statistics_proxy_.get();
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
- it != config_.rtp.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.ssrcs) {
// Add statistics with some arbitrary, but unique, numbers.
VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
@@ -183,10 +174,7 @@
stats.frame_counts = frame_counts;
observer->FrameCountUpdated(frame_counts, ssrc);
}
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
- it != config_.rtp.rtx.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
// Add statistics with some arbitrary, but unique, numbers.
VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
@@ -203,10 +191,7 @@
TEST_F(SendStatisticsProxyTest, DataCounters) {
StreamDataCountersCallback* callback = statistics_proxy_.get();
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
- it != config_.rtp.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.ssrcs) {
StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
// Add statistics with some arbitrary, but unique, numbers.
size_t offset = ssrc * sizeof(StreamDataCounters);
@@ -219,10 +204,7 @@
counters.transmitted.packets = offset_uint32 + 5;
callback->DataCountersUpdated(counters, ssrc);
}
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
- it != config_.rtp.rtx.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
// Add statistics with some arbitrary, but unique, numbers.
size_t offset = ssrc * sizeof(StreamDataCounters);
@@ -242,10 +224,7 @@
TEST_F(SendStatisticsProxyTest, Bitrate) {
BitrateStatisticsObserver* observer = statistics_proxy_.get();
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
- it != config_.rtp.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.ssrcs) {
BitrateStatistics total;
BitrateStatistics retransmit;
// Use ssrc as bitrate_bps to get a unique value for each stream.
@@ -255,10 +234,7 @@
expected_.substreams[ssrc].total_bitrate_bps = total.bitrate_bps;
expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit.bitrate_bps;
}
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
- it != config_.rtp.rtx.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
BitrateStatistics total;
BitrateStatistics retransmit;
// Use ssrc as bitrate_bps to get a unique value for each stream.
@@ -275,10 +251,7 @@
TEST_F(SendStatisticsProxyTest, SendSideDelay) {
SendSideDelayObserver* observer = statistics_proxy_.get();
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.ssrcs.begin();
- it != config_.rtp.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.ssrcs) {
// Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
// stream.
int avg_delay_ms = ssrc;
@@ -287,10 +260,7 @@
expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
}
- for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
- it != config_.rtp.rtx.ssrcs.end();
- ++it) {
- const uint32_t ssrc = *it;
+ for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
// Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
// stream.
int avg_delay_ms = ssrc;
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index c42c6d0..f27a858 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -47,6 +47,7 @@
RtpPacketSender* paced_sender,
TransportSequenceNumberAllocator* transport_sequence_number_allocator,
SendStatisticsProxy* stats_proxy,
+ SendDelayStats* send_delay_stats,
size_t num_modules) {
RTC_DCHECK_GT(num_modules, 0u);
RtpRtcp::Configuration configuration;
@@ -64,6 +65,7 @@
configuration.send_bitrate_observer = stats_proxy;
configuration.send_frame_count_observer = stats_proxy;
configuration.send_side_delay_observer = stats_proxy;
+ configuration.send_packet_observer = send_delay_stats;
configuration.bandwidth_callback = bandwidth_callback;
configuration.transport_feedback_callback = transport_feedback_callback;
@@ -348,6 +350,7 @@
CallStats* call_stats,
CongestionController* congestion_controller,
BitrateAllocator* bitrate_allocator,
+ SendDelayStats* send_delay_stats,
VieRemb* remb,
const VideoSendStream::Config& config,
const VideoEncoderConfig& encoder_config,
@@ -391,6 +394,7 @@
congestion_controller_->pacer(),
congestion_controller_->packet_router(),
&stats_proxy_,
+ send_delay_stats,
config_.rtp.ssrcs.size())),
payload_router_(rtp_rtcp_modules_, config.encoder_settings.payload_type),
input_(&encoder_wakeup_event_,
diff --git a/webrtc/video/video_send_stream.h b/webrtc/video/video_send_stream.h
index ead1abf..bdb0e64 100644
--- a/webrtc/video/video_send_stream.h
+++ b/webrtc/video/video_send_stream.h
@@ -22,6 +22,7 @@
#include "webrtc/video/encoded_frame_callback_adapter.h"
#include "webrtc/video/encoder_state_feedback.h"
#include "webrtc/video/payload_router.h"
+#include "webrtc/video/send_delay_stats.h"
#include "webrtc/video/send_statistics_proxy.h"
#include "webrtc/video/video_capture_input.h"
#include "webrtc/video/vie_channel.h"
@@ -57,6 +58,7 @@
CallStats* call_stats,
CongestionController* congestion_controller,
BitrateAllocator* bitrate_allocator,
+ SendDelayStats* send_delay_stats,
VieRemb* remb,
const VideoSendStream::Config& config,
const VideoEncoderConfig& encoder_config,
diff --git a/webrtc/video/webrtc_video.gypi b/webrtc/video/webrtc_video.gypi
index 514b21d..cb63a2e 100644
--- a/webrtc/video/webrtc_video.gypi
+++ b/webrtc/video/webrtc_video.gypi
@@ -40,6 +40,8 @@
'video/report_block_stats.h',
'video/rtp_stream_receiver.cc',
'video/rtp_stream_receiver.h',
+ 'video/send_delay_stats.cc',
+ 'video/send_delay_stats.h',
'video/send_statistics_proxy.cc',
'video/send_statistics_proxy.h',
'video/stream_synchronization.cc',