Reland "Wire up send-side bandwidth estimation."
Revert was patchset #8 id:140001 of https://codereview.webrtc.org/1338203003/

The culprit was RTC_DCHECK(poller_thread_->Start()); in rampup_test.cc

BUG=webrtc:4173
R=stefan@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#10052}
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index fb46a13..d593dd1 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -215,6 +215,7 @@
             'pacing/packet_router_unittest.cc',
             'remote_bitrate_estimator/bwe_simulations.cc',
             'remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h',
+            'remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h',
             'remote_bitrate_estimator/inter_arrival_unittest.cc',
             'remote_bitrate_estimator/overuse_detector_unittest.cc',
             'remote_bitrate_estimator/rate_statistics_unittest.cc',
diff --git a/webrtc/modules/remote_bitrate_estimator/BUILD.gn b/webrtc/modules/remote_bitrate_estimator/BUILD.gn
index 5f0be09..99c297d 100644
--- a/webrtc/modules/remote_bitrate_estimator/BUILD.gn
+++ b/webrtc/modules/remote_bitrate_estimator/BUILD.gn
@@ -36,7 +36,11 @@
     "overuse_estimator.h",
     "remote_bitrate_estimator_abs_send_time.cc",
     "remote_bitrate_estimator_single_stream.cc",
+    "remote_estimator_proxy.cc",
+    "remote_estimator_proxy.h",
     "send_time_history.cc",
+    "transport_feedback_adapter.cc",
+    "transport_feedback_adapter.h",
   ]
 
   configs += [ "../..:common_config" ]
diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc
index 4c01098..5f51bc5 100644
--- a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc
+++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.cc
@@ -107,6 +107,7 @@
                       << ". Send time history too small?";
     }
   }
+
   RTC_DCHECK(bitrate_estimator_.get() != nullptr);
   bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector);
 }
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
index 9ff7406..5e18116 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
@@ -111,7 +111,8 @@
   kRtcpRemb = 0x10000,
   kRtcpTransmissionTimeOffset = 0x20000,
   kRtcpXrReceiverReferenceTime = 0x40000,
-  kRtcpXrDlrrReportBlock = 0x80000
+  kRtcpXrDlrrReportBlock = 0x80000,
+  kRtcpTransportFeedback = 0x100000,
 };
 
 enum KeyFrameRequestMethod
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc
index a03af24..eb6d35e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc
@@ -60,7 +60,11 @@
   RtcpFormatRembTest()
       : over_use_detector_options_(),
         system_clock_(Clock::GetRealTimeClock()),
+        dummy_rtp_rtcp_impl_(nullptr),
         receive_statistics_(ReceiveStatistics::Create(system_clock_)),
+        rtcp_sender_(nullptr),
+        rtcp_receiver_(nullptr),
+        test_transport_(nullptr),
         remote_bitrate_observer_(),
         remote_bitrate_estimator_(new RemoteBitrateEstimatorSingleStream(
             &remote_bitrate_observer_,
@@ -87,9 +91,9 @@
   configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get();
   dummy_rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration);
   rtcp_sender_ =
-      new RTCPSender(false, system_clock_, receive_statistics_.get(), NULL);
-  rtcp_receiver_ = new RTCPReceiver(system_clock_, false, NULL, NULL, NULL,
-                                    dummy_rtp_rtcp_impl_);
+      new RTCPSender(false, system_clock_, receive_statistics_.get(), nullptr);
+  rtcp_receiver_ = new RTCPReceiver(system_clock_, false, nullptr, nullptr,
+                                    nullptr, nullptr, dummy_rtp_rtcp_impl_);
   test_transport_ = new TestTransport(rtcp_receiver_);
 
   EXPECT_EQ(0, rtcp_sender_->RegisterSendTransport(test_transport_));
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
index f295401..3c34957 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
@@ -91,6 +91,9 @@
                            size_t max_length,
                            PacketReadyCallback* callback) const;
 
+  // Size of this packet in bytes (including headers, excluding nested packets).
+  virtual size_t BlockLength() const = 0;
+
  protected:
   RtcpPacket() {}
 
@@ -109,7 +112,6 @@
                     size_t* index,
                     RtcpPacket::PacketReadyCallback* callback) const;
 
-  virtual size_t BlockLength() const = 0;
   size_t HeaderLength() const;
 
   static const size_t kHeaderLength = 4;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
index 4392f52..168557d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -17,6 +17,7 @@
 
 #include "webrtc/base/checks.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/logging.h"
@@ -29,12 +30,15 @@
 // The number of RTCP time intervals needed to trigger a timeout.
 const int kRrTimeoutIntervals = 3;
 
+const int64_t kMaxWarningLogIntervalMs = 10000;
+
 RTCPReceiver::RTCPReceiver(
     Clock* clock,
     bool receiver_only,
     RtcpPacketTypeCounterObserver* packet_type_counter_observer,
     RtcpBandwidthObserver* rtcp_bandwidth_observer,
     RtcpIntraFrameObserver* rtcp_intra_frame_observer,
+    TransportFeedbackObserver* transport_feedback_observer,
     ModuleRtpRtcpImpl* owner)
     : TMMBRHelp(),
       _clock(clock),
@@ -46,6 +50,7 @@
           CriticalSectionWrapper::CreateCriticalSection()),
       _cbRtcpBandwidthObserver(rtcp_bandwidth_observer),
       _cbRtcpIntraFrameObserver(rtcp_intra_frame_observer),
+      _cbTransportFeedbackObserver(transport_feedback_observer),
       _criticalSectionRTCPReceiver(
           CriticalSectionWrapper::CreateCriticalSection()),
       main_ssrc_(0),
@@ -61,7 +66,9 @@
       _lastReceivedRrMs(0),
       _lastIncreasedSequenceNumberMs(0),
       stats_callback_(NULL),
-      packet_type_counter_observer_(packet_type_counter_observer) {
+      packet_type_counter_observer_(packet_type_counter_observer),
+      num_skipped_packets_(0),
+      last_skipped_packets_warning_(clock->TimeInMilliseconds()) {
   memset(&_remoteSenderInfo, 0, sizeof(_remoteSenderInfo));
 }
 
@@ -349,6 +356,9 @@
             // generic application messages
             HandleAPPItem(*rtcpParser, rtcpPacketInformation);
             break;
+          case RTCPPacketTypes::kTransportFeedback:
+            HandleTransportFeedback(rtcpParser, &rtcpPacketInformation);
+            break;
         default:
             rtcpParser->Iterate();
             break;
@@ -361,6 +371,19 @@
           main_ssrc_, packet_type_counter_);
     }
 
