Add RemoteEstimatorProxy for capturing receive times

For use when send-side bandwidth estimation is enabled.

Receive times need to be captured, buffered and then sent using
TransportFeedback RTCP messaged back to the send side.

BUG=webrtc:4173

Review URL: https://codereview.webrtc.org/1290813008

Cr-Commit-Position: refs/heads/master@{#9898}
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index a195683..a27516d 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -223,6 +223,7 @@
             'remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc',
             'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc',
             'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h',
+            'remote_bitrate_estimator/remote_estimator_proxy_unittest.cc',
             'remote_bitrate_estimator/send_time_history_unittest.cc',
             'remote_bitrate_estimator/test/bwe_test_framework_unittest.cc',
             'remote_bitrate_estimator/test/bwe_unittest.cc',
diff --git a/webrtc/modules/pacing/include/packet_router.h b/webrtc/modules/pacing/include/packet_router.h
index e7d630e..c181ec0 100644
--- a/webrtc/modules/pacing/include/packet_router.h
+++ b/webrtc/modules/pacing/include/packet_router.h
@@ -19,6 +19,7 @@
 #include "webrtc/base/thread_annotations.h"
 #include "webrtc/common_types.h"
 #include "webrtc/modules/pacing/include/paced_sender.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 
 namespace webrtc {
 
@@ -45,6 +46,9 @@
   void SetTransportWideSequenceNumber(uint16_t sequence_number);
   uint16_t AllocateSequenceNumber();
 
+  // Send transport feedback packet to send-side.
+  virtual bool SendFeedback(rtcp::TransportFeedback* packet);
+
  private:
   rtc::CriticalSection modules_lock_;
   // Map from ssrc to sending rtp module.
diff --git a/webrtc/modules/pacing/packet_router.cc b/webrtc/modules/pacing/packet_router.cc
index 1b12498..ac11903 100644
--- a/webrtc/modules/pacing/packet_router.cc
+++ b/webrtc/modules/pacing/packet_router.cc
@@ -14,6 +14,7 @@
 #include "webrtc/base/checks.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 
 namespace webrtc {
 
@@ -89,4 +90,14 @@
   return new_seq;
 }
 
+bool PacketRouter::SendFeedback(rtcp::TransportFeedback* packet) {
+  rtc::CritScope cs(&modules_lock_);
+  for (auto* rtp_module : rtp_modules_) {
+    packet->WithPacketSenderSsrc(rtp_module->SSRC());
+    if (rtp_module->SendFeedbackPacket(*packet))
+      return true;
+  }
+  return false;
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
index 3bbd503..5f4ed85 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
@@ -36,6 +36,8 @@
         'remote_bitrate_estimator_abs_send_time.h',
         'remote_bitrate_estimator_single_stream.cc',
         'remote_bitrate_estimator_single_stream.h',
+        'remote_estimator_proxy.cc',
+        'remote_estimator_proxy.h',
         'send_time_history.cc',
         'test/bwe_test_logging.cc',
         'test/bwe_test_logging.h',
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
new file mode 100644
index 0000000..3ded0df
--- /dev/null
+++ b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
@@ -0,0 +1,162 @@
+/*
+ *  Copyright (c) 2015 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/modules/remote_bitrate_estimator/remote_estimator_proxy.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/system_wrappers/interface/clock.h"
+#include "webrtc/modules/pacing/include/packet_router.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
+
+namespace webrtc {
+
+// TODO(sprang): Tune these!
+const int RemoteEstimatorProxy::kDefaultProcessIntervalMs = 200;
+const int RemoteEstimatorProxy::kBackWindowMs = 500;
+
+RemoteEstimatorProxy::RemoteEstimatorProxy(Clock* clock,
+                                           PacketRouter* packet_router)
+    : clock_(clock),
+      packet_router_(packet_router),
+      last_process_time_ms_(-1),
+      media_ssrc_(0),
+      feedback_sequence_(0),
+      window_start_seq_(-1) {}
+
+RemoteEstimatorProxy::~RemoteEstimatorProxy() {}
+
+void RemoteEstimatorProxy::IncomingPacketFeedbackVector(
+    const std::vector<PacketInfo>& packet_feedback_vector) {
+  rtc::CritScope cs(&lock_);
+  for (PacketInfo info : packet_feedback_vector)
+    OnPacketArrival(info.sequence_number, info.arrival_time_ms);
+}
+
+void RemoteEstimatorProxy::IncomingPacket(int64_t arrival_time_ms,
+                                          size_t payload_size,
+                                          const RTPHeader& header,
+                                          bool was_paced) {
+  DCHECK(header.extension.hasTransportSequenceNumber);
+  rtc::CritScope cs(&lock_);
+  media_ssrc_ = header.ssrc;
+  OnPacketArrival(header.extension.transportSequenceNumber, arrival_time_ms);
+}
+
+void RemoteEstimatorProxy::RemoveStream(unsigned int ssrc) {}
+
+bool RemoteEstimatorProxy::LatestEstimate(std::vector<unsigned int>* ssrcs,
+                                          unsigned int* bitrate_bps) const {
+  return false;
+}
+
+bool RemoteEstimatorProxy::GetStats(
+    ReceiveBandwidthEstimatorStats* output) const {
+  return false;
+}
+
+void RemoteEstimatorProxy::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
+}
+
+int64_t RemoteEstimatorProxy::TimeUntilNextProcess() {
+  int64_t now = clock_->TimeInMilliseconds();
+  int64_t time_until_next = 0;
+  if (last_process_time_ms_ != -1 &&
+      now - last_process_time_ms_ < kDefaultProcessIntervalMs) {
+    time_until_next = (last_process_time_ms_ + kDefaultProcessIntervalMs - now);
+  }
+  return time_until_next;
+}
+
+int32_t RemoteEstimatorProxy::Process() {
+  // TODO(sprang): Perhaps we need a dedicated thread here instead?
+
+  if (TimeUntilNextProcess() > 0)
+    return 0;
+  last_process_time_ms_ = clock_->TimeInMilliseconds();
+
+  bool more_to_build = true;
+  while (more_to_build) {
+    rtcp::TransportFeedback feedback_packet;
+    if (BuildFeedbackPacket(&feedback_packet)) {
+      DCHECK(packet_router_ != nullptr);
+      packet_router_->SendFeedback(&feedback_packet);
+    } else {
+      more_to_build = false;
+    }
+  }
+
+  return 0;
+}
+
+void RemoteEstimatorProxy::OnPacketArrival(uint16_t sequence_number,
+                                           int64_t arrival_time) {
+  int64_t seq = unwrapper_.Unwrap(sequence_number);
+
+  if (window_start_seq_ == -1) {
+    window_start_seq_ = seq;
+    // Start new feedback packet, cull old packets.
+    for (auto it = packet_arrival_times_.begin();
+         it != packet_arrival_times_.end() && it->first < seq &&
+         arrival_time - it->second >= kBackWindowMs;) {
+      auto delete_it = it;
+      ++it;
+      packet_arrival_times_.erase(delete_it);
+    }
+  } else if (seq < window_start_seq_) {
+    window_start_seq_ = seq;
+  }
+
+  DCHECK(packet_arrival_times_.end() == packet_arrival_times_.find(seq));
+  packet_arrival_times_[seq] = arrival_time;
+}
+
+bool RemoteEstimatorProxy::BuildFeedbackPacket(
+    rtcp::TransportFeedback* feedback_packet) {
+  rtc::CritScope cs(&lock_);
+  if (window_start_seq_ == -1)
+    return false;
+
+  // window_start_seq_ is the first sequence number to include in the current
+  // feedback packet. Some older may still be in the map, in case a reordering
+  // happens and we need to retransmit them.
+  auto it = packet_arrival_times_.find(window_start_seq_);
+  DCHECK(it != packet_arrival_times_.end());
+
+  // TODO(sprang): Measure receive times in microseconds and remove the
+  // conversions below.
+  feedback_packet->WithMediaSourceSsrc(media_ssrc_);
+  feedback_packet->WithBase(static_cast<uint16_t>(it->first & 0xFFFF),
+                            it->second * 1000);
+  feedback_packet->WithFeedbackSequenceNumber(feedback_sequence_++);
+  for (; it != packet_arrival_times_.end(); ++it) {
+    if (!feedback_packet->WithReceivedPacket(
+            static_cast<uint16_t>(it->first & 0xFFFF), it->second * 1000)) {
+      // If we can't even add the first seq to the feedback packet, we won't be
+      // able to build it at all.
+      CHECK_NE(window_start_seq_, it->first);
+
+      // Could not add timestamp, feedback packet might be full. Return and
+      // try again with a fresh packet.
+      window_start_seq_ = it->first;
+      break;
+    }
+    // Note: Don't erase items from packet_arrival_times_ after sending, in case
+    // they need to be re-sent after a reordering. Removal will be handled
+    // by OnPacketArrival once packets are too old.
+  }
+  if (it == packet_arrival_times_.end())
+    window_start_seq_ = -1;
+
+  return true;
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h
new file mode 100644
index 0000000..6d7390e
--- /dev/null
+++ b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h
@@ -0,0 +1,76 @@
+/*
+ *  Copyright (c) 2015 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_MODULES_REMOTE_BITRATE_ESTIMATOR_REMOTE_ESTIMATOR_PROXY_H_
+#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_REMOTE_ESTIMATOR_PROXY_H_
+
+#include <map>
+#include <vector>
+
+#include "webrtc/base/criticalsection.h"
+#include "webrtc/modules/interface/module_common_types.h"
+#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
+
+namespace webrtc {
+
+class Clock;
+class PacketRouter;
+namespace rtcp {
+class TransportFeedback;
+}
+
+// Class used when send-side BWE is enabled: This proxy is instantiated on the
+// receive side. It buffers a number of receive timestamps and then sends
+// transport feedback messages back too the send side.
+
+class RemoteEstimatorProxy : public RemoteBitrateEstimator {
+ public:
+  RemoteEstimatorProxy(Clock* clock, PacketRouter* packet_router);
+  virtual ~RemoteEstimatorProxy();
+
+  void IncomingPacketFeedbackVector(
+      const std::vector<PacketInfo>& packet_feedback_vector) override;
+  void IncomingPacket(int64_t arrival_time_ms,
+                      size_t payload_size,
+                      const RTPHeader& header,
+                      bool was_paced) override;
+  void RemoveStream(unsigned int ssrc) override;
+  bool LatestEstimate(std::vector<unsigned int>* ssrcs,
+                      unsigned int* bitrate_bps) const override;
+  bool GetStats(ReceiveBandwidthEstimatorStats* output) const override;
+  void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
+  int64_t TimeUntilNextProcess() override;
+  int32_t Process() override;
+
+  static const int kDefaultProcessIntervalMs;
+  static const int kBackWindowMs;
+
+ private:
+  void OnPacketArrival(uint16_t sequence_number, int64_t arrival_time)
+      EXCLUSIVE_LOCKS_REQUIRED(&lock_);
+  bool BuildFeedbackPacket(rtcp::TransportFeedback* feedback_packetket);
+
+  Clock* const clock_;
+  PacketRouter* const packet_router_;
+  int64_t last_process_time_ms_;
+
+  rtc::CriticalSection lock_;
+
+  uint32_t media_ssrc_ GUARDED_BY(&lock_);
+  uint8_t feedback_sequence_ GUARDED_BY(&lock_);
+  SequenceNumberUnwrapper unwrapper_ GUARDED_BY(&lock_);
+  int64_t window_start_seq_ GUARDED_BY(&lock_);
+  // Map unwrapped seq -> time.
+  std::map<int64_t, int64_t> packet_arrival_times_ GUARDED_BY(&lock_);
+};
+
+}  // namespace webrtc
+
+#endif  //  WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_REMOTE_ESTIMATOR_PROXY_H_
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc
new file mode 100644
index 0000000..5ebd921
--- /dev/null
+++ b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc
@@ -0,0 +1,272 @@
+/*
+ *  Copyright (c) 2015 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 "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/modules/pacing/include/packet_router.h"
+#include "webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "webrtc/system_wrappers/interface/clock.h"
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Invoke;
+
+namespace webrtc {
+
+class MockPacketRouter : public PacketRouter {
+ public:
+  MOCK_METHOD1(SendFeedback, bool(rtcp::TransportFeedback* packet));
+};
+
+class RemoteEstimatorProxyTest : public ::testing::Test {
+ public:
+  RemoteEstimatorProxyTest() : clock_(0), proxy_(&clock_, &router_) {}
+
+ protected:
+  void IncomingPacket(uint16_t seq, int64_t time_ms) {
+    RTPHeader header;
+    header.extension.hasTransportSequenceNumber = true;
+    header.extension.transportSequenceNumber = seq;
+    header.ssrc = kMediaSsrc;
+    proxy_.IncomingPacket(time_ms, kDefaultPacketSize, header, true);
+  }
+
+  void Process() {
+    clock_.AdvanceTimeMilliseconds(
+        RemoteEstimatorProxy::kDefaultProcessIntervalMs);
+    proxy_.Process();
+  }
+
+  SimulatedClock clock_;
+  MockPacketRouter router_;
+  RemoteEstimatorProxy proxy_;
+
+  const size_t kDefaultPacketSize = 100;
+  const uint32_t kMediaSsrc = 456;
+  const uint16_t kBaseSeq = 10;
+  const int64_t kBaseTimeMs = 123;
+  const int64_t kMaxSmallDeltaMs =
+      (rtcp::TransportFeedback::kDeltaScaleFactor * 0xFF) / 1000;
+};
+
+TEST_F(RemoteEstimatorProxyTest, SendsSinglePacketFeedback) {
+  IncomingPacket(kBaseSeq, kBaseTimeMs);
+
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
+        EXPECT_EQ(kMediaSsrc, packet->GetMediaSourceSsrc());
+
+        std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
+            packet->GetStatusVector();
+        EXPECT_EQ(1u, status_vec.size());
+        EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
+                  status_vec[0]);
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(1u, delta_vec.size());
+        EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        return true;
+      }));
+
+  Process();
+}
+
+TEST_F(RemoteEstimatorProxyTest, SendsFeedbackWithVaryingDeltas) {
+  IncomingPacket(kBaseSeq, kBaseTimeMs);
+  IncomingPacket(kBaseSeq + 1, kBaseTimeMs + kMaxSmallDeltaMs);
+  IncomingPacket(kBaseSeq + 2, kBaseTimeMs + (2 * kMaxSmallDeltaMs) + 1);
+
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
+        EXPECT_EQ(kMediaSsrc, packet->GetMediaSourceSsrc());
+
+        std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
+            packet->GetStatusVector();
+        EXPECT_EQ(3u, status_vec.size());
+        EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
+                  status_vec[0]);
+        EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
+                  status_vec[1]);
+        EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedLargeDelta,
+                  status_vec[2]);
+
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(3u, delta_vec.size());
+        EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        EXPECT_EQ(kMaxSmallDeltaMs, delta_vec[1] / 1000);
+        EXPECT_EQ(kMaxSmallDeltaMs + 1, delta_vec[2] / 1000);
+        return true;
+      }));
+
+  Process();
+}
+
+TEST_F(RemoteEstimatorProxyTest, SendsFragmentedFeedback) {
+  const int64_t kTooLargeDelta =
+      rtcp::TransportFeedback::kDeltaScaleFactor * (1 << 16);
+
+  IncomingPacket(kBaseSeq, kBaseTimeMs);
+  IncomingPacket(kBaseSeq + 1, kBaseTimeMs + kTooLargeDelta);
+
+  InSequence s;
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([kTooLargeDelta, this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
+        EXPECT_EQ(kMediaSsrc, packet->GetMediaSourceSsrc());
+
+        std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
+            packet->GetStatusVector();
+        EXPECT_EQ(1u, status_vec.size());
+        EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
+                  status_vec[0]);
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(1u, delta_vec.size());
+        EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        return true;
+      }))
+      .RetiresOnSaturation();
+
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([kTooLargeDelta, this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq + 1, packet->GetBaseSequence());
+        EXPECT_EQ(kMediaSsrc, packet->GetMediaSourceSsrc());
+
+        std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
+            packet->GetStatusVector();
+        EXPECT_EQ(1u, status_vec.size());
+        EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
+                  status_vec[0]);
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(1u, delta_vec.size());
+        EXPECT_EQ(kBaseTimeMs + kTooLargeDelta,
+                  (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        return true;
+      }))
+      .RetiresOnSaturation();
+
+  Process();
+}
+
+TEST_F(RemoteEstimatorProxyTest, ResendsTimestampsOnReordering) {
+  IncomingPacket(kBaseSeq, kBaseTimeMs);
+  IncomingPacket(kBaseSeq + 2, kBaseTimeMs + 2);
+
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
+        EXPECT_EQ(kMediaSsrc, packet->GetMediaSourceSsrc());
+
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(2u, delta_vec.size());
+        EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        EXPECT_EQ(2, delta_vec[1] / 1000);
+        return true;
+      }));
+
+  Process();
+
+  IncomingPacket(kBaseSeq + 1, kBaseTimeMs + 1);
+
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq + 1, packet->GetBaseSequence());
+        EXPECT_EQ(kMediaSsrc, packet->GetMediaSourceSsrc());
+
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(2u, delta_vec.size());
+        EXPECT_EQ(kBaseTimeMs + 1,
+                  (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        EXPECT_EQ(1, delta_vec[1] / 1000);
+        return true;
+      }));
+
+  Process();
+}
+
+TEST_F(RemoteEstimatorProxyTest, RemovesTimestampsOutOfScope) {
+  const int64_t kTimeoutTimeMs =
+      kBaseTimeMs + RemoteEstimatorProxy::kBackWindowMs;
+
+  IncomingPacket(kBaseSeq + 2, kBaseTimeMs);
+
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq + 2, packet->GetBaseSequence());
+
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(1u, delta_vec.size());
+        EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        return true;
+      }));
+
+  Process();
+
+  IncomingPacket(kBaseSeq + 3, kTimeoutTimeMs);  // kBaseSeq + 2 times out here.
+
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq + 3, packet->GetBaseSequence());
+
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(1u, delta_vec.size());
+        EXPECT_EQ(kTimeoutTimeMs,
+                  (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        return true;
+      }));
+
+  Process();
+
+  // New group, with sequence starting below the first so that they may be
+  // retransmitted.
+  IncomingPacket(kBaseSeq, kBaseTimeMs - 1);
+  IncomingPacket(kBaseSeq + 1, kTimeoutTimeMs - 1);
+
+  EXPECT_CALL(router_, SendFeedback(_))
+      .Times(1)
+      .WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
+        packet->Build();
+        EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
+
+        // Four status entries (kBaseSeq + 3 missing).
+        EXPECT_EQ(4u, packet->GetStatusVector().size());
+
+        // Only three actual timestamps.
+        std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
+        EXPECT_EQ(3u, delta_vec.size());
+        EXPECT_EQ(kBaseTimeMs - 1,
+                  (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
+        EXPECT_EQ(kTimeoutTimeMs - kBaseTimeMs, delta_vec[1] / 1000);
+        EXPECT_EQ(1, delta_vec[2] / 1000);
+        return true;
+      }));
+
+  Process();
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
index d8f9a94..6aa4687 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -25,6 +25,9 @@
 class RemoteBitrateEstimator;
 class RtpReceiver;
 class Transport;
+namespace rtcp {
+class TransportFeedback;
+}
 
 class RtpRtcp : public Module {
  public:
@@ -542,6 +545,8 @@
         RtcpStatisticsCallback* callback) = 0;
     virtual RtcpStatisticsCallback*
         GetRtcpStatisticsCallback() = 0;
+    // BWE feedback packets.
+    virtual bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) = 0;
 
     /**************************************************************************
     *
diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 13837d3..fe63239 100644
--- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -16,6 +16,7 @@
 #include "webrtc/modules/interface/module.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 
 namespace webrtc {
 
@@ -205,6 +206,7 @@
   MOCK_CONST_METHOD0(StorePackets, bool());
   MOCK_METHOD1(RegisterRtcpStatisticsCallback, void(RtcpStatisticsCallback*));
   MOCK_METHOD0(GetRtcpStatisticsCallback, RtcpStatisticsCallback*());
+  MOCK_METHOD1(SendFeedbackPacket, bool(const rtcp::TransportFeedback& packet));
   MOCK_METHOD1(RegisterAudioCallback,
       int32_t(RtpAudioFeedback* messagesCallback));
   MOCK_METHOD1(SetAudioPacketSize,
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
index fee634b..975d3f3 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
@@ -304,6 +304,13 @@
   media_source_ssrc_ = ssrc;
 }
 
+uint32_t TransportFeedback::GetPacketSenderSsrc() const {
+  return packet_sender_ssrc_;
+}
+
+uint32_t TransportFeedback::GetMediaSourceSsrc() const {
+  return media_source_ssrc_;
+}
 void TransportFeedback::WithBase(uint16_t base_sequence,
                                  int64_t ref_timestamp_us) {
   DCHECK_EQ(-1, base_seq_);
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
index 357355d..1bca184 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h
@@ -52,6 +52,8 @@
   // is relative the base time.
   std::vector<int64_t> GetReceiveDeltasUs() const;
 
+  uint32_t GetPacketSenderSsrc() const;
+  uint32_t GetMediaSourceSsrc() const;
   static const int kDeltaScaleFactor = 250;  // Convert to multiples of 0.25ms.
   static const uint8_t kFeedbackMessageType = 15;  // TODO(sprang): IANA reg?
   static const uint8_t kPayloadType = 205;         // RTPFB, see RFC4585.
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
index eed5cd6..6040805 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -21,6 +21,7 @@
 #include "webrtc/common_types.h"
 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/system_wrappers/interface/trace_event.h"
@@ -1210,4 +1211,29 @@
   return true;
 }
 
+bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) {
+  CriticalSectionScoped lock(critical_section_transport_.get());
+  if (!cbTransport_)
+    return false;
+
+  class Sender : public rtcp::RtcpPacket::PacketReadyCallback {
+   public:
+    Sender(Transport* transport, int32_t id)
+        : transport_(transport), id_(id), send_failure_(false) {}
+
+    void OnPacketReady(uint8_t* data, size_t length) override {
+      if (transport_->SendRTCPPacket(id_, data, length) <= 0)
+        send_failure_ = true;
+    }
+
+    Transport* const transport_;
+    int32_t id_;
+    bool send_failure_;
+  } sender(cbTransport_, id_);
+
+  uint8_t buffer[IP_PACKET_SIZE];
+  return packet.BuildExternalBuffer(buffer, IP_PACKET_SIZE, &sender) &&
+         !sender.send_failure_;
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
index 67d58aa..083ce78 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
@@ -33,6 +33,9 @@
 class ModuleRtpRtcpImpl;
 class RTCPReceiver;
 
+namespace rtcp {
+class TransportFeedback;
+}
 class NACKStringBuilder {
  public:
   NACKStringBuilder();
@@ -147,6 +150,7 @@
  void SetCsrcs(const std::vector<uint32_t>& csrcs);
 
  void SetTargetBitrate(unsigned int target_bitrate);
+ bool SendFeedbackPacket(const rtcp::TransportFeedback& packet);
 
 private:
  struct RtcpContext;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index df5fb65..523d000 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -768,6 +768,11 @@
   return rtcp_receiver_.GetRtcpStatisticsCallback();
 }
 
+bool ModuleRtpRtcpImpl::SendFeedbackPacket(
+    const rtcp::TransportFeedback& packet) {
+  return rtcp_sender_.SendFeedbackPacket(packet);
+}
+
 // Send a TelephoneEvent tone using RFC 2833 (4733).
 int32_t ModuleRtpRtcpImpl::SendTelephoneEventOutband(
     const uint8_t key,
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 5548e54..fe69437 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -228,6 +228,7 @@
       RtcpStatisticsCallback* callback) override;
   RtcpStatisticsCallback* GetRtcpStatisticsCallback() override;
 
+  bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override;
   // (APP) Application specific data.
   int32_t SetRTCPApplicationSpecificData(uint8_t sub_type,
                                          uint32_t name,