Add REMB functionality to ViE.

This CL only adds support for encoding one stream, but receiving multiple streams.

BUG=
TEST=video_engine_core_unittest + auto_test/loopback

Review URL: http://webrtc-codereview.appspot.com/333011

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1284 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp.h b/src/modules/rtp_rtcp/interface/rtp_rtcp.h
index 984bcd7..0cdb0de 100644
--- a/src/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/src/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -767,6 +767,11 @@
                                       const WebRtc_UWord8 numberOfSSRC,
                                       const WebRtc_UWord32* SSRC) = 0;
 
+    // Registers an observer to call when the estimate of the incoming channel
+    // changes.
+    virtual bool SetRemoteBitrateObserver(
+        RtpRemoteBitrateObserver* observer) = 0;
+
     /*
     *   (IJ) Extended jitter report.
     */
diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
index f376d56..8ca0d80 100644
--- a/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
+++ b/src/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
@@ -245,6 +245,16 @@
     virtual ~RtpRtcpClock() {}
 };
 
+// RtpReceiveBitrateUpdate is used to signal changes in bitrate estimates for
+// the incoming stream.
+class RtpRemoteBitrateObserver
+{
+public:
+    virtual void OnReceiveBitrateChanged(unsigned int ssrc,
+                                         unsigned int bitrate) = 0;
+    virtual ~RtpRemoteBitrateObserver() {}
+};
+
 } // namespace webrtc
 
 #endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_DEFINES_H_