+    num_skipped_packets_ += rtcpParser->NumSkippedBlocks();
+
+    int64_t now = _clock->TimeInMilliseconds();
+    if (now - last_skipped_packets_warning_ >= kMaxWarningLogIntervalMs &&
+        num_skipped_packets_ > 0) {
+      last_skipped_packets_warning_ = now;
+      LOG(LS_WARNING)
+          << num_skipped_packets_
+          << " RTCP blocks were skipped due to being malformed or of "
+             "unrecognized/unsupported type, during the past "
+          << (kMaxWarningLogIntervalMs / 1000) << " second period.";
+    }
+
     return 0;
 }
 
@@ -1252,6 +1275,17 @@
   rtcpParser.Iterate();
 }
 
+void RTCPReceiver::HandleTransportFeedback(
+    RTCPUtility::RTCPParserV2* rtcp_parser,
+    RTCPHelp::RTCPPacketInformation* rtcp_packet_information) {
+  rtcp::RtcpPacket* packet = rtcp_parser->ReleaseRtcpPacket();
+  RTC_DCHECK(packet != nullptr);
+  rtcp_packet_information->rtcpPacketTypeFlags |= kRtcpTransportFeedback;
+  rtcp_packet_information->transport_feedback_.reset(
+      static_cast<rtcp::TransportFeedback*>(packet));
+
+  rtcp_parser->Iterate();
+}
 int32_t RTCPReceiver::UpdateTMMBR() {
   int32_t numBoundingSet = 0;
   uint32_t bitrate = 0;
@@ -1321,11 +1355,11 @@
     local_ssrc = main_ssrc_;
   }
   if (!receiver_only_ &&
-      rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSrReq) {
+      (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpSrReq)) {
     _rtpRtcp.OnRequestSendReport();
   }
   if (!receiver_only_ &&
-      rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack) {
+      (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpNack)) {
     if (rtcpPacketInformation.nackSequenceNumbers.size() > 0) {
       LOG(LS_VERBOSE) << "Incoming NACK length: "
                    << rtcpPacketInformation.nackSequenceNumbers.size();
@@ -1376,6 +1410,17 @@
             now);
       }
     }
+    if (_cbTransportFeedbackObserver &&
+        (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTransportFeedback)) {
+      uint32_t media_source_ssrc =
+          rtcpPacketInformation.transport_feedback_->GetMediaSourceSsrc();
+      if (media_source_ssrc == main_ssrc_ ||
+          registered_ssrcs_.find(media_source_ssrc) !=
+              registered_ssrcs_.end()) {
+        _cbTransportFeedbackObserver->OnTransportFeedback(
+            *rtcpPacketInformation.transport_feedback_.get());
+      }
+    }
   }
 
   if (!receiver_only_) {
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
index 9392e51..68cf231 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -34,6 +34,7 @@
               RtcpPacketTypeCounterObserver* packet_type_counter_observer,
               RtcpBandwidthObserver* rtcp_bandwidth_observer,
               RtcpIntraFrameObserver* rtcp_intra_frame_observer,
+              TransportFeedbackObserver* transport_feedback_observer,
               ModuleRtpRtcpImpl* owner);
     virtual ~RTCPReceiver();
 
@@ -216,6 +217,10 @@
     void HandleAPPItem(RTCPUtility::RTCPParserV2& rtcpParser,
                        RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
 
+    void HandleTransportFeedback(
+        RTCPUtility::RTCPParserV2* rtcp_parser,
+        RTCPHelp::RTCPPacketInformation* rtcp_packet_information);
+
  private:
   typedef std::map<uint32_t, RTCPHelp::RTCPReceiveInformation*>
       ReceivedInfoMap;
@@ -241,6 +246,7 @@
   CriticalSectionWrapper* _criticalSectionFeedbacks;
   RtcpBandwidthObserver* const _cbRtcpBandwidthObserver;
   RtcpIntraFrameObserver* const _cbRtcpIntraFrameObserver;
+  TransportFeedbackObserver* const _cbTransportFeedbackObserver;
 
   CriticalSectionWrapper* _criticalSectionRTCPReceiver;
   uint32_t main_ssrc_;
@@ -282,6 +288,9 @@
   RtcpPacketTypeCounter packet_type_counter_;
 
   RTCPUtility::NackStats nack_stats_;
+
+  size_t num_skipped_packets_;
+  int64_t last_skipped_packets_warning_;
 };
 }  // namespace webrtc
 #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc
index b86e5cc..718990d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc
@@ -13,6 +13,7 @@
 #include <assert.h>  // assert
 #include <string.h>  // memset
 
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
 
 namespace webrtc {
@@ -36,8 +37,7 @@
       rtp_timestamp(0),
       xr_originator_ssrc(0),
       xr_dlrr_item(false),
-      VoIPMetric(NULL) {
-}
+      VoIPMetric(nullptr) {}
 
 RTCPPacketInformation::~RTCPPacketInformation()
 {
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h
index 790fe81..37b7b88 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h
@@ -20,6 +20,9 @@
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
+namespace rtcp {
+class TransportFeedback;
+}
 namespace RTCPHelp
 {
 
@@ -84,6 +87,8 @@
     bool xr_dlrr_item;
     RTCPVoIPMetric*  VoIPMetric;
 
+    rtc::scoped_ptr<rtcp::TransportFeedback> transport_feedback_;
+
 private:
     RTC_DISALLOW_COPY_AND_ASSIGN(RTCPPacketInformation);
 };
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index 6ef2a14..e09c29d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -33,9 +33,7 @@
 class TestTransport : public Transport,
                       public NullRtpData {
  public:
-  explicit TestTransport()
-      : rtcp_receiver_(NULL) {
-  }
+  explicit TestTransport() : rtcp_receiver_(nullptr) {}
   void SetRTCPReceiver(RTCPReceiver* rtcp_receiver) {
     rtcp_receiver_ = rtcp_receiver;
   }
@@ -78,8 +76,8 @@
     configuration.outgoing_transport = test_transport_;
     configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get();
     rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration);
-    rtcp_receiver_ = new RTCPReceiver(&system_clock_, false, NULL, NULL, NULL,
-                                      rtp_rtcp_impl_);
+    rtcp_receiver_ = new RTCPReceiver(&system_clock_, false, nullptr, nullptr,
+                                      nullptr, nullptr, rtp_rtcp_impl_);
     test_transport_->SetRTCPReceiver(rtcp_receiver_);
   }
   ~RtcpReceiverTest() {
@@ -362,7 +360,8 @@
   rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
 
   // No report block received.
-  EXPECT_EQ(-1, rtcp_receiver_->RTT(kSenderSsrc, NULL, NULL, NULL, NULL));
+  EXPECT_EQ(
+      -1, rtcp_receiver_->RTT(kSenderSsrc, nullptr, nullptr, nullptr, nullptr));
 
   rtcp::ReportBlock rb;
   rb.To(kSourceSsrc);
@@ -374,10 +373,12 @@
   EXPECT_EQ(kSenderSsrc, rtcp_packet_info_.remoteSSRC);
   EXPECT_EQ(kRtcpRr, rtcp_packet_info_.rtcpPacketTypeFlags);
   EXPECT_EQ(1u, rtcp_packet_info_.report_blocks.size());
-  EXPECT_EQ(0, rtcp_receiver_->RTT(kSenderSsrc, NULL, NULL, NULL, NULL));
+  EXPECT_EQ(
+      0, rtcp_receiver_->RTT(kSenderSsrc, nullptr, nullptr, nullptr, nullptr));
 
   // Report block not received.
-  EXPECT_EQ(-1, rtcp_receiver_->RTT(kSenderSsrc + 1, NULL, NULL, NULL, NULL));
+  EXPECT_EQ(-1, rtcp_receiver_->RTT(kSenderSsrc + 1, nullptr, nullptr, nullptr,
+                                    nullptr));
 }
 
 TEST_F(RtcpReceiverTest, InjectIjWithNoItem) {
@@ -589,7 +590,7 @@
   xr.WithVoipMetric(&voip_metric);
   rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
   EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
-  ASSERT_TRUE(rtcp_packet_info_.VoIPMetric != NULL);
+  ASSERT_TRUE(rtcp_packet_info_.VoIPMetric != nullptr);
   EXPECT_EQ(kLossRate, rtcp_packet_info_.VoIPMetric->lossRate);
   EXPECT_EQ(kRtcpXrVoipMetric, rtcp_packet_info_.rtcpPacketTypeFlags);
 }
@@ -843,7 +844,7 @@
 
 TEST_F(RtcpReceiverTest, TmmbrReceivedWithNoIncomingPacket) {
   // This call is expected to fail because no data has arrived.
-  EXPECT_EQ(-1, rtcp_receiver_->TMMBRReceived(0, 0, NULL));
+  EXPECT_EQ(-1, rtcp_receiver_->TMMBRReceived(0, 0, nullptr));
 }
 
 TEST_F(RtcpReceiverTest, TmmbrPacketAccepted) {
@@ -864,7 +865,7 @@
   rtc::scoped_ptr<rtcp::RawPacket> packet(sr.Build());
   EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
 
-  EXPECT_EQ(1, rtcp_receiver_->TMMBRReceived(0, 0, NULL));
+  EXPECT_EQ(1, rtcp_receiver_->TMMBRReceived(0, 0, nullptr));
   TMMBRSet candidate_set;
   candidate_set.VerifyAndAllocateSet(1);
   EXPECT_EQ(1, rtcp_receiver_->TMMBRReceived(1, 0, &candidate_set));
@@ -890,7 +891,7 @@
   ssrcs.insert(kMediaFlowSsrc);
   rtcp_receiver_->SetSsrcs(kMediaFlowSsrc, ssrcs);
   EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
-  EXPECT_EQ(0, rtcp_receiver_->TMMBRReceived(0, 0, NULL));
+  EXPECT_EQ(0, rtcp_receiver_->TMMBRReceived(0, 0, nullptr));
 }
 
 TEST_F(RtcpReceiverTest, TmmbrPacketZeroRateIgnored) {
@@ -911,7 +912,7 @@
   rtc::scoped_ptr<rtcp::RawPacket> packet(sr.Build());
 
   EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
-  EXPECT_EQ(0, rtcp_receiver_->TMMBRReceived(0, 0, NULL));
+  EXPECT_EQ(0, rtcp_receiver_->TMMBRReceived(0, 0, nullptr));
 }
 
 TEST_F(RtcpReceiverTest, TmmbrThreeConstraintsTimeOut) {
@@ -938,7 +939,7 @@
     system_clock_.AdvanceTimeMilliseconds(5000);
   }
   // It is now starttime + 15.
-  EXPECT_EQ(3, rtcp_receiver_->TMMBRReceived(0, 0, NULL));
+  EXPECT_EQ(3, rtcp_receiver_->TMMBRReceived(0, 0, nullptr));
   TMMBRSet candidate_set;
   candidate_set.VerifyAndAllocateSet(3);
   EXPECT_EQ(3, rtcp_receiver_->TMMBRReceived(3, 0, &candidate_set));
@@ -947,7 +948,7 @@
   // seconds, timing out the first packet.
   system_clock_.AdvanceTimeMilliseconds(12000);
   // Odd behaviour: Just counting them does not trigger the timeout.
-  EXPECT_EQ(3, rtcp_receiver_->TMMBRReceived(0, 0, NULL));
+  EXPECT_EQ(3, rtcp_receiver_->TMMBRReceived(0, 0, nullptr));
   EXPECT_EQ(2, rtcp_receiver_->TMMBRReceived(3, 0, &candidate_set));
   EXPECT_EQ(kSenderSsrc + 1, candidate_set.Ssrc(0));
 }
@@ -1008,7 +1009,7 @@
   EXPECT_TRUE(callback.Matches(kSourceSsrc, kSequenceNumber, kFractionLoss,
                                kCumulativeLoss, kJitter));
 
-  rtcp_receiver_->RegisterRtcpStatisticsCallback(NULL);
+  rtcp_receiver_->RegisterRtcpStatisticsCallback(nullptr);
 
   // Add arbitrary numbers, callback should not be called (retain old values).
   rtcp::ReportBlock rb2;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
index e0195f1..fa6468e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
@@ -33,9 +33,6 @@
 class ModuleRtpRtcpImpl;
 class RTCPReceiver;
 
-namespace rtcp {
-class TransportFeedback;
-}
 class NACKStringBuilder {
  public:
   NACKStringBuilder();
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
index caffb63..6c1deb4 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
@@ -8,7 +8,9 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include "webrtc/base/checks.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
 
 #include <assert.h>
 #include <math.h>   // ceil
@@ -55,6 +57,7 @@
       _ptrRTCPBlockEnd(NULL),
       _state(ParseState::State_TopLevel),
       _numberOfBlocks(0),
+      num_skipped_blocks_(0),
       _packetType(RTCPPacketTypes::kInvalid) {
   Validate();
 }
@@ -80,6 +83,9 @@
     return _packet;
 }
 
+rtcp::RtcpPacket* RTCPUtility::RTCPParserV2::ReleaseRtcpPacket() {
+  return rtcp_packet_.release();
+}
 RTCPUtility::RTCPPacketTypes
 RTCPUtility::RTCPParserV2::Begin()
 {
@@ -147,7 +153,7 @@
             IterateAppItem();
             break;
         default:
-            assert(false); // Invalid state!
+          RTC_NOTREACHED() << "Invalid state!";
             break;
         }
     }