diff --git a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
new file mode 100644
index 0000000..14150ef
--- /dev/null
+++ b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -0,0 +1,257 @@
+#include "../testing/gmock/include/gmock/gmock.h"
+
+#include "modules/interface/module.h"
+#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
+#include "modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
+
+namespace webrtc {
+
+class MockRtpRtcp : public RtpRtcp {
+ public:
+  MOCK_METHOD1(ChangeUniqueId,
+      WebRtc_Word32(const WebRtc_Word32 id));
+  MOCK_METHOD1(RegisterDefaultModule,
+      WebRtc_Word32(RtpRtcp* module));
+  MOCK_METHOD0(DeRegisterDefaultModule,
+      WebRtc_Word32());
+  MOCK_METHOD0(DefaultModuleRegistered,
+      bool());
+  MOCK_METHOD0(NumberChildModules,
+      WebRtc_UWord32());
+  MOCK_METHOD1(RegisterSyncModule,
+      WebRtc_Word32(RtpRtcp* module));
+  MOCK_METHOD0(DeRegisterSyncModule,
+      WebRtc_Word32());
+  MOCK_METHOD0(InitReceiver,
+      WebRtc_Word32());
+  MOCK_METHOD1(RegisterIncomingDataCallback,
+      WebRtc_Word32(RtpData* incomingDataCallback));
+  MOCK_METHOD1(RegisterIncomingRTPCallback,
+      WebRtc_Word32(RtpFeedback* incomingMessagesCallback));
+  MOCK_METHOD2(SetPacketTimeout,
+      WebRtc_Word32(const WebRtc_UWord32 RTPtimeoutMS, const WebRtc_UWord32 RTCPtimeoutMS));
+  MOCK_METHOD2(SetPeriodicDeadOrAliveStatus,
+      WebRtc_Word32(const bool enable, const WebRtc_UWord8 sampleTimeSeconds));
+  MOCK_METHOD2(PeriodicDeadOrAliveStatus,
+      WebRtc_Word32(bool &enable, WebRtc_UWord8 &sampleTimeSeconds));
+  MOCK_METHOD1(RegisterReceivePayload,
+      WebRtc_Word32(const CodecInst& voiceCodec));
+  MOCK_METHOD1(RegisterReceivePayload,
+      WebRtc_Word32(const VideoCodec& videoCodec));
+  MOCK_METHOD2(ReceivePayloadType,
+      WebRtc_Word32(const CodecInst& voiceCodec, WebRtc_Word8* plType));
+  MOCK_METHOD2(ReceivePayloadType,
+      WebRtc_Word32(const VideoCodec& videoCodec, WebRtc_Word8* plType));
+  MOCK_METHOD1(DeRegisterReceivePayload,
+      WebRtc_Word32(const WebRtc_Word8 payloadType));
+  MOCK_METHOD2(RegisterReceiveRtpHeaderExtension,
+      WebRtc_Word32(const RTPExtensionType type, const WebRtc_UWord8 id));
+  MOCK_METHOD1(DeregisterReceiveRtpHeaderExtension,
+               WebRtc_Word32(const RTPExtensionType type));
+  MOCK_CONST_METHOD0(RemoteTimestamp,
+      WebRtc_UWord32());
+  MOCK_CONST_METHOD1(EstimatedRemoteTimeStamp,
+      WebRtc_Word32(WebRtc_UWord32& timestamp));
+  MOCK_CONST_METHOD0(RemoteSSRC,
+      WebRtc_UWord32());
+  MOCK_CONST_METHOD1(RemoteCSRCs,
+      WebRtc_Word32(WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]));
+  MOCK_CONST_METHOD1(SSRCFilter,
+      WebRtc_Word32(WebRtc_UWord32& allowedSSRC));
+  MOCK_METHOD2(SetSSRCFilter,
+      WebRtc_Word32(const bool enable, const WebRtc_UWord32 allowedSSRC));
+  MOCK_METHOD2(IncomingPacket,
+      WebRtc_Word32(const WebRtc_UWord8* incomingPacket, const WebRtc_UWord16 packetLength));
+  MOCK_METHOD4(IncomingAudioNTP,
+      WebRtc_Word32(const WebRtc_UWord32 audioReceivedNTPsecs, const WebRtc_UWord32 audioReceivedNTPfrac, const WebRtc_UWord32 audioRTCPArrivalTimeSecs, const WebRtc_UWord32 audioRTCPArrivalTimeFrac));
+  MOCK_METHOD0(InitSender,
+      WebRtc_Word32());
+  MOCK_METHOD1(RegisterSendTransport,
+      WebRtc_Word32(Transport* outgoingTransport));
+  MOCK_METHOD1(SetMaxTransferUnit,
+      WebRtc_Word32(const WebRtc_UWord16 size));
+  MOCK_METHOD3(SetTransportOverhead,
+      WebRtc_Word32(const bool TCP, const bool IPV6, const WebRtc_UWord8 authenticationOverhead));
+  MOCK_CONST_METHOD0(MaxPayloadLength,
+      WebRtc_UWord16());
+  MOCK_CONST_METHOD0(MaxDataPayloadLength,
+      WebRtc_UWord16());
+  MOCK_METHOD3(SetRTPKeepaliveStatus,
+      WebRtc_Word32(const bool enable, const WebRtc_Word8 unknownPayloadType, const WebRtc_UWord16 deltaTransmitTimeMS));
+  MOCK_CONST_METHOD3(RTPKeepaliveStatus,
+      WebRtc_Word32(bool* enable, WebRtc_Word8* unknownPayloadType, WebRtc_UWord16* deltaTransmitTimeMS));
+  MOCK_CONST_METHOD0(RTPKeepalive,
+      bool());
+  MOCK_METHOD1(RegisterSendPayload,
+      WebRtc_Word32(const CodecInst& voiceCodec));
+  MOCK_METHOD1(RegisterSendPayload,
+      WebRtc_Word32(const VideoCodec& videoCodec));
+  MOCK_METHOD1(DeRegisterSendPayload,
+      WebRtc_Word32(const WebRtc_Word8 payloadType));
+  MOCK_METHOD2(RegisterSendRtpHeaderExtension,
+      WebRtc_Word32(const RTPExtensionType type, const WebRtc_UWord8 id));
+  MOCK_METHOD1(DeregisterSendRtpHeaderExtension,
+      WebRtc_Word32(const RTPExtensionType type));
+  MOCK_CONST_METHOD0(StartTimestamp,
+      WebRtc_UWord32());
+  MOCK_METHOD1(SetStartTimestamp,
+      WebRtc_Word32(const WebRtc_UWord32 timestamp));
+  MOCK_CONST_METHOD0(SequenceNumber,
+      WebRtc_UWord16());
+  MOCK_METHOD1(SetSequenceNumber,
+      WebRtc_Word32(const WebRtc_UWord16 seq));
+  MOCK_CONST_METHOD0(SSRC,
+      WebRtc_UWord32());
+  MOCK_METHOD1(SetSSRC,
+      WebRtc_Word32(const WebRtc_UWord32 ssrc));
+  MOCK_CONST_METHOD1(CSRCs,
+      WebRtc_Word32(WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]));
+  MOCK_METHOD2(SetCSRCs,
+      WebRtc_Word32(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize], const WebRtc_UWord8 arrLength));
+  MOCK_METHOD1(SetCSRCStatus,
+      WebRtc_Word32(const bool include));
+  MOCK_METHOD1(SetSendingStatus,
+      WebRtc_Word32(const bool sending));
+  MOCK_CONST_METHOD0(Sending,
+      bool());
+  MOCK_METHOD1(SetSendingMediaStatus,
+      WebRtc_Word32(const bool sending));
+  MOCK_CONST_METHOD0(SendingMedia,
+      bool());
+  MOCK_CONST_METHOD4(BitrateSent,
+      void(WebRtc_UWord32* totalRate, WebRtc_UWord32* videoRate, WebRtc_UWord32* fecRate, WebRtc_UWord32* nackRate));
+  MOCK_METHOD7(SendOutgoingData,
+      WebRtc_Word32(const FrameType frameType, const WebRtc_Word8 payloadType, const WebRtc_UWord32 timeStamp, const WebRtc_UWord8* payloadData, const WebRtc_UWord32 payloadSize, const RTPFragmentationHeader* fragmentation, const RTPVideoHeader* rtpVideoHdr));
+  MOCK_METHOD1(RegisterIncomingRTCPCallback,
+      WebRtc_Word32(RtcpFeedback* incomingMessagesCallback));
+  MOCK_CONST_METHOD0(RTCP,
+      RTCPMethod());
+  MOCK_METHOD1(SetRTCPStatus,
+      WebRtc_Word32(const RTCPMethod method));
+  MOCK_METHOD1(SetCNAME,
+      WebRtc_Word32(const WebRtc_Word8 cName[RTCP_CNAME_SIZE]));
+  MOCK_METHOD1(CNAME,
+      WebRtc_Word32(WebRtc_Word8 cName[RTCP_CNAME_SIZE]));
+  MOCK_CONST_METHOD2(RemoteCNAME,
+      WebRtc_Word32(const WebRtc_UWord32 remoteSSRC, WebRtc_Word8 cName[RTCP_CNAME_SIZE]));
+  MOCK_CONST_METHOD4(RemoteNTP,
+      WebRtc_Word32(WebRtc_UWord32 *ReceivedNTPsecs, WebRtc_UWord32 *ReceivedNTPfrac, WebRtc_UWord32 *RTCPArrivalTimeSecs, WebRtc_UWord32 *RTCPArrivalTimeFrac));
+  MOCK_METHOD2(AddMixedCNAME,
+      WebRtc_Word32(const WebRtc_UWord32 SSRC, const WebRtc_Word8 cName[RTCP_CNAME_SIZE]));
+  MOCK_METHOD1(RemoveMixedCNAME,
+      WebRtc_Word32(const WebRtc_UWord32 SSRC));
+  MOCK_CONST_METHOD5(RTT,
+      WebRtc_Word32(const WebRtc_UWord32 remoteSSRC, WebRtc_UWord16* RTT, WebRtc_UWord16* avgRTT, WebRtc_UWord16* minRTT, WebRtc_UWord16* maxRTT));
+  MOCK_METHOD1(ResetRTT,
+      WebRtc_Word32(const WebRtc_UWord32 remoteSSRC));
+  MOCK_METHOD1(SendRTCP,
+      WebRtc_Word32(WebRtc_UWord32 rtcpPacketType));
+  MOCK_METHOD1(SendRTCPReferencePictureSelection,
+      WebRtc_Word32(const WebRtc_UWord64 pictureID));
+  MOCK_METHOD1(SendRTCPSliceLossIndication,
+      WebRtc_Word32(const WebRtc_UWord8 pictureID));
+  MOCK_METHOD0(ResetStatisticsRTP,
+      WebRtc_Word32());
+  MOCK_CONST_METHOD5(StatisticsRTP,
+      WebRtc_Word32(WebRtc_UWord8 *fraction_lost, WebRtc_UWord32 *cum_lost, WebRtc_UWord32 *ext_max, WebRtc_UWord32 *jitter, WebRtc_UWord32 *max_jitter));
+  MOCK_METHOD0(ResetReceiveDataCountersRTP,
+      WebRtc_Word32());
+  MOCK_METHOD0(ResetSendDataCountersRTP,
+      WebRtc_Word32());
+  MOCK_CONST_METHOD4(DataCountersRTP,
+      WebRtc_Word32(WebRtc_UWord32 *bytesSent, WebRtc_UWord32 *packetsSent, WebRtc_UWord32 *bytesReceived, WebRtc_UWord32 *packetsReceived));
+  MOCK_METHOD1(RemoteRTCPStat,
+      WebRtc_Word32(RTCPSenderInfo* senderInfo));
+  MOCK_METHOD2(RemoteRTCPStat,
+      WebRtc_Word32(const WebRtc_UWord32 remoteSSRC, RTCPReportBlock* receiveBlock));
+  MOCK_METHOD2(AddRTCPReportBlock,
+      WebRtc_Word32(const WebRtc_UWord32 SSRC, const RTCPReportBlock* receiveBlock));
+  MOCK_METHOD1(RemoveRTCPReportBlock,
+      WebRtc_Word32(const WebRtc_UWord32 SSRC));
+  MOCK_METHOD4(SetRTCPApplicationSpecificData,
+      WebRtc_Word32(const WebRtc_UWord8 subType, const WebRtc_UWord32 name, const WebRtc_UWord8* data, const WebRtc_UWord16 length));
+  MOCK_METHOD1(SetRTCPVoIPMetrics,
+      WebRtc_Word32(const RTCPVoIPMetric* VoIPMetric));
+  MOCK_CONST_METHOD0(REMB,
+      bool());
+  MOCK_METHOD1(SetREMBStatus,
+      WebRtc_Word32(const bool enable));
+  MOCK_METHOD3(SetREMBData,
+      WebRtc_Word32(const WebRtc_UWord32 bitrate, const WebRtc_UWord8 numberOfSSRC, const WebRtc_UWord32* SSRC));
+  MOCK_METHOD1(SetRemoteBitrateObserver,
+      bool(RtpRemoteBitrateObserver*));
+  MOCK_CONST_METHOD0(IJ,
+      bool());
+  MOCK_METHOD1(SetIJStatus,
+      WebRtc_Word32(const bool));
+  MOCK_CONST_METHOD0(TMMBR,
+      bool());
+  MOCK_METHOD1(SetTMMBRStatus,
+      WebRtc_Word32(const bool enable));
+  MOCK_METHOD1(OnBandwidthEstimateUpdate,
+      void(WebRtc_UWord16 bandWidthKbit));
+  MOCK_CONST_METHOD0(NACK,
+      NACKMethod());
+  MOCK_METHOD1(SetNACKStatus,
+      WebRtc_Word32(const NACKMethod method));
+  MOCK_METHOD2(SendNACK,
+      WebRtc_Word32(const WebRtc_UWord16* nackList, const WebRtc_UWord16 size));
+  MOCK_METHOD2(SetStorePacketsStatus,
+      WebRtc_Word32(const bool enable, const WebRtc_UWord16 numberToStore));
+  MOCK_METHOD1(RegisterAudioCallback,
+      WebRtc_Word32(RtpAudioFeedback* messagesCallback));
+  MOCK_METHOD1(SetAudioPacketSize,
+      WebRtc_Word32(const WebRtc_UWord16 packetSizeSamples));
+  MOCK_METHOD3(SetTelephoneEventStatus,
+      WebRtc_Word32(const bool enable, const bool forwardToDecoder, const bool detectEndOfTone));
+  MOCK_CONST_METHOD0(TelephoneEvent,
+      bool());
+  MOCK_CONST_METHOD0(TelephoneEventForwardToDecoder,
+      bool());
+  MOCK_CONST_METHOD1(SendTelephoneEventActive,
+      bool(WebRtc_Word8& telephoneEvent));
+  MOCK_METHOD3(SendTelephoneEventOutband,
+      WebRtc_Word32(const WebRtc_UWord8 key, const WebRtc_UWord16 time_ms, const WebRtc_UWord8 level));
+  MOCK_METHOD1(SetSendREDPayloadType,
+      WebRtc_Word32(const WebRtc_Word8 payloadType));
+  MOCK_CONST_METHOD1(SendREDPayloadType,
+      WebRtc_Word32(WebRtc_Word8& payloadType));
+  MOCK_METHOD2(SetRTPAudioLevelIndicationStatus,
+      WebRtc_Word32(const bool enable, const WebRtc_UWord8 ID));
+  MOCK_CONST_METHOD2(GetRTPAudioLevelIndicationStatus,
+      WebRtc_Word32(bool& enable, WebRtc_UWord8& ID));
+  MOCK_METHOD1(SetAudioLevel,
+      WebRtc_Word32(const WebRtc_UWord8 level_dBov));
+  MOCK_METHOD1(RegisterIncomingVideoCallback,
+      WebRtc_Word32(RtpVideoFeedback* incomingMessagesCallback));
+  MOCK_METHOD1(SetCameraDelay,
+      WebRtc_Word32(const WebRtc_Word32 delayMS));
+  MOCK_METHOD3(SetSendBitrate,
+      WebRtc_Word32(const WebRtc_UWord32 startBitrate, const WebRtc_UWord16 minBitrateKbit, const WebRtc_UWord16 maxBitrateKbit));
+  MOCK_METHOD3(SetGenericFECStatus,
+      WebRtc_Word32(const bool enable, const WebRtc_UWord8 payloadTypeRED, const WebRtc_UWord8 payloadTypeFEC));
+  MOCK_METHOD3(GenericFECStatus,
+      WebRtc_Word32(bool& enable, WebRtc_UWord8& payloadTypeRED, WebRtc_UWord8& payloadTypeFEC));
+  MOCK_METHOD2(SetFECCodeRate,
+      WebRtc_Word32(const WebRtc_UWord8 keyFrameCodeRate, const WebRtc_UWord8 deltaFrameCodeRate));
+  MOCK_METHOD2(SetFECUepProtection,
+      WebRtc_Word32(const bool keyUseUepProtection, const bool deltaUseUepProtection));
+  MOCK_METHOD1(SetKeyFrameRequestMethod,
+      WebRtc_Word32(const KeyFrameRequestMethod method));
+  MOCK_METHOD1(RequestKeyFrame,
+      WebRtc_Word32(const FrameType frameType));
+  MOCK_METHOD1(SetH263InverseLogic,
+      WebRtc_Word32(const bool enable));
+
+  MOCK_CONST_METHOD3(Version,
+      int32_t(char* version, uint32_t& remaining_buffer_in_bytes, uint32_t& position));
+  MOCK_METHOD0(TimeUntilNextProcess,
+        int32_t());
+  MOCK_METHOD0(Process,
+        int32_t());
+
+  // Members.
+  unsigned int remote_ssrc_;
+};
+
+}  // namespace webrtc
diff --git a/src/modules/rtp_rtcp/source/rtcp_receiver.cc b/src/modules/rtp_rtcp/source/rtcp_receiver.cc
index 9ddcee4..7c20927 100644
--- a/src/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/src/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -1311,11 +1311,14 @@
         if(rtcpPacketInformation.reportBlock)
         {
             // We only want to trigger one OnNetworkChanged callback per RTCP
-            // packet. The callback is triggered by a SR, RR and TMMBR, so we
-            // don't want to trigger one from here if the packet also contains a
-            // TMMBR block.
-            bool triggerCallback =
-                !(rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTmmbr);
+            // packet. The callback is triggered by a SR, RR, REMB or TMMBR, so
+            // we don't want to trigger one from here if the packet also
+            // contains a REMB or TMMBR block.
+            bool triggerCallback = true;
+            if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb ||
+                rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpTmmbr) {
+              triggerCallback = false;
+            }
             _rtpRtcp.OnPacketLossStatisticsUpdate(
                 rtcpPacketInformation.fractionLost,
                 rtcpPacketInformation.roundTripTime,
@@ -1367,7 +1370,7 @@
     }
     if (rtcpPacketInformation.rtcpPacketTypeFlags & kRtcpRemb)
     {
-       // We need to bounce this to the default channel
+       // We need to bounce this to the default channel.
         _rtpRtcp.OnReceivedEstimatedMaxBitrate(
             rtcpPacketInformation.receiverEstimatedMaxBitrate);
     }
diff --git a/src/modules/rtp_rtcp/source/rtcp_sender.cc b/src/modules/rtp_rtcp/source/rtcp_sender.cc
index 4200aae..5928d2a 100644
--- a/src/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/src/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -266,9 +266,26 @@
     {  
         _rembSSRC[i] = SSRC[i];
     }
+    _sendREMB = true;
     return 0;
 }
 
+bool RTCPSender::SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer) {
+  CriticalSectionScoped lock(_criticalSectionRTCPSender);
+  if (observer && _bitrate_observer) {
+    return false;
+  }
+  _bitrate_observer = observer;
+  return true;
+}
+
+void RTCPSender::UpdateRemoteBitrateEstimate(unsigned int target_bitrate) {
+  CriticalSectionScoped lock(_criticalSectionRTCPSender);
+  if (_bitrate_observer && _remoteSSRC != 0) {
+    _bitrate_observer->OnReceiveBitrateChanged(_remoteSSRC, target_bitrate);
+  }
+}
+
 bool
 RTCPSender::TMMBR() const
 {
@@ -1719,8 +1736,9 @@
         }
         if(_REMB && _sendREMB)
         {
+            // Always attach REMB to SR if that is configured. Note that REMB is
+            // only sent on one of the RTP modules in the REMB group.
             rtcpPacketTypeFlags |= kRtcpRemb;
-            _sendREMB = false;
         }        
         if(_xrSendVoIPMetric)
         {
diff --git a/src/modules/rtp_rtcp/source/rtcp_sender.h b/src/modules/rtp_rtcp/source/rtcp_sender.h
index ef9efa3..c51e913 100644
--- a/src/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/src/modules/rtp_rtcp/source/rtcp_sender.h
@@ -84,6 +84,11 @@
     WebRtc_Word32 SetREMBData(const WebRtc_UWord32 bitrate,
                               const WebRtc_UWord8 numberOfSSRC,
                               const WebRtc_UWord32* SSRC);
+
+    bool SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer);
+
+    void UpdateRemoteBitrateEstimate(unsigned int target_bitrate);
+
     /*
     *   TMMBR
     */