@@ -170,7 +176,7 @@
         _ptrRTCPBlockEnd = _ptrRTCPData + header.BlockSize();
         if (_ptrRTCPBlockEnd > _ptrRTCPDataEnd)
         {
-            // Bad block!
+          ++num_skipped_blocks_;
             return;
         }
 
@@ -219,16 +225,15 @@
             ParseIJ();
             return;
         }
-        case PT_RTPFB: // Fall through!
+        case PT_RTPFB:
+          FALLTHROUGH();
         case PT_PSFB:
         {
-            const bool ok = ParseFBCommon(header);
-            if (!ok)
-            {
-                // Nothing supported found, continue to next block!
-                break;
-            }
-            return;
+          if (!ParseFBCommon(header)) {
+            // Nothing supported found, continue to next block!
+            break;
+          }
+          return;
         }
         case PT_APP:
         {
@@ -252,6 +257,7 @@
         }
         default:
             // Not supported! Skip!
+            ++num_skipped_blocks_;
             EndCurrentBlock();
             break;
         }
@@ -1160,28 +1166,26 @@
 }
 
 bool RTCPUtility::RTCPParserV2::ParseFBCommon(const RtcpCommonHeader& header) {
-  assert((header.packet_type == PT_RTPFB) ||
-         (header.packet_type == PT_PSFB));  // Parser logic check
+  RTC_CHECK((header.packet_type == PT_RTPFB) ||
+            (header.packet_type == PT_PSFB));  // Parser logic check
 
     const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
 
-    if (length < 12) // 4 * 3, RFC4585 section 6.1
-    {
-        EndCurrentBlock();
+    // 4 * 3, RFC4585 section 6.1
+    if (length < 12) {
+      LOG(LS_WARNING)
+          << "Invalid RTCP packet: Too little data (" << length
+          << " bytes) left in buffer to parse a 12 byte RTPFB/PSFB message.";
         return false;
     }
 
     _ptrRTCPData += 4; // Skip RTCP header
 
-    uint32_t senderSSRC = *_ptrRTCPData++ << 24;
-    senderSSRC += *_ptrRTCPData++ << 16;
-    senderSSRC += *_ptrRTCPData++ << 8;
-    senderSSRC += *_ptrRTCPData++;
+    uint32_t senderSSRC = ByteReader<uint32_t>::ReadBigEndian(_ptrRTCPData);
+    _ptrRTCPData += 4;
 
-    uint32_t mediaSSRC = *_ptrRTCPData++ << 24;
-    mediaSSRC += *_ptrRTCPData++ << 16;
-    mediaSSRC += *_ptrRTCPData++ << 8;
-    mediaSSRC += *_ptrRTCPData++;
+    uint32_t mediaSSRC = ByteReader<uint32_t>::ReadBigEndian(_ptrRTCPData);
+    _ptrRTCPData += 4;
 
     if (header.packet_type == PT_RTPFB) {
         // Transport layer feedback
@@ -1198,12 +1202,6 @@
 
             return true;
         }
-        case 2:
-        {
-            // used to be ACK is this code point, which is removed
-            // conficts with http://tools.ietf.org/html/draft-levin-avt-rtcp-burst-00
-            break;
-        }
         case 3:
         {
             // TMMBR
@@ -1236,10 +1234,23 @@
             // Note: No state transition, SR REQ is empty!
             return true;
         }
+        case 15: {
+          _packetType = RTCPPacketTypes::kTransportFeedback;
+          rtcp_packet_ =
+              rtcp::TransportFeedback::ParseFrom(_ptrRTCPData - 12, length);
+          // Since we parse the whole packet here, keep the TopLevel state and
+          // just end the current block.
+          if (rtcp_packet_.get()) {
+            EndCurrentBlock();
+            return true;
+          }
+          break;
+        }
         default:
             break;
         }
-        EndCurrentBlock();
+        // Unsupported RTPFB message. Skip and move to next block.
+        ++num_skipped_blocks_;
         return false;
     } else if (header.packet_type == PT_PSFB) {
         // Payload specific feedback
@@ -1287,14 +1298,11 @@
             break;
         }
 
-        EndCurrentBlock();
         return false;
     }
     else
     {
-        assert(false);
-
-        EndCurrentBlock();
+      RTC_NOTREACHED();
         return false;
     }
 }
@@ -1654,6 +1662,10 @@
     return true;
 }
 
+size_t RTCPUtility::RTCPParserV2::NumSkippedBlocks() const {
+  return num_skipped_blocks_;
+}
+
 RTCPUtility::RTCPPacketIterator::RTCPPacketIterator(uint8_t* rtcpData,
                                                     size_t rtcpDataLength)
     : _ptrBegin(rtcpData),
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
index 73658a0..f05d512 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
@@ -13,11 +13,15 @@
 
 #include <stddef.h> // size_t, ptrdiff_t
 
+#include "webrtc/base/scoped_ptr.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
+namespace rtcp {
+class RtcpPacket;
+}
 namespace RTCPUtility {
 
 class NackStats {
@@ -294,6 +298,9 @@
 
   kApp,
   kAppItem,
+
+  // draft-holmer-rmcat-transport-wide-cc-extensions
+  kTransportFeedback,
 };
 
 struct RTCPRawPacket {
@@ -359,10 +366,12 @@
 
   RTCPPacketTypes PacketType() const;
   const RTCPPacket& Packet() const;
+  rtcp::RtcpPacket* ReleaseRtcpPacket();
   const RTCPRawPacket& RawPacket() const;
   ptrdiff_t LengthLeft() const;
 
   bool IsValid() const;
+  size_t NumSkippedBlocks() const;
 
   RTCPPacketTypes Begin();
   RTCPPacketTypes Iterate();
@@ -454,9 +463,11 @@
 
   ParseState _state;
   uint8_t _numberOfBlocks;
+  size_t num_skipped_blocks_;
 
   RTCPPacketTypes _packetType;
   RTCPPacket _packet;
+  rtc::scoped_ptr<webrtc::rtcp::RtcpPacket> rtcp_packet_;
 };
 
 class RTCPPacketIterator {
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index d941201..ae4caf7 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -78,6 +78,7 @@
                      configuration.rtcp_packet_type_counter_observer,
                      configuration.bandwidth_callback,
                      configuration.intra_frame_callback,
+                     configuration.transport_feedback_callback,
                      this),
       clock_(configuration.clock),
       audio_(configuration.audio),
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index 00e7279..7224478 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -15,6 +15,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #include "webrtc/base/checks.h"
+#include "webrtc/base/event.h"
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/call.h"
 #include "webrtc/frame_callback.h"
@@ -1445,6 +1446,68 @@
   tester.RunTest();
 }
 