@@ -231,6 +236,7 @@
     WebRtc_UWord8       _sizeRembSSRC;
     WebRtc_UWord32*     _rembSSRC;
     WebRtc_UWord32      _rembBitrate;
+    RtpRemoteBitrateObserver* _bitrate_observer;
 
     TMMBRHelp           _tmmbrHelp;
     WebRtc_UWord32      _tmmbr_Send;
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp.gypi b/src/modules/rtp_rtcp/source/rtp_rtcp.gypi
index e030845..8fe8599 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp.gypi
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp.gypi
@@ -84,6 +84,8 @@
         'video_codec_information.h',
         'rtp_format_vp8.cc',
         'rtp_format_vp8.h',
+        # Mocks
+        '../mocks/mock_rtp_rtcp.h',
       ], # source
     },
   ],
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 901677b..3b141c7 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -453,8 +453,12 @@
     {
         WebRtc_UWord16 RTT = 0;
         _rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL, NULL, NULL);
-        if (TMMBR())
+        if (REMB())
         {
+          unsigned int target_bitrate =
+              _rtcpSender.CalculateNewTargetBitrate(RTT);
+          _rtcpSender.UpdateRemoteBitrateEstimate(target_bitrate);
+        } else if (TMMBR()) {
             _rtcpSender.CalculateNewTargetBitrate(RTT);
         }
         _rtcpSender.SendRTCP(kRtcpReport, 0, 0, RTT);
@@ -1768,9 +1772,9 @@
     return _rtcpSender.RemoveReportBlock(SSRC);
 }
 
-    /*
-    *  (REMB) Receiver Estimated Max Bitrate
-    */
+/*
+ *  (REMB) Receiver Estimated Max Bitrate
+ */
 bool ModuleRtpRtcpImpl::REMB() const
 {
     WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "REMB()");
@@ -1804,9 +1808,14 @@
     return _rtcpSender.SetREMBData(bitrate, numberOfSSRC, SSRC);
 }
 
-    /*
-    *   (IJ) Extended jitter report.
-    */
+bool ModuleRtpRtcpImpl::SetRemoteBitrateObserver(
+    RtpRemoteBitrateObserver* observer) {
+  return _rtcpSender.SetRemoteBitrateObserver(observer);
+}
+
+/*
+ *   (IJ) Extended jitter report.
+ */
 bool ModuleRtpRtcpImpl::IJ() const
 {
     WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, _id, "IJ()");
@@ -2573,13 +2582,18 @@
     RateControlRegion region = _rtcpSender.UpdateOverUseState(rateControlInput,
                                                               firstOverUse);
     if (firstOverUse) {
-        // Send TMMBR immediately
+        // Send TMMBR or REMB immediately.
         WebRtc_UWord16 RTT = 0;
         _rtcpReceiver.RTT(_rtpReceiver.SSRC(), &RTT, NULL, NULL, NULL);
          // About to send TMMBR, first run remote rate control
          // to get a target bit rate.
-        _rtcpSender.CalculateNewTargetBitrate(RTT);
-        _rtcpSender.SendRTCP(kRtcpTmmbr);
+        unsigned int target_bitrate =
+            _rtcpSender.CalculateNewTargetBitrate(RTT);
+        if (REMB()) {
+          _rtcpSender.UpdateRemoteBitrateEstimate(target_bitrate);
+        } else if (TMMBR()) {
+          _rtcpSender.SendRTCP(kRtcpTmmbr);
+        }
     }
     return region;
 }
@@ -2637,7 +2651,9 @@
                                                      &newBitrate,
                                                      &fractionLost,
                                                      &roundTripTime) == 0) {
-        // might trigger a OnNetworkChanged in video callback
+      // TODO(mflodman) When encoding two streams, we need to split the bitrate
+      // between REMB sending channels.
+      // might trigger a OnNetworkChanged in video callback
         _rtpReceiver.UpdateBandwidthManagement(newBitrate,
                                                fractionLost,
                                                roundTripTime);
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 358af9c..b2e1639 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -336,6 +336,7 @@
                                       const WebRtc_UWord8 numberOfSSRC,
                                       const WebRtc_UWord32* SSRC);
 
+    virtual bool SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer);
     /*
     *   (IJ) Extended jitter report.
     */
diff --git a/src/video_engine/include/vie_rtp_rtcp.h b/src/video_engine/include/vie_rtp_rtcp.h
index f636898..1a42537 100644
--- a/src/video_engine/include/vie_rtp_rtcp.h
+++ b/src/video_engine/include/vie_rtp_rtcp.h
@@ -220,6 +220,12 @@
     // RTCP, implemented based on RFC4585.
     virtual int SetTMMBRStatus(const int videoChannel, const bool enable) = 0;
 
+    // Enables and disables REMB packets for this channel. |sender| indicates
+    // this channel is encoding, |receiver| tells the bitrate estimate for
+    // this channel should be included in the REMB packet.
+    virtual bool SetRembStatus(int video_channel, bool sender,
+                               bool receiver) = 0;
+
     // The function gets statistics from the received RTCP report.
     virtual int GetReceivedRTCPStatistics(
         const int videoChannel, unsigned short& fractionLost,
diff --git a/src/video_engine/test/auto_test/source/vie_autotest_loopback.cc b/src/video_engine/test/auto_test/source/vie_autotest_loopback.cc
index a672200..8d76fca 100644
--- a/src/video_engine/test/auto_test/source/vie_autotest_loopback.cc
+++ b/src/video_engine/test/auto_test/source/vie_autotest_loopback.cc
@@ -204,7 +204,8 @@
         printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n");
         return -1;
     }
-    error = ptrViERtpRtcp->SetTMMBRStatus(videoChannel, true);
+
+    error = ptrViERtpRtcp->SetRembStatus(videoChannel, true, true);
     if (error == -1)
     {
         printf("ERROR in ViERTP_RTCP::SetTMMBRStatus\n");
diff --git a/src/video_engine/video_engine_core.gypi b/src/video_engine/video_engine_core.gypi
index e17e799..8749bee 100644
--- a/src/video_engine/video_engine_core.gypi
+++ b/src/video_engine/video_engine_core.gypi
@@ -71,6 +71,7 @@
         'vie_impl.h',
         'vie_network_impl.h',
         'vie_ref_count.h',
+        'vie_remb.h',
         'vie_render_impl.h',
         'vie_rtp_rtcp_impl.h',
         'vie_shared_data.h',
@@ -117,13 +118,38 @@
         'vie_manager_base.cc',
         'vie_performance_monitor.cc',
         'vie_receiver.cc',
+        'vie_remb.cc',
         'vie_renderer.cc',
         'vie_render_manager.cc',
         'vie_sender.cc',
         'vie_sync_module.cc',
       ], # source
     },
-  ],
+  ], # targets
+  'conditions': [
+    ['build_with_chromium==0', {
+      'targets': [
+        {
+          'target_name': 'video_engine_core_unittests',
+          'type': 'executable',
+          'dependencies': [
+            'video_engine_core',
+            '<(webrtc_root)/../testing/gtest.gyp:gtest',
+            '<(webrtc_root)/../testing/gmock.gyp:gmock',
+            '<(webrtc_root)/../test/test.gyp:test_support_main',
+          ],
+          'include_dirs': [
+            '..',
+            '../modules/interface',
+            '../modules/rtp_rtcp/interface',
+          ],
+          'sources': [
+            'vie_remb_unittest.cc',
+          ],
+        },
+      ], # targets
+    }], # build_with_chromium
+  ], # conditions
 }
 
 # Local Variables:
diff --git a/src/video_engine/vie_channel.cc b/src/video_engine/vie_channel.cc
index 54637c9..e9d989d 100644
--- a/src/video_engine/vie_channel.cc
+++ b/src/video_engine/vie_channel.cc
@@ -704,6 +704,14 @@
   return rtp_rtcp_.SetKeyFrameRequestMethod(method);
 }
 
+bool ViEChannel::EnableRemb(bool enable) {
+  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
+               "ViEChannel::EnableRemb: %d", enable);
+  if (rtp_rtcp_.SetREMBStatus(enable) != 0)
+    return false;
+  return true;
+}
+
 WebRtc_Word32 ViEChannel::EnableTMMBR(const bool enable) {
   WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
                "%s: %d", __FUNCTION__, enable);
@@ -2076,6 +2084,11 @@
   return rtp_rtcp_.DeRegisterDefaultModule();
 }
 
+RtpRtcp* ViEChannel::rtp_rtcp() {
+  return &rtp_rtcp_;
+}
+
+
 WebRtc_Word32 ViEChannel::FrameToRender(VideoFrame& video_frame) {
   CriticalSectionScoped cs(callbackCritsect_);
 
diff --git a/src/video_engine/vie_channel.h b/src/video_engine/vie_channel.h
index ac16820..435d615 100644
--- a/src/video_engine/vie_channel.h
+++ b/src/video_engine/vie_channel.h
@@ -101,6 +101,7 @@
                                        const unsigned char payload_typeRED,
                                        const unsigned char payload_typeFEC);
   WebRtc_Word32 SetKeyFrameRequestMethod(const KeyFrameRequestMethod method);
+  bool EnableRemb(bool enable);
   WebRtc_Word32 EnableTMMBR(const bool enable);
   WebRtc_Word32 EnableKeyFrameRequestCallback(const bool enable);
 
@@ -289,6 +290,9 @@
   // the channel.
   WebRtc_Word32 DeregisterSendRtpRtcpModule();
 
+  // Gets the modules used by the channel.
+  RtpRtcp* rtp_rtcp();
+
   // Implements VCMReceiveCallback.
   virtual WebRtc_Word32 FrameToRender(VideoFrame& video_frame);
 
diff --git a/src/video_engine/vie_channel_manager.cc b/src/video_engine/vie_channel_manager.cc
index 403bf20..6bfdde2 100644
--- a/src/video_engine/vie_channel_manager.cc
+++ b/src/video_engine/vie_channel_manager.cc
@@ -11,12 +11,14 @@
 #include "video_engine/vie_channel_manager.h"
 
 #include "engine_configurations.h"
+#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
 #include "modules/utility/interface/process_thread.h"
 #include "system_wrappers/interface/critical_section_wrapper.h"
 #include "system_wrappers/interface/trace.h"
 #include "video_engine/vie_channel.h"
 #include "video_engine/vie_defines.h"
 #include "video_engine/vie_encoder.h"
+#include "video_engine/vie_remb.h"
 #include "voice_engine/main/interface/voe_video_sync.h"
 
 namespace webrtc {
@@ -32,6 +34,7 @@
       free_channel_ids_(new bool[kViEMaxNumberOfChannels]),
       free_channel_ids_size_(kViEMaxNumberOfChannels),
       voice_sync_interface_(NULL),
+      remb_(new VieRemb(engine_id)),
       voice_engine_(NULL),
       module_process_thread_(NULL) {
   WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id),
@@ -46,6 +49,7 @@
   WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id_),
                "ViEChannelManager Destructor, engine_id: %d", engine_id_);
 
+  module_process_thread_->DeRegisterModule(remb_.get());
   while (channel_map_.Size() != 0) {
     MapItem* item = channel_map_.First();
     const int channel_id = item->GetId();
@@ -71,6 +75,7 @@
     ProcessThread& module_process_thread) {
   assert(!module_process_thread_);
   module_process_thread_ = &module_process_thread;
+  module_process_thread_->RegisterModule(remb_.get());
 }
 
 int ViEChannelManager::CreateChannel(int& channel_id) {
@@ -348,6 +353,38 @@
   return voice_engine_;
 }
 
+bool ViEChannelManager::SetRembStatus(int channel_id, bool sender,
+                                      bool receiver) {
+  CriticalSectionScoped cs(*channel_id_critsect_);
+  ViEChannel* channel = ViEChannelPtr(channel_id);
+  if (!channel) {
+    return false;
+  }
+
+  if (sender || receiver) {
+    if (!channel->EnableRemb(true)) {
+      return false;
+    }
+  } else {
+    channel->EnableRemb(false);
+  }
+  RtpRtcp* rtp_module = channel->rtp_rtcp();
+  // TODO(mflodman) Add when implemented.
+  if (sender) {
+    // remb_->AddSendChannel(rtp_module);
+  } else {
+    // remb_->RemoveSendChannel(rtp_module);
+  }
+  if (receiver) {
+    remb_->AddReceiveChannel(rtp_module);
+    rtp_module->SetRemoteBitrateObserver(remb_.get());
+  } else {
+    remb_->RemoveReceiveChannel(rtp_module);
+    rtp_module->SetRemoteBitrateObserver(NULL);
+  }
+  return true;
+}
+
 ViEChannel* ViEChannelManager::ViEChannelPtr(int channel_id) const {
   CriticalSectionScoped cs(*channel_id_critsect_);
   MapItem* map_item = channel_map_.Find(channel_id);
diff --git a/src/video_engine/vie_channel_manager.h b/src/video_engine/vie_channel_manager.h
index f3bdb93..d4a9ef1 100644
--- a/src/video_engine/vie_channel_manager.h
+++ b/src/video_engine/vie_channel_manager.h
@@ -13,6 +13,7 @@
 
 #include "engine_configurations.h"
 #include "system_wrappers/interface/map_wrapper.h"
+#include "system_wrappers/interface/scoped_ptr.h"
 #include "typedefs.h"
 #include "video_engine/vie_defines.h"
 #include "video_engine/vie_manager_base.h"
@@ -24,6 +25,7 @@
 class ViEChannel;
 class ViEEncoder;
 class ViEPerformanceMonitor;
+class VieRemb;
 class VoEVideoSync;
 class VoiceEngine;
 
@@ -57,6 +59,9 @@
 
   VoiceEngine* GetVoiceEngine();
 
+  // Adds a channel to include when sending REMB.
+  bool SetRembStatus(int channel_id, bool sender, bool receiver);
+
  private:
   // Used by ViEChannelScoped, forcing a manager user to use scoped.
   // Returns a pointer to the channel with id 'channelId'.
@@ -92,6 +97,7 @@
   // Maps Channel id -> ViEEncoder.
   MapWrapper vie_encoder_map_;
   VoEVideoSync* voice_sync_interface_;
+  scoped_ptr<VieRemb> remb_;
   VoiceEngine* voice_engine_;
   ProcessThread* module_process_thread_;
 };