+TEST_F(EndToEndTest, ReceivesTransportFeedback) {
+  static const int kExtensionId = 5;
+
+  class TransportFeedbackObserver : public test::DirectTransport {
+   public:
+    TransportFeedbackObserver(rtc::Event* done_event) : done_(done_event) {}
+    virtual ~TransportFeedbackObserver() {}
+
+    bool SendRtcp(const uint8_t* data, size_t length) override {
+      RTCPUtility::RTCPParserV2 parser(data, length, true);
+      EXPECT_TRUE(parser.IsValid());
+
+      RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
+      while (packet_type != RTCPUtility::RTCPPacketTypes::kInvalid) {
+        if (packet_type == RTCPUtility::RTCPPacketTypes::kTransportFeedback) {
+          done_->Set();
+          break;
+        }
+        packet_type = parser.Iterate();
+      }
+
+      return test::DirectTransport::SendRtcp(data, length);
+    }
+
+    rtc::Event* done_;
+  };
+
+  class TransportFeedbackTester : public MultiStreamTest {
+   public:
+    TransportFeedbackTester() : done_(false, false) {}
+    virtual ~TransportFeedbackTester() {}
+
+   protected:
+    void Wait() override {
+      EXPECT_TRUE(done_.Wait(CallTest::kDefaultTimeoutMs));
+    }
+
+    void UpdateSendConfig(
+        size_t stream_index,
+        VideoSendStream::Config* send_config,
+        VideoEncoderConfig* encoder_config,
+        test::FrameGeneratorCapturer** frame_generator) override {
+      send_config->rtp.extensions.push_back(
+          RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
+    }
+
+    void UpdateReceiveConfig(
+        size_t stream_index,
+        VideoReceiveStream::Config* receive_config) override {
+      receive_config->rtp.extensions.push_back(
+          RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
+    }
+
+    virtual test::DirectTransport* CreateReceiveTransport() {
+      return new TransportFeedbackObserver(&done_);
+    }
+
+   private:
+    rtc::Event done_;
+  } tester;
+  tester.RunTest();
+}
 TEST_F(EndToEndTest, ObserversEncodedFrames) {
   class EncodedFrameTestObserver : public EncodedFrameObserver {
    public:
diff --git a/webrtc/video/rampup_tests.cc b/webrtc/video/rampup_tests.cc
index d308f2d..f69f8ce 100644
--- a/webrtc/video/rampup_tests.cc
+++ b/webrtc/video/rampup_tests.cc
@@ -11,14 +11,18 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/base/common.h"
+#include "webrtc/base/event.h"
+#include "webrtc/modules/pacing/include/packet_router.h"
 #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h"
 #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h"
+#include "webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h"
 #include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/interface/thread_wrapper.h"
 #include "webrtc/test/testsupport/perf_test.h"
 #include "webrtc/video/rampup_tests.h"
 
@@ -70,14 +74,22 @@
   rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
   rtp_rtcp_->SetREMBStatus(true);
   rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
+  packet_router_.reset(new PacketRouter());
+  packet_router_->AddRtpModule(rtp_rtcp_.get());
   rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
                                           kAbsSendTimeExtensionId);
   rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
                                           kTransmissionTimeOffsetExtensionId);
+  rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber,
+                                          kTransportSequenceNumberExtensionId);
   payload_registry_->SetRtxPayloadType(RampUpTest::kSendRtxPayloadType,
                                        RampUpTest::kFakeSendPayloadType);
 }
 
+StreamObserver::~StreamObserver() {
+  packet_router_->RemoveRtpModule(rtp_rtcp_.get());
+}
+
 void StreamObserver::set_expected_bitrate_bps(
     unsigned int expected_bitrate_bps) {
   rtc::CritScope lock(&crit_);
@@ -163,6 +175,10 @@
   remote_bitrate_estimator_.reset(rbe);
 }
 
+PacketRouter* StreamObserver::GetPacketRouter() {
+  return packet_router_.get();
+}
+
 void StreamObserver::ReportResult(const std::string& measurement,
                   size_t value,
                   const std::string& units) {
@@ -371,6 +387,49 @@
   return test_done_->Wait(test::CallTest::kLongTimeoutMs);
 }
 
+class SendBitrateAdapter {
+ public:
+  static const int64_t kPollIntervalMs = 250;
+
+  SendBitrateAdapter(const Call& call,
+                     const std::vector<uint32_t>& ssrcs,
+                     RemoteBitrateObserver* bitrate_observer)
+      : event_(false, false),
+        call_(call),
+        ssrcs_(ssrcs),
+        bitrate_observer_(bitrate_observer) {
+    RTC_DCHECK(bitrate_observer != nullptr);
+    poller_thread_ = ThreadWrapper::CreateThread(&SendBitrateAdapterThread,
+                                                 this, "SendBitratePoller");
+    bool thread_start_ok = poller_thread_->Start();
+    RTC_DCHECK(thread_start_ok);
+  }
+
+  virtual ~SendBitrateAdapter() {
+    event_.Set();
+    poller_thread_->Stop();
+  }
+
+ private:
+  static bool SendBitrateAdapterThread(void* obj) {
+    return static_cast<SendBitrateAdapter*>(obj)->PollStats();
+  }
+
+  bool PollStats() {
+    Call::Stats stats = call_.GetStats();
+
+    bitrate_observer_->OnReceiveBitrateChanged(ssrcs_,
+                                               stats.send_bandwidth_bps);
+    return !event_.Wait(kPollIntervalMs);
+  }
+
+  rtc::Event event_;
+  rtc::scoped_ptr<ThreadWrapper> poller_thread_;
+  const Call& call_;
+  const std::vector<uint32_t> ssrcs_;
+  RemoteBitrateObserver* const bitrate_observer_;
+};
+
 void RampUpTest::RunRampUpTest(size_t num_streams,
                                unsigned int start_bitrate_bps,
                                const std::string& extension_type,
@@ -391,6 +450,8 @@
   CreateSendConfig(num_streams, &stream_observer);
   send_config_.rtp.extensions.clear();
 
+  rtc::scoped_ptr<SendBitrateAdapter> send_bitrate_adapter_;
+
   if (extension_type == RtpExtension::kAbsSendTime) {
     stream_observer.SetRemoteBitrateEstimator(
         new RemoteBitrateEstimatorAbsSendTime(
@@ -398,6 +459,11 @@
             kRemoteBitrateEstimatorMinBitrateBps));
     send_config_.rtp.extensions.push_back(RtpExtension(
         extension_type.c_str(), kAbsSendTimeExtensionId));
+  } else if (extension_type == RtpExtension::kTransportSequenceNumber) {
+    stream_observer.SetRemoteBitrateEstimator(new RemoteEstimatorProxy(
+        Clock::GetRealTimeClock(), stream_observer.GetPacketRouter()));
+    send_config_.rtp.extensions.push_back(RtpExtension(
+        extension_type.c_str(), kTransportSequenceNumberExtensionId));
   } else {
     stream_observer.SetRemoteBitrateEstimator(
         new RemoteBitrateEstimatorSingleStream(
@@ -449,10 +515,18 @@
   CreateStreams();
   CreateFrameGeneratorCapturer();
 
+  if (extension_type == RtpExtension::kTransportSequenceNumber) {
+    send_bitrate_adapter_.reset(
+        new SendBitrateAdapter(*sender_call_.get(), ssrcs, &stream_observer));
+  }
   Start();
 
   EXPECT_EQ(kEventSignaled, stream_observer.Wait());
 
+  // Destroy the SendBitrateAdapter (if any) to stop the poller thread in it,
+  // otherwise we might get a data race with the destruction of the call.
+  send_bitrate_adapter_.reset();
+
   Stop();
   DestroyStreams();
 }
@@ -563,4 +637,25 @@
   RunRampUpTest(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kAbsSendTime,
                 false, false);
 }
+
+TEST_F(RampUpTest, TransportSequenceNumberSingleStream) {
+  RunRampUpTest(1, 0, RtpExtension::kTransportSequenceNumber, false, false);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSimulcast) {
+  RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, false, false);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSimulcastWithRtx) {
+  RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, true, false);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSimulcastByRedWithRtx) {
+  RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, true, true);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSingleStreamWithHighStartBitrate) {
+  RunRampUpTest(1, 0.9 * kSingleStreamTargetBps,
+                RtpExtension::kTransportSequenceNumber, false, false);
+}
 }  // namespace webrtc