diff --git a/src/video_engine/vie_remb.cc b/src/video_engine/vie_remb.cc
new file mode 100644
index 0000000..837dcc4
--- /dev/null
+++ b/src/video_engine/vie_remb.cc
@@ -0,0 +1,173 @@
+/*
+ *  Copyright (c) 2011 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 "video_engine/vie_remb.h"
+
+#include <cassert>
+
+#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
+#include "system_wrappers/interface/critical_section_wrapper.h"
+#include "system_wrappers/interface/tick_util.h"
+#include "system_wrappers/interface/trace.h"
+
+namespace webrtc {
+
+const int kRembSendIntervallMs = 1000;
+
+// % threshold for if we should send a new REMB asap.
+const int kSendThresholdPercent = 97;
+
+VieRemb::VieRemb(int engine_id)
+    : engine_id_(engine_id),
+      list_crit_(CriticalSectionWrapper::CreateCriticalSection()),
+      last_remb_time_(TickTime::MillisecondTimestamp()),
+      last_send_bitrate_(0) {
+}
+
+VieRemb::~VieRemb() {
+}
+
+void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) {
+  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
+               "VieRemb::AddReceiveChannel");
+  assert(rtp_rtcp);
+
+  CriticalSectionScoped cs(list_crit_.get());
+  for (RtpModules::iterator it = receive_modules_.begin();
+       it != receive_modules_.end(); ++it) {
+    if ((*it) == rtp_rtcp)
+      return;
+  }
+
+  WEBRTC_TRACE(kTraceInfo, kTraceVideo, engine_id_, "AddRembChannel");
+  // The module probably doesn't have a remote SSRC yet, so don't add it to the
+  // map.
+  receive_modules_.push_back(rtp_rtcp);
+}
+
+void VieRemb::RemoveReceiveChannel(RtpRtcp* rtp_rtcp) {
+  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
+               "VieRemb::RemoveReceiveChannel");
+  assert(rtp_rtcp);
+
+  CriticalSectionScoped cs(list_crit_.get());
+  unsigned int ssrc = rtp_rtcp->RemoteSSRC();
+  for (RtpModules::iterator it = receive_modules_.begin();
+       it != receive_modules_.end(); ++it) {
+    if ((*it)->RemoteSSRC() == ssrc) {
+      receive_modules_.erase(it);
+      break;
+    }
+  }
+  bitrates_.erase(ssrc);
+}
+
+void VieRemb::AddSendChannel(RtpRtcp* rtp_rtcp) {
+  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
+               "VieRemb::AddSendChannel");
+  assert(rtp_rtcp);
+  assert(false);
+  return;
+}
+
+void VieRemb::RemoveSendChannel(RtpRtcp* rtp_rtcp) {
+  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
+               "VieRemb::AddSendChannel");
+  assert(rtp_rtcp);
+  assert(false);
+  return;
+}
+
+void VieRemb::OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate) {
+  WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
+               "VieRemb::UpdateBitrateEstimate(ssrc: %u, bitrate: %u)",
+               ssrc, bitrate);
+  CriticalSectionScoped cs(list_crit_.get());
+
+  // Check if this is a new ssrc and add it to the map if it is.
+  if (bitrates_.find(ssrc) == bitrates_.end()) {
+    bitrates_[ssrc] = bitrate;
+  }
+
+  int new_remb_bitrate = last_send_bitrate_ - bitrates_[ssrc] + bitrate;
+  if (new_remb_bitrate < kSendThresholdPercent * last_send_bitrate_ / 100) {
+    // The new bitrate estimate is less than kSendThresholdPercent % of the last
+    // report. Send a REMB asap.
+    last_remb_time_ = TickTime::MillisecondTimestamp() - kRembSendIntervallMs;
+  }
+  bitrates_[ssrc] = bitrate;
+}
+
+WebRtc_Word32 VieRemb::Version(WebRtc_Word8* version,
+                               WebRtc_UWord32& remaining_buffer_in_bytes,
+                               WebRtc_UWord32& position) const {
+  return 0;
+}
+
+WebRtc_Word32 VieRemb::ChangeUniqueId(const WebRtc_Word32 id) {
+  return 0;
+}
+
+WebRtc_Word32 VieRemb::TimeUntilNextProcess() {
+  return kRembSendIntervallMs -
+      (TickTime::MillisecondTimestamp() - last_remb_time_);
+}
+
+WebRtc_Word32 VieRemb::Process() {
+  int64_t now = TickTime::MillisecondTimestamp();
+  if (now - last_remb_time_ < kRembSendIntervallMs)
+    return 0;
+
+  last_remb_time_ = now;
+
+  // Calculate total receive bitrate estimate.
+  list_crit_->Enter();
+  int total_bitrate = 0;
+  int num_bitrates = bitrates_.size();
+
+  if (num_bitrates == 0) {
+    list_crit_->Leave();
+    return 0;
+  }
+
+  // TODO(mflodman) Use std::vector and change RTP module API.
+  unsigned int* ssrcs = new unsigned int[num_bitrates];
+
+  int idx = 0;
+  for (SsrcBitrate::iterator it = bitrates_.begin(); it != bitrates_.end();
+       ++it, ++idx) {
+    total_bitrate += it->second;
+    ssrcs[idx] = it->first;
+  }
+
+  // Send a REMB packet.
+  RtpRtcp* sender = NULL;
+  if (!send_modules_.empty()) {
+    sender = send_modules_.front();
+  } else {
+    for (RtpModules::iterator it = receive_modules_.begin();
+         it != receive_modules_.end(); ++it) {
+      if ((*it)->Sending()) {
+        sender = *it;
+        break;
+      }
+    }
+  }
+  last_send_bitrate_ = total_bitrate;
+  list_crit_->Leave();
+
+  if (sender) {
+    sender->SetREMBData(total_bitrate, num_bitrates, ssrcs);
+  }
+  delete [] ssrcs;
+  return 0;
+}
+
+}  // namespace webrtc
diff --git a/src/video_engine/vie_remb.h b/src/video_engine/vie_remb.h
new file mode 100644
index 0000000..b091cf4
--- /dev/null
+++ b/src/video_engine/vie_remb.h
@@ -0,0 +1,88 @@
+/*
+ *  Copyright (c) 2011 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.
+ */
+
+// 1. Register a RtpRtcp module to include in the REMB packet.
+// 2. When UpdateBitrateEstimate is called for the first time for a SSRC, add it
+//    to the map.
+// 3. Send a new REMB every kRembSendIntervallMs or if a lower bitrate estimate
+//    for a specified SSRC.
+
+
+#ifndef WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REMB_H_
+#define WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REMB_H_
+
+#include <list>
+#include <map>
+
+#include "modules/interface/module.h"
+#include "modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
+#include "system_wrappers/interface/scoped_ptr.h"
+
+namespace webrtc {
+
+class CriticalSectionWrapper;
+class RtpRtcp;
+
+class VieRemb : public RtpRemoteBitrateObserver, public Module {
+ public:
+  explicit VieRemb(int engine_id);
+  ~VieRemb();
+
+  // Called to add a receive channel to include in the REMB packet.
+  void AddReceiveChannel(RtpRtcp* rtp_rtcp);
+
+  // Removes the specified channel from REMB estimate.
+  void RemoveReceiveChannel(RtpRtcp* rtp_rtcp);
+
+  // Called to add a send channel to include in the REMB packet.
+  void AddSendChannel(RtpRtcp* rtp_rtcp);
+
+  // Removes the specified channel from receiving REMB packet estimates.
+  void RemoveSendChannel(RtpRtcp* rtp_rtcp);
+
+  // Called every time there is a new bitrate estimate for the received stream
+  // with given SSRC. This call will trigger a new RTCP REMB packet if the
+  // bitrate estimate has decreased or if no RTCP REMB packet has been sent for
+  // a certain time interval.
+  // Implements RtpReceiveBitrateUpdate.
+  virtual void OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate);
+
+  // Implements Module.
+  virtual WebRtc_Word32 Version(WebRtc_Word8* version,
+                                WebRtc_UWord32& remaining_buffer_in_bytes,
+                                WebRtc_UWord32& position) const;
+  virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
+  virtual WebRtc_Word32 TimeUntilNextProcess();
+  virtual WebRtc_Word32 Process();
+
+ private:
+  typedef std::list<RtpRtcp*> RtpModules;
+  typedef std::map<unsigned int, unsigned int> SsrcBitrate;
+
+  int engine_id_;
+  scoped_ptr<CriticalSectionWrapper> list_crit_;
+
+  // The last time a REMB was sent.
+  int64_t last_remb_time_;
+  int last_send_bitrate_;
+
+  // All RtpRtcp modules to include in the REMB packet.
+  RtpModules receive_modules_;
+
+  // All modules encoding and sending data.
+  RtpModules send_modules_;
+
+  // The last bitrate update for each SSRC.
+  SsrcBitrate bitrates_;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_VIDEO_ENGINE_MAIN_SOURCE_VIE_REMB_H_
diff --git a/src/video_engine/vie_remb_unittest.cc b/src/video_engine/vie_remb_unittest.cc
new file mode 100644
index 0000000..25ea5a0
--- /dev/null
+++ b/src/video_engine/vie_remb_unittest.cc
@@ -0,0 +1,294 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.8
+ *
+ *  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.
+ */
+
+
+// This file includes unit tests for ViERemb.
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
+#include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h"
+#include "system_wrappers/interface/scoped_ptr.h"
+#include "video_engine/vie_remb.h"
+
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::Return;
+
+namespace webrtc {
+
+class ViERembTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    vie_remb_.reset(new VieRemb(1234));
+  }
+  scoped_ptr<VieRemb> vie_remb_;
+};
+
+TEST_F(ViERembTest, OneModuleTestForSendingRemb)
+{
+  MockRtpRtcp rtp;
+  EXPECT_CALL(rtp, Sending())
+      .WillRepeatedly(Return(true));
+
+  vie_remb_->AddReceiveChannel(&rtp);
+
+  const unsigned int bitrate_estimate = 456;
+  unsigned int ssrc[] = { 1234 };
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
+  EXPECT_CALL(rtp, RemoteSSRC())
+      .WillRepeatedly(Return(ssrc[0]));
+
+  // TODO(mflodman) Add fake clock and remove the lowered bitrate below.
+  usleep(1010000);
+  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
+      .Times(1);
+  vie_remb_->Process();
+
+  // Lower bitrate to send another REMB packet.
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate - 100);
+  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate - 100, 1, _))
+        .Times(1);
+  vie_remb_->Process();
+
+  vie_remb_->RemoveReceiveChannel(&rtp);
+}
+
+TEST_F(ViERembTest, LowerEstimateToSendRemb)
+{
+  MockRtpRtcp rtp;
+  EXPECT_CALL(rtp, Sending())
+      .WillRepeatedly(Return(true));
+
+  vie_remb_->AddReceiveChannel(&rtp);
+
+  unsigned int bitrate_estimate = 456;
+  unsigned int ssrc[] = { 1234 };
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
+  EXPECT_CALL(rtp, RemoteSSRC())
+      .WillRepeatedly(Return(ssrc[0]));
+
+  // Lower the estimate with more than 3% to trigger a call to SetREMBData right
+  // away.
+  bitrate_estimate = bitrate_estimate - 100;
+  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
+      .Times(1);
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
+  vie_remb_->Process();
+}
+
+TEST_F(ViERembTest, VerifyCombinedBitrateEstimate)
+{
+  MockRtpRtcp rtp_0;
+  EXPECT_CALL(rtp_0, Sending())
+      .WillRepeatedly(Return(true));
+  MockRtpRtcp rtp_1;
+  EXPECT_CALL(rtp_1, Sending())
+      .WillRepeatedly(Return(true));
+
+  vie_remb_->AddReceiveChannel(&rtp_0);
+  vie_remb_->AddReceiveChannel(&rtp_1);
+
+  unsigned int bitrate_estimate[] = { 456, 789 };
+  unsigned int ssrc[] = { 1234, 5678 };
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
+  EXPECT_CALL(rtp_0, RemoteSSRC())
+      .Times(AnyNumber())
+      .WillRepeatedly(Return(ssrc[0]));
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1] + 100);
+  EXPECT_CALL(rtp_1, RemoteSSRC())
+      .Times(AnyNumber())
+      .WillRepeatedly(Return(ssrc[1]));
+
+  // Lower the estimate to trigger a callback.
+  int total_bitrate = bitrate_estimate[0] + bitrate_estimate[1];
+  EXPECT_CALL(rtp_0, SetREMBData(total_bitrate, 2, _))
+      .Times(1);
+  vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1]);
+  vie_remb_->Process();
+
+  vie_remb_->RemoveReceiveChannel(&rtp_0);
+  vie_remb_->RemoveReceiveChannel(&rtp_1);
+}
+
+TEST_F(ViERembTest, NoRembForIncreasedBitrate)
+{
+  MockRtpRtcp rtp_0;
+  EXPECT_CALL(rtp_0, Sending())
+      .WillRepeatedly(Return(true));
+  MockRtpRtcp rtp_1;
+  EXPECT_CALL(rtp_1, Sending())
+      .WillRepeatedly(Return(true));
+
+  vie_remb_->AddReceiveChannel(&rtp_0);
+  vie_remb_->AddReceiveChannel(&rtp_1);
+
+  unsigned int bitrate_estimate[] = { 456, 789 };
+  unsigned int ssrc[] = { 1234, 5678 };
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
+  EXPECT_CALL(rtp_0, RemoteSSRC())
+      .Times(AnyNumber())
+      .WillRepeatedly(Return(ssrc[0]));
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1]);
+  EXPECT_CALL(rtp_1, RemoteSSRC())
+      .Times(AnyNumber())
+      .WillRepeatedly(Return(ssrc[1]));
+
+  // Trigger a first call to have a running state.
+  // TODO(mflodman) Add fake clock.
+  usleep(1010000);
+  EXPECT_CALL(rtp_0,
+              SetREMBData(bitrate_estimate[0] + bitrate_estimate[1], 2, _))
+      .Times(1);
+  vie_remb_->Process();
+
+  // Increased estimate shouldn't trigger a callback right away.
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0] + 1);
+  EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
+      .Times(0);
+
+  // Decresing the estimate less than 3% shouldn't trigger a new callback.
+  int lower_estimate = bitrate_estimate[0] * 98 / 100;
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], lower_estimate);
+   EXPECT_CALL(rtp_0, SetREMBData(_, _, _))
+       .Times(0);
+
+  vie_remb_->Process();
+  vie_remb_->RemoveReceiveChannel(&rtp_1);
+  vie_remb_->RemoveReceiveChannel(&rtp_0);
+}
+
+TEST_F(ViERembTest, ChangeSendRtpModule)
+{
+  MockRtpRtcp rtp_0;
+  EXPECT_CALL(rtp_0, Sending())
+      .WillRepeatedly(Return(true));
+  MockRtpRtcp rtp_1;
+  EXPECT_CALL(rtp_1, Sending())
+      .WillRepeatedly(Return(true));
+
+  vie_remb_->AddReceiveChannel(&rtp_0);
+  vie_remb_->AddReceiveChannel(&rtp_1);
+
+  unsigned int bitrate_estimate[] = { 456, 789 };
+  unsigned int ssrc[] = { 1234, 5678 };
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
+  EXPECT_CALL(rtp_0, RemoteSSRC())
+      .Times(AnyNumber())
+      .WillRepeatedly(Return(ssrc[0]));
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1]);
+  EXPECT_CALL(rtp_1, RemoteSSRC())
+      .Times(AnyNumber())
+      .WillRepeatedly(Return(ssrc[1]));
+
+  // Decrease estimate to trigger a REMB.
+  bitrate_estimate[0] = bitrate_estimate[0] - 100;
+  EXPECT_CALL(rtp_0, SetREMBData(bitrate_estimate[0] + bitrate_estimate[1], 2,
+                                 _))
+      .Times(1);
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
+  vie_remb_->Process();
+
+  // Remove the sending module, add it again -> should get remb on the second
+  // module.
+  vie_remb_->RemoveReceiveChannel(&rtp_0);
+  vie_remb_->AddReceiveChannel(&rtp_0);
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
+
+  bitrate_estimate[1] = bitrate_estimate[1] - 100;
+  EXPECT_CALL(rtp_1, SetREMBData(bitrate_estimate[0] + bitrate_estimate[1], 2,
+                                 _))
+        .Times(1);
+  vie_remb_->OnReceiveBitrateChanged(ssrc[1], bitrate_estimate[1]);
+  vie_remb_->Process();
+
+  vie_remb_->RemoveReceiveChannel(&rtp_0);
+  vie_remb_->RemoveReceiveChannel(&rtp_1);
+}
+
+TEST_F(ViERembTest, OnlyOneRembForDoubleProcess)
+{
+  MockRtpRtcp rtp;
+  EXPECT_CALL(rtp, Sending())
+      .WillRepeatedly(Return(true));
+
+  unsigned int bitrate_estimate = 456;
+  unsigned int ssrc[] = { 1234 };
+
+  vie_remb_->AddReceiveChannel(&rtp);
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
+  EXPECT_CALL(rtp, RemoteSSRC())
+      .WillRepeatedly(Return(ssrc[0]));
+
+  // Lower the estimate, should trigger a call to SetREMBData right away.
+  bitrate_estimate = bitrate_estimate - 100;
+  EXPECT_CALL(rtp, SetREMBData(bitrate_estimate, 1, _))
+      .Times(1);
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
+  vie_remb_->Process();
+
+  // Call Process again, this should not trigger a new callback.
+  EXPECT_CALL(rtp, SetREMBData(_, _, _))
+      .Times(0);
+  vie_remb_->Process();
+  vie_remb_->RemoveReceiveChannel(&rtp);
+}
+
+TEST_F(ViERembTest, NoOnReceivedBitrateChangedCall)
+{
+  MockRtpRtcp rtp;
+  EXPECT_CALL(rtp, RemoteSSRC())
+        .WillRepeatedly(Return(1234));
+
+  vie_remb_->AddReceiveChannel(&rtp);
+  // TODO(mflodman) Add fake clock.
+  usleep(1010000);
+  // No bitrate estimate given, no callback expected.
+  EXPECT_CALL(rtp, SetREMBData(_, _, _))
+      .Times(0);
+  vie_remb_->Process();
+
+  vie_remb_->RemoveReceiveChannel(&rtp);
+}
+
+TEST_F(ViERembTest, NoSendingRtpModule)
+{
+  MockRtpRtcp rtp;
+  EXPECT_CALL(rtp, Sending())
+      .WillRepeatedly(Return(false));
+
+  vie_remb_->AddReceiveChannel(&rtp);
+
+  unsigned int bitrate_estimate = 456;
+  unsigned int ssrc[] = { 1234 };
+
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
+  EXPECT_CALL(rtp, RemoteSSRC())
+      .WillRepeatedly(Return(ssrc[0]));
+
+  // Lower the estimate. This should normally trigger a callback, but not now
+  // since we have no sending module.
+  bitrate_estimate = bitrate_estimate - 100;
+  EXPECT_CALL(rtp, SetREMBData(_, _, _))
+      .Times(0);
+  vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
+  vie_remb_->Process();
+}
+
+}  // namespace webrtc
diff --git a/src/video_engine/vie_rtp_rtcp_impl.cc b/src/video_engine/vie_rtp_rtcp_impl.cc
index bf14646..4bba011 100644
--- a/src/video_engine/vie_rtp_rtcp_impl.cc
+++ b/src/video_engine/vie_rtp_rtcp_impl.cc
@@ -541,6 +541,14 @@
   return 0;
 }
 
+bool ViERTP_RTCPImpl::SetRembStatus(int video_channel, bool sender,
+                                   bool receiver) {
+  WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_, video_channel),
+               "ViERTP_RTCPImpl::SetRembStatus(%d, %d, %d)", video_channel,
+               sender, receiver);
+  return channel_manager_.SetRembStatus(video_channel, sender, receiver);
+}
+
 int ViERTP_RTCPImpl::GetReceivedRTCPStatistics(const int video_channel,
                                                unsigned short& fraction_lost,
                                                unsigned int& cumulative_lost,
diff --git a/src/video_engine/vie_rtp_rtcp_impl.h b/src/video_engine/vie_rtp_rtcp_impl.h
index ef17b1c..f074b48 100644
--- a/src/video_engine/vie_rtp_rtcp_impl.h
+++ b/src/video_engine/vie_rtp_rtcp_impl.h
@@ -65,6 +65,7 @@
   virtual int SetKeyFrameRequestMethod(const int video_channel,
                                        const ViEKeyFrameRequestMethod method);
   virtual int SetTMMBRStatus(const int video_channel, const bool enable);
+  virtual bool SetRembStatus(int video_channel, bool sender, bool receiver);
   virtual int GetReceivedRTCPStatistics(const int video_channel,
                                         unsigned short& fraction_lost,
                                         unsigned int& cumulative_lost,