diff --git a/webrtc/video/rampup_tests.h b/webrtc/video/rampup_tests.h
index 56c5e75..8c18a52 100644
--- a/webrtc/video/rampup_tests.h
+++ b/webrtc/video/rampup_tests.h
@@ -26,9 +26,11 @@
 
 static const int kTransmissionTimeOffsetExtensionId = 6;
 static const int kAbsSendTimeExtensionId = 7;
+static const int kTransportSequenceNumberExtensionId = 8;
 static const unsigned int kSingleStreamTargetBps = 1000000;
 
 class Clock;
+class PacketRouter;
 class ReceiveStatistics;
 class RtpHeaderParser;
 class RTPPayloadRegistry;
@@ -41,6 +43,7 @@
   StreamObserver(const SsrcMap& rtx_media_ssrcs,
                  newapi::Transport* feedback_transport,
                  Clock* clock);
+  virtual ~StreamObserver();
 
   void set_expected_bitrate_bps(unsigned int expected_bitrate_bps);
 
@@ -57,6 +60,8 @@
 
   void SetRemoteBitrateEstimator(RemoteBitrateEstimator* rbe);
 
+  PacketRouter* GetPacketRouter();
+
  private:
   void ReportResult(const std::string& measurement,
                     size_t value,
@@ -67,6 +72,7 @@
   const rtc::scoped_ptr<EventWrapper> test_done_;
   const rtc::scoped_ptr<RtpHeaderParser> rtp_parser_;
   rtc::scoped_ptr<RtpRtcp> rtp_rtcp_;
+  rtc::scoped_ptr<PacketRouter> packet_router_;
   internal::TransportAdapter feedback_transport_;
   const rtc::scoped_ptr<ReceiveStatistics> receive_stats_;
   const rtc::scoped_ptr<RTPPayloadRegistry> payload_registry_;
diff --git a/webrtc/video/screenshare_loopback.cc b/webrtc/video/screenshare_loopback.cc
index 34f6894..9897783 100644
--- a/webrtc/video/screenshare_loopback.cc
+++ b/webrtc/video/screenshare_loopback.cc
@@ -139,6 +139,8 @@
   return static_cast<int>(FLAGS_duration);
 }
 
+DEFINE_bool(send_side_bwe, true, "Use send-side bandwidth estimation");
+
 DEFINE_string(
     force_fieldtrials,
     "",
@@ -162,19 +164,12 @@
   call_bitrate_config.max_bitrate_bps = flags::MaxBitrateKbps() * 1000;
 
   VideoQualityTest::Params params{
-      {
-        flags::Width(),
-        flags::Height(),
-        flags::Fps(),
-        flags::MinBitrateKbps() * 1000,
-        flags::TargetBitrateKbps() * 1000,
-        flags::MaxBitrateKbps() * 1000,
-        flags::Codec(),
-        flags::NumTemporalLayers(),
-        flags::MinTransmitBitrateKbps() * 1000,
-        call_bitrate_config,
-        flags::TLDiscardThreshold()
-      },
+      {flags::Width(), flags::Height(), flags::Fps(),
+       flags::MinBitrateKbps() * 1000, flags::TargetBitrateKbps() * 1000,
+       flags::MaxBitrateKbps() * 1000, flags::Codec(),
+       flags::NumTemporalLayers(), flags::MinTransmitBitrateKbps() * 1000,
+       call_bitrate_config, flags::TLDiscardThreshold(),
+       flags::FLAGS_send_side_bwe},
       {},  // Video specific.
       {true, flags::SlideChangeInterval(), flags::ScrollDuration()},
       {"screenshare", 0.0, 0.0, flags::DurationSecs(), flags::OutputFilename()},
diff --git a/webrtc/video/video_loopback.cc b/webrtc/video/video_loopback.cc
index c5e9254..0dceea8 100644
--- a/webrtc/video/video_loopback.cc
+++ b/webrtc/video/video_loopback.cc
@@ -140,6 +140,8 @@
   return static_cast<int>(FLAGS_duration);
 }
 
+DEFINE_bool(send_side_bwe, true, "Use send-side bandwidth estimation");
+
 }  // namespace flags
 
 void Loopback() {
@@ -158,19 +160,13 @@
   std::string clip = flags::Clip();
   std::string graph_title = clip.empty() ? "" : "video " + clip;
   VideoQualityTest::Params params{
-      {
-        flags::Width(),
-        flags::Height(),
-        flags::Fps(),
-        flags::MinBitrateKbps() * 1000,
-        flags::TargetBitrateKbps() * 1000,
-        flags::MaxBitrateKbps() * 1000,
-        flags::Codec(),
-        flags::NumTemporalLayers(),
-        0,  // No min transmit bitrate.
-        call_bitrate_config,
-        flags::TLDiscardThreshold()
-      },
+      {flags::Width(), flags::Height(), flags::Fps(),
+       flags::MinBitrateKbps() * 1000, flags::TargetBitrateKbps() * 1000,
+       flags::MaxBitrateKbps() * 1000, flags::Codec(),
+       flags::NumTemporalLayers(),
+       0,  // No min transmit bitrate.
+       call_bitrate_config, flags::TLDiscardThreshold(),
+       flags::FLAGS_send_side_bwe},
       {clip},
       {},  // Screenshare specific.
       {graph_title, 0.0, 0.0, flags::DurationSecs(), flags::OutputFilename()},
diff --git a/webrtc/video/video_quality_test.cc b/webrtc/video/video_quality_test.cc
index 47c5021..110cb06 100644
--- a/webrtc/video/video_quality_test.cc
+++ b/webrtc/video/video_quality_test.cc
@@ -32,6 +32,8 @@
 
 namespace webrtc {
 
+static const int kTransportSeqExtensionId =
+    VideoQualityTest::kAbsSendTimeExtensionId + 1;
 static const int kSendStatsPollingIntervalMs = 1000;
 static const int kPayloadTypeVP8 = 123;
 static const int kPayloadTypeVP9 = 124;
@@ -598,6 +600,15 @@
   send_config_.rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
   send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
 
+  send_config_.rtp.extensions.clear();
+  if (params.common.send_side_bwe) {
+    send_config_.rtp.extensions.push_back(RtpExtension(
+        RtpExtension::kTransportSequenceNumber, kTransportSeqExtensionId));
+  } else {
+    send_config_.rtp.extensions.push_back(
+        RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
+  }
+
   // Automatically fill out streams[0] with params.
   VideoStream* stream = &encoder_config_.streams[0];
   stream->width = params.common.width;
diff --git a/webrtc/video/video_quality_test.h b/webrtc/video/video_quality_test.h
index d6020fa..52ac9e4 100644
--- a/webrtc/video/video_quality_test.h
+++ b/webrtc/video/video_quality_test.h
@@ -38,6 +38,7 @@
       int min_transmit_bps;
       Call::Config::BitrateConfig call_bitrate_config;
       size_t tl_discard_threshold;
+      bool send_side_bwe;
     } common;
     struct {  // Video-specific settings.
       std::string clip_name;
diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc
index 2c8d8f8..1be63e0 100644
--- a/webrtc/video/video_receive_stream.cc
+++ b/webrtc/video/video_receive_stream.cc
@@ -140,7 +140,7 @@
       channel_group_(channel_group),
       channel_id_(channel_id) {
   RTC_CHECK(channel_group_->CreateReceiveChannel(
-      channel_id_, &transport_adapter_, num_cpu_cores));
+      channel_id_, &transport_adapter_, num_cpu_cores, config));
 
   vie_channel_ = channel_group_->GetChannel(channel_id_);
 
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index 721cc9d..6703448 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -120,7 +120,7 @@
   RTC_DCHECK(!config_.rtp.ssrcs.empty());
   RTC_CHECK(channel_group->CreateSendChannel(
       channel_id_, &transport_adapter_, &stats_proxy_,
-      config.pre_encode_callback, num_cpu_cores, config_.rtp.ssrcs));
+      config.pre_encode_callback, num_cpu_cores, config_));
   vie_channel_ = channel_group_->GetChannel(channel_id_);
   vie_encoder_ = channel_group_->GetEncoder(channel_id_);
 
diff --git a/webrtc/video_engine/vie_channel_group.cc b/webrtc/video_engine/vie_channel_group.cc
index 42ffafb..6553ce2 100644
--- a/webrtc/video_engine/vie_channel_group.cc
+++ b/webrtc/video_engine/vie_channel_group.cc
@@ -18,6 +18,7 @@
 #include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h"
 #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h"
 #include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h"
+#include "webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h"
 #include "webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h"
 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
 #include "webrtc/modules/utility/interface/process_thread.h"
@@ -145,7 +146,6 @@
     : remb_(new VieRemb()),
       bitrate_allocator_(new BitrateAllocator()),
       call_stats_(new CallStats()),
-      encoder_state_feedback_(new EncoderStateFeedback()),
       packet_router_(new PacketRouter()),
       pacer_(new PacedSender(Clock::GetRealTimeClock(),
                              packet_router_.get(),
@@ -153,6 +153,12 @@
                              PacedSender::kDefaultPaceMultiplier *
                                  BitrateController::kDefaultStartBitrateKbps,
                              0)),
+      remote_bitrate_estimator_(
+          new WrappingBitrateEstimator(remb_.get(), Clock::GetRealTimeClock())),
+      remote_estimator_proxy_(
+          new RemoteEstimatorProxy(Clock::GetRealTimeClock(),
+                                   packet_router_.get())),
+      encoder_state_feedback_(new EncoderStateFeedback()),
       process_thread_(process_thread),
       pacer_thread_(ProcessThread::Create("PacerThread")),
       // Constructed last as this object calls the provided callback on
@@ -160,14 +166,12 @@
       bitrate_controller_(
           BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
                                                      this)) {
-  remote_bitrate_estimator_.reset(new WrappingBitrateEstimator(
-      remb_.get(), Clock::GetRealTimeClock()));
-
   call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get());
 
   pacer_thread_->RegisterModule(pacer_.get());
   pacer_thread_->Start();
 
+  process_thread->RegisterModule(remote_estimator_proxy_.get());
   process_thread->RegisterModule(remote_bitrate_estimator_.get());
   process_thread->RegisterModule(call_stats_.get());
   process_thread->RegisterModule(bitrate_controller_.get());
@@ -179,7 +183,10 @@
   process_thread_->DeRegisterModule(bitrate_controller_.get());
   process_thread_->DeRegisterModule(call_stats_.get());
   process_thread_->DeRegisterModule(remote_bitrate_estimator_.get());
+  process_thread_->DeRegisterModule(remote_estimator_proxy_.get());
   call_stats_->DeregisterStatsObserver(remote_bitrate_estimator_.get());
+  if (transport_feedback_adapter_.get())
+    call_stats_->DeregisterStatsObserver(transport_feedback_adapter_.get());
   RTC_DCHECK(channel_map_.empty());
   RTC_DCHECK(!remb_->InUse());
   RTC_DCHECK(vie_encoder_map_.empty());
@@ -190,7 +197,30 @@
                                      SendStatisticsProxy* stats_proxy,
                                      I420FrameCallback* pre_encode_callback,
                                      int number_of_cores,
-                                     const std::vector<uint32_t>& ssrcs) {
+                                     const VideoSendStream::Config& config) {
+  TransportFeedbackObserver* transport_feedback_observer = nullptr;
+  bool transport_seq_enabled = false;
+  for (const RtpExtension& extension : config.rtp.extensions) {
+    if (extension.name == RtpExtension::kTransportSequenceNumber) {
+      transport_seq_enabled = true;
+      break;
+    }
+  }
+  if (transport_seq_enabled) {
+    if (transport_feedback_adapter_.get() == nullptr) {
+      transport_feedback_adapter_.reset(new TransportFeedbackAdapter(
+          bitrate_controller_->CreateRtcpBandwidthObserver(),
+          Clock::GetRealTimeClock(), process_thread_));
+      transport_feedback_adapter_->SetBitrateEstimator(
+          new RemoteBitrateEstimatorAbsSendTime(
+              transport_feedback_adapter_.get(), Clock::GetRealTimeClock(),
+              RemoteBitrateEstimator::kDefaultMinBitrateBps));
+      call_stats_->RegisterStatsObserver(transport_feedback_adapter_.get());
+    }
+    transport_feedback_observer = transport_feedback_adapter_.get();
+  }
+
+  const std::vector<uint32_t>& ssrcs = config.rtp.ssrcs;
   RTC_DCHECK(!ssrcs.empty());
   rtc::scoped_ptr<ViEEncoder> vie_encoder(new ViEEncoder(
       channel_id, number_of_cores, process_thread_, stats_proxy,
@@ -200,7 +230,9 @@
   }
   ViEEncoder* encoder = vie_encoder.get();
   if (!CreateChannel(channel_id, transport, number_of_cores,
-                     vie_encoder.release(), ssrcs.size(), true)) {
+                     vie_encoder.release(), ssrcs.size(), true,
+                     remote_bitrate_estimator_.get(),
+                     transport_feedback_observer)) {
     return false;
   }
   ViEChannel* channel = channel_map_[channel_id];
@@ -214,11 +246,27 @@
   return true;
 }
 
-bool ChannelGroup::CreateReceiveChannel(int channel_id,
-                                        Transport* transport,
-                                        int number_of_cores) {
-  return CreateChannel(channel_id, transport, number_of_cores,
-                       nullptr, 1, false);
+bool ChannelGroup::CreateReceiveChannel(
+    int channel_id,
+    Transport* transport,
+    int number_of_cores,
+    const VideoReceiveStream::Config& config) {
+  bool send_side_bwe = false;
+  for (const RtpExtension& extension : config.rtp.extensions) {
+    if (extension.name == RtpExtension::kTransportSequenceNumber) {
+      send_side_bwe = true;
+      break;
+    }
+  }
+
+  RemoteBitrateEstimator* bitrate_estimator;
+  if (send_side_bwe) {
+    bitrate_estimator = remote_estimator_proxy_.get();
+  } else {
+    bitrate_estimator = remote_bitrate_estimator_.get();
+  }
+  return CreateChannel(channel_id, transport, number_of_cores, nullptr, 1,
+                       false, bitrate_estimator, nullptr);
 }
 
 bool ChannelGroup::CreateChannel(int channel_id,
@@ -226,13 +274,15 @@
                                  int number_of_cores,
                                  ViEEncoder* vie_encoder,
                                  size_t max_rtp_streams,
-                                 bool sender) {
+                                 bool sender,
+                                 RemoteBitrateEstimator* bitrate_estimator,
+                                 TransportFeedbackObserver* feedback_observer) {
   rtc::scoped_ptr<ViEChannel> channel(new ViEChannel(
       number_of_cores, transport, process_thread_,
       encoder_state_feedback_->GetRtcpIntraFrameObserver(),
-      bitrate_controller_->CreateRtcpBandwidthObserver(), nullptr,
-      remote_bitrate_estimator_.get(), call_stats_->rtcp_rtt_stats(),
-      pacer_.get(), packet_router_.get(), max_rtp_streams, sender));
+      bitrate_controller_->CreateRtcpBandwidthObserver(), feedback_observer,
+      bitrate_estimator, call_stats_->rtcp_rtt_stats(), pacer_.get(),
+      packet_router_.get(), max_rtp_streams, sender));
   if (channel->Init() != 0) {
     return false;
   }
diff --git a/webrtc/video_engine/vie_channel_group.h b/webrtc/video_engine/vie_channel_group.h
index 91f9490..e133d1a 100644
--- a/webrtc/video_engine/vie_channel_group.h
+++ b/webrtc/video_engine/vie_channel_group.h
@@ -19,6 +19,8 @@
 #include "webrtc/base/criticalsection.h"
 #include "webrtc/base/scoped_ptr.h"
 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
+#include "webrtc/video_receive_stream.h"
+#include "webrtc/video_send_stream.h"
 
 namespace webrtc {
 
@@ -52,10 +54,11 @@
                          SendStatisticsProxy* stats_proxy,
                          I420FrameCallback* pre_encode_callback,
                          int number_of_cores,
-                         const std::vector<uint32_t>& ssrcs);
+                         const VideoSendStream::Config& config);
   bool CreateReceiveChannel(int channel_id,
                             Transport* transport,
-                            int number_of_cores);
+                            int number_of_cores,
+                            const VideoReceiveStream::Config& config);
   void DeleteChannel(int channel_id);
   ViEChannel* GetChannel(int channel_id) const;
   ViEEncoder* GetEncoder(int channel_id) const;
@@ -83,16 +86,19 @@
                      int number_of_cores,
                      ViEEncoder* vie_encoder,
                      size_t max_rtp_streams,
-                     bool sender);
+                     bool sender,
+                     RemoteBitrateEstimator* bitrate_estimator,
+                     TransportFeedbackObserver* feedback_observer);
   ViEChannel* PopChannel(int channel_id);
 
   rtc::scoped_ptr<VieRemb> remb_;
   rtc::scoped_ptr<BitrateAllocator> bitrate_allocator_;
   rtc::scoped_ptr<CallStats> call_stats_;
-  rtc::scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_;
-  rtc::scoped_ptr<EncoderStateFeedback> encoder_state_feedback_;
   rtc::scoped_ptr<PacketRouter> packet_router_;
   rtc::scoped_ptr<PacedSender> pacer_;
+  rtc::scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_;
+  rtc::scoped_ptr<RemoteEstimatorProxy> remote_estimator_proxy_;
+  rtc::scoped_ptr<EncoderStateFeedback> encoder_state_feedback_;
   ChannelMap channel_map_;
   // Maps Channel id -> ViEEncoder.
   mutable rtc::CriticalSection encoder_map_crit_;
@@ -103,6 +109,7 @@
   rtc::scoped_ptr<ProcessThread> pacer_thread_;
 
   rtc::scoped_ptr<BitrateController> bitrate_controller_;
+  rtc::scoped_ptr<TransportFeedbackAdapter> transport_feedback_adapter_;
 };
 
 }  // namespace webrtc