Added RTX to ViE. 
Review URL: http://webrtc-codereview.appspot.com/336001

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1373 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/modules/modules.gyp b/src/modules/modules.gyp
index 86678a7..83b5cc6 100644
--- a/src/modules/modules.gyp
+++ b/src/modules/modules.gyp
@@ -49,6 +49,7 @@
         'rtp_rtcp/source/rtp_rtcp_tests.gypi',
         'rtp_rtcp/test/test_bwe/test_bwe.gypi',
         'rtp_rtcp/test/testFec/test_fec.gypi',
+        'rtp_rtcp/test/testAPI/test_api.gypi',
         'video_coding/main/source/video_coding_test.gypi',
         'video_coding/codecs/test/video_codecs_test_framework.gypi',
         'video_coding/codecs/tools/video_codecs_tools.gypi',
diff --git a/src/modules/rtp_rtcp/interface/rtp_rtcp.h b/src/modules/rtp_rtcp/interface/rtp_rtcp.h
index 2a1aef3..646501d 100644
--- a/src/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/src/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -261,7 +261,20 @@
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32 SetSSRCFilter(const bool enable, const WebRtc_UWord32 allowedSSRC) = 0;
+    virtual WebRtc_Word32 SetSSRCFilter(const bool enable,
+                                        const WebRtc_UWord32 allowedSSRC) = 0;
+
+    /*
+    * Turn on/off receiving RTX (RFC 4588) on a specific SSRC.
+    */
+    virtual WebRtc_Word32 SetRTXReceiveStatus(const bool enable,
+                                              const WebRtc_UWord32 SSRC) = 0;
+
+    /*
+    * Get status of receiving RTX (RFC 4588) on a specific SSRC.
+    */
+    virtual WebRtc_Word32 RTXReceiveStatus(bool* enable,
+                                           WebRtc_UWord32* SSRC) const = 0;
 
     /*
     *   called by the network module when we receive a packet
@@ -360,9 +373,10 @@
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32 SetRTPKeepaliveStatus(const bool enable,
-                                              const WebRtc_Word8 unknownPayloadType,
-                                              const WebRtc_UWord16 deltaTransmitTimeMS) = 0;
+    virtual WebRtc_Word32 SetRTPKeepaliveStatus(
+        const bool enable,
+        const WebRtc_Word8 unknownPayloadType,
+        const WebRtc_UWord16 deltaTransmitTimeMS) = 0;
 
     /*
     *   Get RTPKeepaliveStatus
@@ -406,7 +420,8 @@
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32 DeRegisterSendPayload(const WebRtc_Word8 payloadType) = 0;
+    virtual WebRtc_Word32 DeRegisterSendPayload(
+        const WebRtc_Word8 payloadType) = 0;
 
    /*
     *   (De)register RTP header extension type and id.
@@ -432,7 +447,8 @@
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32 SetStartTimestamp(const WebRtc_UWord32 timestamp) = 0;
+    virtual WebRtc_Word32 SetStartTimestamp(
+        const WebRtc_UWord32 timestamp) = 0;
 
     /*
     *   Get SequenceNumber
@@ -465,7 +481,8 @@
     *
     *   return -1 on failure else number of valid entries in the array
     */
-    virtual WebRtc_Word32 CSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const = 0;
+    virtual WebRtc_Word32 CSRCs(
+        WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const = 0;
 
     /*
     *   Set CSRC
@@ -475,8 +492,9 @@
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32 SetCSRCs( const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
-                                  const WebRtc_UWord8 arrLength) = 0;
+    virtual WebRtc_Word32 SetCSRCs(
+        const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
+        const WebRtc_UWord8 arrLength) = 0;
 
     /*
     *   includes CSRCs in RTP header if enabled
@@ -490,6 +508,20 @@
     virtual WebRtc_Word32 SetCSRCStatus(const bool include) = 0;
 
     /*
+    * Turn on/off sending RTX (RFC 4588) on a specific SSRC.
+    */
+    virtual WebRtc_Word32 SetRTXSendStatus(const bool enable,
+                                           const bool setSSRC,
+                                           const WebRtc_UWord32 SSRC) = 0;
+
+
+    /*
+    * Get status of sending RTX (RFC 4588) on a specific SSRC.
+    */
+    virtual WebRtc_Word32 RTXSendStatus(bool* enable,
+                                        WebRtc_UWord32* SSRC) const = 0;
+
+    /*
     *   sends kRtcpByeCode when going from true to false
     *
     *   sending - on/off
@@ -537,14 +569,14 @@
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32
-    SendOutgoingData(const FrameType frameType,
-                     const WebRtc_Word8 payloadType,
-                     const WebRtc_UWord32 timeStamp,
-                     const WebRtc_UWord8* payloadData,
-                     const WebRtc_UWord32 payloadSize,
-                     const RTPFragmentationHeader* fragmentation = NULL,
-                     const RTPVideoHeader* rtpVideoHdr = NULL) = 0;
+    virtual WebRtc_Word32 SendOutgoingData(
+        const FrameType frameType,
+        const WebRtc_Word8 payloadType,
+        const WebRtc_UWord32 timeStamp,
+        const WebRtc_UWord8* payloadData,
+        const WebRtc_UWord32 payloadSize,
+        const RTPFragmentationHeader* fragmentation = NULL,
+        const RTPVideoHeader* rtpVideoHdr = NULL) = 0;
 
     /**************************************************************************
     *
@@ -594,26 +626,29 @@
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32 RemoteCNAME(const WebRtc_UWord32 remoteSSRC,
-                                    WebRtc_Word8 cName[RTCP_CNAME_SIZE]) const = 0;
+    virtual WebRtc_Word32 RemoteCNAME(
+        const WebRtc_UWord32 remoteSSRC,
+        WebRtc_Word8 cName[RTCP_CNAME_SIZE]) const = 0;
 
     /*
     *   Get remote NTP
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32 RemoteNTP(WebRtc_UWord32 *ReceivedNTPsecs,
-                                  WebRtc_UWord32 *ReceivedNTPfrac,
-                                  WebRtc_UWord32 *RTCPArrivalTimeSecs,
-                                  WebRtc_UWord32 *RTCPArrivalTimeFrac) const  = 0;
+    virtual WebRtc_Word32 RemoteNTP(
+        WebRtc_UWord32 *ReceivedNTPsecs,
+        WebRtc_UWord32 *ReceivedNTPfrac,
+        WebRtc_UWord32 *RTCPArrivalTimeSecs,
+        WebRtc_UWord32 *RTCPArrivalTimeFrac) const  = 0;
 
     /*
     *   AddMixedCNAME
     *
     *   return -1 on failure else 0
     */
-    virtual WebRtc_Word32 AddMixedCNAME(const WebRtc_UWord32 SSRC,
-                                      const WebRtc_Word8 cName[RTCP_CNAME_SIZE]) = 0;
+    virtual WebRtc_Word32 AddMixedCNAME(
+        const WebRtc_UWord32 SSRC,
+        const WebRtc_Word8 cName[RTCP_CNAME_SIZE]) = 0;
 
     /*
     *   RemoveMixedCNAME
@@ -628,10 +663,10 @@
     *   return -1 on failure else 0
     */
     virtual WebRtc_Word32 RTT(const WebRtc_UWord32 remoteSSRC,
-                            WebRtc_UWord16* RTT,
-                            WebRtc_UWord16* avgRTT,
-                            WebRtc_UWord16* minRTT,
-                            WebRtc_UWord16* maxRTT) const = 0 ;
+                              WebRtc_UWord16* RTT,
+                              WebRtc_UWord16* avgRTT,
+                              WebRtc_UWord16* minRTT,
+                              WebRtc_UWord16* maxRTT) const = 0 ;
 
     /*
     *   Reset RoundTripTime statistics
diff --git a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index c7033b3..3721316 100644
--- a/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/src/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -60,6 +60,10 @@
       WebRtc_Word32(WebRtc_UWord32& allowedSSRC));
   MOCK_METHOD2(SetSSRCFilter,
       WebRtc_Word32(const bool enable, const WebRtc_UWord32 allowedSSRC));
+  MOCK_METHOD2(SetRTXReceiveStatus,
+      WebRtc_Word32(const bool enable, const WebRtc_UWord32 SSRC));
+  MOCK_CONST_METHOD2(RTXReceiveStatus,
+      WebRtc_Word32(bool* enable, WebRtc_UWord32* SSRC));
   MOCK_METHOD2(IncomingPacket,
       WebRtc_Word32(const WebRtc_UWord8* incomingPacket, const WebRtc_UWord16 packetLength));
   MOCK_METHOD4(IncomingAudioNTP,
@@ -110,6 +114,10 @@
       WebRtc_Word32(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize], const WebRtc_UWord8 arrLength));
   MOCK_METHOD1(SetCSRCStatus,
       WebRtc_Word32(const bool include));
+  MOCK_METHOD3(SetRTXSendStatus,
+      WebRtc_Word32(const bool enable, const bool setSSRC, const WebRtc_UWord32 SSRC));
+ MOCK_CONST_METHOD2(RTXSendStatus,
+      WebRtc_Word32(bool* enable, WebRtc_UWord32* SSRC));
   MOCK_METHOD1(SetSendingStatus,
       WebRtc_Word32(const bool sending));
   MOCK_CONST_METHOD0(Sending,
diff --git a/src/modules/rtp_rtcp/source/rtp_receiver.cc b/src/modules/rtp_rtcp/source/rtp_receiver.cc
index a864b9d..159f0cc 100644
--- a/src/modules/rtp_rtcp/source/rtp_receiver.cc
+++ b/src/modules/rtp_rtcp/source/rtp_receiver.cc
@@ -84,17 +84,18 @@
     _lastReportJitter(0),
     _lastReportJitterTransmissionTimeOffset(0),
 
-    _nackMethod(kNackOff)
-{
-    memset(_currentRemoteCSRC, 0, sizeof(_currentRemoteCSRC));
-    memset(_currentRemoteEnergy, 0, sizeof(_currentRemoteEnergy));
-    memset(&_lastReceivedAudioSpecific, 0, sizeof(_lastReceivedAudioSpecific));
+    _nackMethod(kNackOff),
+    _RTX(false),
+    _ssrcRTX(0) {
+  memset(_currentRemoteCSRC, 0, sizeof(_currentRemoteCSRC));
+  memset(_currentRemoteEnergy, 0, sizeof(_currentRemoteEnergy));
+  memset(&_lastReceivedAudioSpecific, 0, sizeof(_lastReceivedAudioSpecific));
 
-    _lastReceivedAudioSpecific.channels = 1;
-    _lastReceivedVideoSpecific.maxRate = 0;
-    _lastReceivedVideoSpecific.videoCodecType = kRtpNoVideo;
+  _lastReceivedAudioSpecific.channels = 1;
+  _lastReceivedVideoSpecific.maxRate = 0;
+  _lastReceivedVideoSpecific.videoCodecType = kRtpNoVideo;
 
-    WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
+  WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
 }
 
 RTPReceiver::~RTPReceiver()
@@ -729,6 +730,19 @@
     return 0;
 }
 
+void RTPReceiver::SetRTXStatus(const bool enable,
+                               const WebRtc_UWord32 SSRC) {
+  CriticalSectionScoped lock(_criticalSectionRTPReceiver);
+  _RTX = enable;
+  _ssrcRTX = SSRC;
+}
+
+void RTPReceiver::RTXStatus(bool* enable, WebRtc_UWord32* SSRC) const {
+  CriticalSectionScoped lock(_criticalSectionRTPReceiver);
+  *enable = _RTX;
+  *SSRC = _ssrcRTX;
+}
+
 WebRtc_UWord32
 RTPReceiver::SSRC() const
 {
@@ -765,136 +779,143 @@
     return _numEnergy;
 }
 
-WebRtc_Word32
-RTPReceiver::IncomingRTPPacket(WebRtcRTPHeader* rtpHeader,
-                               const WebRtc_UWord8* incomingRtpPacket,
-                               const WebRtc_UWord16 incomingRtpPacketLength)
-{
-    // rtpHeader now contains the parsed RTP header.
-    // Adjust packet length w r t RTP padding.
-    WebRtc_Word32 length = incomingRtpPacketLength - rtpHeader->header.paddingLength;
+WebRtc_Word32 RTPReceiver::IncomingRTPPacket(
+    WebRtcRTPHeader* rtp_header,
+    const WebRtc_UWord8* packet,
+    const WebRtc_UWord16 packet_length) {
+  // rtp_header contains the parsed RTP header.
+  // Adjust packet length w r t RTP padding.
+  int length = packet_length - rtp_header->header.paddingLength;
 
-    // length sanity
-    if((length - rtpHeader->header.headerLength) < 0)
-    {
-        WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
-        return -1;
-    }
-    if(_useSSRCFilter)
-    {
-        if(rtpHeader->header.ssrc != _SSRCFilter)
-        {
-            WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s drop packet due to SSRC filter", __FUNCTION__);
-            return -1;
-        }
-    }
-    if(_lastReceiveTime == 0)
-    {
-        // trigger only once
-        CriticalSectionScoped lock(_criticalSectionCbs);
-        if(_cbRtpFeedback)
-        {
-            if(length - rtpHeader->header.headerLength == 0)
-            {
-                // keepalive packet
-                _cbRtpFeedback->OnReceivedPacket(_id, kPacketKeepAlive);
-            }else
-            {
-                _cbRtpFeedback->OnReceivedPacket(_id, kPacketRtp);
-            }
-        }
-    }
-    WebRtc_Word8 firstPayloadByte = 0;
-    if(length > 0)
-    {
-        firstPayloadByte = incomingRtpPacket[rtpHeader->header.headerLength];
-    }
-
-    // trigger our callbacks
-    CheckSSRCChanged(rtpHeader);
-
-    bool isRED = false;
-    ModuleRTPUtility::VideoPayload videoSpecific;
-    videoSpecific.maxRate = 0;
-    videoSpecific.videoCodecType = kRtpNoVideo;
-
-    ModuleRTPUtility::AudioPayload audioSpecific;
-    audioSpecific.bitsPerSample = 0;
-    audioSpecific.channels = 0;
-    audioSpecific.frequency = 0;
-
-    if (CheckPayloadChanged(rtpHeader,
-                            firstPayloadByte,
-                            isRED,
-                            audioSpecific,
-                            videoSpecific) == -1)
-    {
-        if (length - rtpHeader->header.headerLength == 0)
-        {
-            // ok keepalive packet
-            WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
-                 "%s received keepalive",
+  // length sanity
+  if ((length - rtp_header->header.headerLength) < 0) {
+     WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
+                  "%s invalid argument",
                   __FUNCTION__);
-            return 0;
-        }
-        WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
-             "%s received invalid payloadtype",
-              __FUNCTION__);
+     return -1;
+  }
+  if (_RTX) {
+    if (_ssrcRTX == rtp_header->header.ssrc) {
+      // Sanity check.
+      if (rtp_header->header.headerLength + 2 > packet_length) {
         return -1;
+      }
+      rtp_header->header.ssrc = _SSRC;
+      rtp_header->header.sequenceNumber =
+          (packet[rtp_header->header.headerLength] << 8) +
+          packet[1 + rtp_header->header.headerLength];
+      // Count the RTX header as part of the RTP header.
+      rtp_header->header.headerLength += 2;
     }
-    CheckCSRC(rtpHeader);
-
-    WebRtc_Word32 retVal = 0;
-    const WebRtc_UWord8* payloadData       = incomingRtpPacket + rtpHeader->header.headerLength;
-    const WebRtc_UWord16 payloadDataLength = (WebRtc_UWord16)(length - rtpHeader->header.headerLength);
-
-    if(_audio)
-    {
-        retVal = ParseAudioCodecSpecific(rtpHeader,
-                                         payloadData,
-                                         payloadDataLength,
-                                         audioSpecific,
-                                         isRED);
-    } else
-    {
-        retVal = ParseVideoCodecSpecific(rtpHeader,
-                                         payloadData,
-                                         payloadDataLength,
-                                         videoSpecific.videoCodecType,
-                                         isRED,
-                                         incomingRtpPacket,
-                                         incomingRtpPacketLength,
-                                         _clock.GetTimeInMS());
+  }
+  if (_useSSRCFilter) {
+    if (rtp_header->header.ssrc != _SSRCFilter) {
+      WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
+                   "%s drop packet due to SSRC filter",
+                   __FUNCTION__);
+      return -1;
     }
-    if(retVal != -1)
-    {
-        CriticalSectionScoped lock(_criticalSectionRTPReceiver);
-
-        // this compare to _receivedSeqMax
-        // we store the last received after we have done the callback
-        const bool oldPacket = RetransmitOfOldPacket(rtpHeader->header.sequenceNumber,
-                                                     rtpHeader->header.timestamp);
-
-        // this updates _receivedSeqMax and other members
-        UpdateStatistics(rtpHeader, payloadDataLength, oldPacket);
-
-        // need to be updated after RetransmitOfOldPacket &
-        // RetransmitOfOldPacketUpdateStatistics
-        _lastReceiveTime = _clock.GetTimeInMS();
-        _lastReceivedPayloadLength = payloadDataLength;
-
-        if(retVal >= 0 && !oldPacket)
-        {
-            if(_lastReceivedTimestamp != rtpHeader->header.timestamp)
-            {
-                _lastReceivedTimestamp = rtpHeader->header.timestamp;
-            }
-            _lastReceivedSequenceNumber = rtpHeader->header.sequenceNumber;
-            _lastReceivedTransmissionTimeOffset =
-                rtpHeader->extension.transmissionTimeOffset;
-        }
+  }
+  if (_lastReceiveTime == 0) {
+    // trigger only once
+    CriticalSectionScoped lock(_criticalSectionCbs);
+    if (_cbRtpFeedback) {
+      if (length - rtp_header->header.headerLength == 0) {
+        // keepalive packet
+        _cbRtpFeedback->OnReceivedPacket(_id, kPacketKeepAlive);
+      } else {
+        _cbRtpFeedback->OnReceivedPacket(_id, kPacketRtp);
+      }
     }
+  }
+  WebRtc_Word8 first_payload_byte = 0;
+  if (length > 0) {
+    first_payload_byte = packet[rtp_header->header.headerLength];
+  }
+  // trigger our callbacks
+  CheckSSRCChanged(rtp_header);
+
+  bool is_red = false;
+  ModuleRTPUtility::VideoPayload video_specific;
+  video_specific.maxRate = 0;
+  video_specific.videoCodecType = kRtpNoVideo;
+
+  ModuleRTPUtility::AudioPayload audio_specific;
+  audio_specific.bitsPerSample = 0;
+  audio_specific.channels = 0;
+  audio_specific.frequency = 0;
+
+  if (CheckPayloadChanged(rtp_header,
+                          first_payload_byte,
+                          is_red,
+                          audio_specific,
+                          video_specific) == -1) {
+    if (length - rtp_header->header.headerLength == 0)
+    {
+      // ok keepalive packet
+      WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
+                   "%s received keepalive",
+                   __FUNCTION__);
+      return 0;
+    }
+    WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
+                 "%s received invalid payloadtype",
+                 __FUNCTION__);
+    return -1;
+  }
+  CheckCSRC(rtp_header);
+
+  const WebRtc_UWord8* payload_data =
+      packet + rtp_header->header.headerLength;
+
+  WebRtc_UWord16 payload_data_length =
+      static_cast<WebRtc_UWord16>(length - rtp_header->header.headerLength);
+
+  WebRtc_Word32 retVal = 0;
+  if(_audio) {
+    retVal = ParseAudioCodecSpecific(rtp_header,
+                                     payload_data,
+                                     payload_data_length,
+                                     audio_specific,
+                                     is_red);
+  } else {
+    retVal = ParseVideoCodecSpecific(rtp_header,
+                                     payload_data,
+                                     payload_data_length,
+                                     video_specific.videoCodecType,
+                                     is_red,
+                                     packet,
+                                     packet_length,
+                                     _clock.GetTimeInMS());
+  }
+  if(retVal < 0) {
     return retVal;
+  }
+
+  CriticalSectionScoped lock(_criticalSectionRTPReceiver);
+
+  // this compare to _receivedSeqMax
+  // we store the last received after we have done the callback
+  bool old_packet = RetransmitOfOldPacket(rtp_header->header.sequenceNumber,
+                                          rtp_header->header.timestamp);
+
+  // this updates _receivedSeqMax and other members
+  UpdateStatistics(rtp_header, payload_data_length, old_packet);
+
+  // Need to be updated after RetransmitOfOldPacket &
+  // RetransmitOfOldPacketUpdateStatistics
+  _lastReceiveTime = _clock.GetTimeInMS();
+  _lastReceivedPayloadLength = payload_data_length;
+
+  if (!old_packet) {
+    if (_lastReceivedTimestamp != rtp_header->header.timestamp) {
+      _lastReceivedTimestamp = rtp_header->header.timestamp;
+    }
+    _lastReceivedSequenceNumber = rtp_header->header.sequenceNumber;
+    _lastReceivedTransmissionTimeOffset =
+        rtp_header->extension.transmissionTimeOffset;
+  }
+  return retVal;
 }
 
 // must not have critsect when called
diff --git a/src/modules/rtp_rtcp/source/rtp_receiver.h b/src/modules/rtp_rtcp/source/rtp_receiver.h
index 2fb8b2e..32916c7 100644
--- a/src/modules/rtp_rtcp/source/rtp_receiver.h
+++ b/src/modules/rtp_rtcp/source/rtp_receiver.h
@@ -147,6 +147,12 @@
 
     virtual WebRtc_UWord32 PayloadTypeToPayload(const WebRtc_UWord8 payloadType,
                                                 ModuleRTPUtility::Payload*& payload) const;
+    /*
+    *  RTX
+    */
+    void SetRTXStatus(const bool enable, const WebRtc_UWord32 SSRC);
+
+    void RTXStatus(bool* enable, WebRtc_UWord32* SSRC) const;
 
 protected:
     virtual WebRtc_Word32 CallbackOfReceivedPayloadData(const WebRtc_UWord8* payloadData,
@@ -246,8 +252,10 @@
     mutable WebRtc_UWord32    _lastReportJitter;
     mutable WebRtc_UWord32    _lastReportJitterTransmissionTimeOffset;
 
-    // NACK
-    NACKMethod          _nackMethod;
+    NACKMethod _nackMethod;
+
+    bool _RTX;
+    WebRtc_UWord32 _ssrcRTX;
 };
 } // namespace webrtc
 
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 5a33f0d..378b078 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -690,6 +690,33 @@
     return _rtpReceiver.CSRCs(arrOfCSRC);
 }
 
+WebRtc_Word32 ModuleRtpRtcpImpl::SetRTXSendStatus(
+    const bool enable,
+    const bool setSSRC,
+    const WebRtc_UWord32 SSRC) {
+  _rtpSender.SetRTXStatus(enable, setSSRC, SSRC);
+  return 0;
+}
+
+WebRtc_Word32 ModuleRtpRtcpImpl::RTXSendStatus(bool* enable,
+                                               WebRtc_UWord32* SSRC) const {
+  _rtpSender.RTXStatus(enable, SSRC);
+  return 0;
+}
+
+WebRtc_Word32 ModuleRtpRtcpImpl::SetRTXReceiveStatus(
+    const bool enable,
+    const WebRtc_UWord32 SSRC) {
+  _rtpReceiver.SetRTXStatus(enable, SSRC);
+  return 0;
+}
+
+WebRtc_Word32 ModuleRtpRtcpImpl::RTXReceiveStatus(bool* enable,
+                                                  WebRtc_UWord32* SSRC) const {
+  _rtpReceiver.RTXStatus(enable, SSRC);
+  return 0;
+}
+
 // called by the network module when we receive a packet
 WebRtc_Word32
 ModuleRtpRtcpImpl::IncomingPacket(const WebRtc_UWord8* incomingPacket,
diff --git a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index cec02cd..8548bba 100644
--- a/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/src/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -112,12 +112,16 @@
     // Get the current estimated remote timestamp
     virtual WebRtc_Word32 EstimatedRemoteTimeStamp(WebRtc_UWord32& timestamp) const;
 
-    // Get incoming SSRC
     virtual WebRtc_UWord32 RemoteSSRC() const;
 
-    // Get remote CSRC
     virtual WebRtc_Word32 RemoteCSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const ;
 
+    virtual WebRtc_Word32 SetRTXReceiveStatus(const bool enable,
+                                              const WebRtc_UWord32 SSRC);
+
+    virtual WebRtc_Word32 RTXReceiveStatus(bool* enable,
+                                           WebRtc_UWord32* SSRC) const;
+
     // called by the network module when we receive a packet
     virtual WebRtc_Word32 IncomingPacket( const WebRtc_UWord8* incomingPacket,
                                         const WebRtc_UWord16 packetLength);
@@ -183,22 +187,18 @@
     // configure start timestamp, default is a random number
     virtual WebRtc_Word32 SetStartTimestamp(const WebRtc_UWord32 timestamp);
 
-    // Get SequenceNumber
     virtual WebRtc_UWord16 SequenceNumber() const;
 
     // Set SequenceNumber, default is a random number
     virtual WebRtc_Word32 SetSequenceNumber(const WebRtc_UWord16 seq);
 
-    // Get SSRC
     virtual WebRtc_UWord32 SSRC() const;
 
     // configure SSRC, default is a random number
     virtual WebRtc_Word32 SetSSRC(const WebRtc_UWord32 ssrc);
 
-    // Get CSRC
     virtual WebRtc_Word32 CSRCs( WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize]) const ;
 
-    // Set CSRC
     virtual WebRtc_Word32 SetCSRCs( const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
                                   const WebRtc_UWord8 arrLength);
 
@@ -210,30 +210,35 @@
 
     virtual WebRtc_UWord32 ByteCountSent() const;
 
+    virtual WebRtc_Word32 SetRTXSendStatus(const bool enable,
+                                           const bool setSSRC,
+                                           const WebRtc_UWord32 SSRC);
+
+    virtual WebRtc_Word32 RTXSendStatus(bool* enable,
+                                        WebRtc_UWord32* SSRC) const;
+
     // sends kRtcpByeCode when going from true to false
     virtual WebRtc_Word32 SetSendingStatus(const bool sending);
 
-    // get send status
     virtual bool Sending() const;
 
     // Drops or relays media packets
     virtual WebRtc_Word32 SetSendingMediaStatus(const bool sending);
 
-    // Send media status
     virtual bool SendingMedia() const;
 
     // Used by the module to send RTP and RTCP packet to the network module
     virtual WebRtc_Word32 RegisterSendTransport(Transport* outgoingTransport);
 
     // Used by the codec module to deliver a video or audio frame for packetization
-    virtual WebRtc_Word32
-    SendOutgoingData(const FrameType frameType,
-                     const WebRtc_Word8 payloadType,
-                     const WebRtc_UWord32 timeStamp,
-                     const WebRtc_UWord8* payloadData,
-                     const WebRtc_UWord32 payloadSize,
-                     const RTPFragmentationHeader* fragmentation = NULL,
-                     const RTPVideoHeader* rtpVideoHdr = NULL);
+    virtual WebRtc_Word32 SendOutgoingData(
+        const FrameType frameType,
+        const WebRtc_Word8 payloadType,
+        const WebRtc_UWord32 timeStamp,
+        const WebRtc_UWord8* payloadData,
+        const WebRtc_UWord32 payloadSize,
+        const RTPFragmentationHeader* fragmentation = NULL,
+        const RTPVideoHeader* rtpVideoHdr = NULL);
 
     /*
     *   RTCP
diff --git a/src/modules/rtp_rtcp/source/rtp_sender.cc b/src/modules/rtp_rtcp/source/rtp_sender.cc
index d6c9175..e1fa13d 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/src/modules/rtp_rtcp/source/rtp_sender.cc
@@ -74,12 +74,15 @@
     _remoteSSRC(0),
     _sequenceNumberForced(false),
     _sequenceNumber(0),
+    _sequenceNumberRTX(0),
     _ssrcForced(false),
     _ssrc(0),
     _timeStamp(0),
     _CSRCs(0),
     _CSRC(),
-    _includeCSRCs(true)
+    _includeCSRCs(true),
+    _RTX(false),
+    _ssrcRTX(0)
 {
     memset(_nackByteCountTimes, 0, sizeof(_nackByteCountTimes));
     memset(_nackByteCount, 0, sizeof(_nackByteCount));
@@ -173,6 +176,7 @@
         _ssrcDB.RegisterSSRC(remoteSSRC);
     }
     _sequenceNumber = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
+    _sequenceNumberRTX = rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER);
     _packetsSent = 0;
     _payloadBytesSent = 0;
     _packetOverHead = 28;
@@ -592,16 +596,14 @@
     return 0;
 }
 
-WebRtc_UWord16
-RTPSender::MaxDataPayloadLength() const
-{
-    if(_audioConfigured)
-    {
-        return _maxPayloadLength - RTPHeaderLength();
-    } else
-    {
-        return _maxPayloadLength - RTPHeaderLength() - _video->FECPacketOverhead(); // Include the FEC/ULP/RED overhead.
-    }
+WebRtc_UWord16 RTPSender::MaxDataPayloadLength() const {
+  if(_audioConfigured) {
+    return _maxPayloadLength - RTPHeaderLength();
+  } else {
+    return _maxPayloadLength - RTPHeaderLength() -
+        _video->FECPacketOverhead() - ((_RTX) ? 2 : 0);
+        // Include the FEC/ULP/RED overhead.
+  }
 }
 
 WebRtc_UWord16
@@ -616,6 +618,27 @@
     return _packetOverHead;
 }
 
+void RTPSender::SetRTXStatus(const bool enable,
+                             const bool setSSRC,
+                             const WebRtc_UWord32 SSRC) {
+  CriticalSectionScoped cs(_sendCritsect);
+  _RTX = enable;
+  if (enable) {
+    if (setSSRC) {
+     _ssrcRTX = SSRC;
+    } else {
+     _ssrcRTX = _ssrcDB.CreateSSRC();   // can't be 0
+    }
+  }
+}
+
+void RTPSender::RTXStatus(bool* enable,
+                          WebRtc_UWord32* SSRC) const {
+  CriticalSectionScoped cs(_sendCritsect);
+  *enable = _RTX;
+  *SSRC = _ssrcRTX;
+}
+
 WebRtc_Word32
 RTPSender::CheckPayloadType(const WebRtc_Word8 payloadType,
                             RtpVideoCodecTypes& videoType)
@@ -876,127 +899,159 @@
     return 0;
 }
 
-bool
-RTPSender::StorePackets() const
-{
-    return _storeSentPackets;
+bool RTPSender::StorePackets() const {
+  return _storeSentPackets;
 }
 
-WebRtc_Word32
-RTPSender::ReSendToNetwork(WebRtc_UWord16 packetID,
-                           WebRtc_UWord32 minResendTime)
-{
-#ifdef DEBUG_RTP_SEQUENCE_NUMBER
-    char str[256];
-    sprintf(str,"Re-Send sequenceNumber %d\n", packetID) ;
-    OutputDebugString(str);
-#endif
+WebRtc_Word32 RTPSender::ReSendPacket(WebRtc_UWord16 packetID,
+                                      WebRtc_UWord32 minResendTime) {
+  WebRtc_Word32 length = 0;
+  WebRtc_Word32 index = 0;
+  WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE];
+  {
+    CriticalSectionScoped lock(_prevSentPacketsCritsect);
 
-    WebRtc_Word32 i = -1;
-    WebRtc_Word32 length = 0;
-    WebRtc_Word32 index =0;
-    WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE];
-
-    {
-        CriticalSectionScoped lock(_prevSentPacketsCritsect);
-
-        WebRtc_UWord16 seqNum = 0;
-        if(_storeSentPackets)
-        {
-            if(_prevSentPacketsIndex)
-            {
-                seqNum = _prevSentPacketsSeqNum[_prevSentPacketsIndex-1];
-            }else
-            {
-                seqNum = _prevSentPacketsSeqNum[_storeSentPacketsNumber-1];
-            }
-            index = (_prevSentPacketsIndex-1) - (seqNum - packetID);
-            if (index >= 0 && index < _storeSentPacketsNumber)
-            {
-                seqNum = _prevSentPacketsSeqNum[index];
-            }
-            if(seqNum != packetID)
-            {
-                //we did not found a match, search all
-                for (WebRtc_Word32 m = 0; m < _storeSentPacketsNumber ;m++)
-                {
-                    if(_prevSentPacketsSeqNum[m] == packetID)
-                    {
-                        index = m;
-                        seqNum = _prevSentPacketsSeqNum[index];
-                        break;
-                    }
-                }
-            }
-            if(seqNum == packetID)
-            {
-                WebRtc_UWord32 timeNow= _clock.GetTimeInMS();
-                if(minResendTime>0 && (timeNow-_prevSentPacketsResendTime[index]<minResendTime))
-                {
-                    // No point in sending the packet again yet. Get out of here
-                    WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "Skipping to resend RTP packet %d because it was just resent", seqNum);
-                    return 0;
-                }
-
-                length = _prevSentPacketsLength[index];
-
-                if(length > _maxPayloadLength || _ptrPrevSentPackets[index] == 0)
-                {
-                    WEBRTC_TRACE(
-                        kTraceWarning, kTraceRtpRtcp, _id,
-                        "Failed to resend seqNum %u: length = %d index = %d",
-                        seqNum, length, index);
-                    return -1;
-                }
-            } else
-            {
-                WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
-                             "No match for resending seqNum %u and packetId %u",
-                             seqNum, packetID);
-                return -1;
-            }
-        }
-        if (length == 0)
-        {
-            // This is a valid case since packets which we decide not to
-            // retransmit are stored but with length zero.
-            return 0;
-        }
-
-        // copy to local buffer for callback
-        memcpy(dataBuffer, _ptrPrevSentPackets[index], length);
+    WebRtc_UWord16 seqNum = 0;
+    if (!_storeSentPackets) {
+      WEBRTC_TRACE(kTraceWarning,
+                   kTraceRtpRtcp,
+                   _id,
+                   "Ignoring request to ReSendPacket:%u we're not storing.",
+                   seqNum);
+      return -1;
     }
-    {
-        CriticalSectionScoped lock(_transportCritsect);
-        if(_transport)
-        {
-            i = _transport->SendPacket(_id, dataBuffer, length);
+    if (_prevSentPacketsIndex) {
+      seqNum = _prevSentPacketsSeqNum[_prevSentPacketsIndex-1];
+    } else {
+      seqNum = _prevSentPacketsSeqNum[_storeSentPacketsNumber-1];
+    }
+    index = (_prevSentPacketsIndex-1) - (seqNum - packetID);
+    if (index >= 0 && index < _storeSentPacketsNumber) {
+      seqNum = _prevSentPacketsSeqNum[index];
+    }
+    if (seqNum != packetID) {
+      // we did not found a match, search all
+      for (WebRtc_Word32 m = 0; m < _storeSentPacketsNumber; m++)  {
+        if(_prevSentPacketsSeqNum[m] == packetID) {
+          index = m;
+          seqNum = _prevSentPacketsSeqNum[index];
+          break;
         }
+      }
     }
-    if(i > 0)
-    {
-        CriticalSectionScoped cs(_sendCritsect);
-
-        Bitrate::Update(i);
-
-        _packetsSent++;
-
-        // we on purpose don't add to _payloadBytesSent since this is a re-transmit and not new payload data
+    if (seqNum != packetID) {
+      WEBRTC_TRACE(kTraceWarning,
+                   kTraceRtpRtcp,
+                   _id,
+                   "No match for resending seqNum %u and packetId %u",
+                   seqNum, packetID);
+      return -1;
     }
-    if(_storeSentPackets && i > 0)
-    {
-        CriticalSectionScoped lock(_prevSentPacketsCritsect);
-
-        if(_prevSentPacketsSeqNum[index] == packetID) // Make sure the  packet is still in the array
-        {
-            // Store the time when the frame was last resent.
-            _prevSentPacketsResendTime[index]= _clock.GetTimeInMS();
-        }
-        return i; //bytes sent over network
+    WebRtc_UWord32 timeNow = _clock.GetTimeInMS();
+    if (minResendTime > 0 &&
+        (timeNow-_prevSentPacketsResendTime[index] < minResendTime)) {
+      // No point in sending the packet again yet. Get out of here
+      WEBRTC_TRACE(kTraceStream,
+                   kTraceRtpRtcp,
+                   _id,
+                   "Skipping to resend RTP packet %d, it was just resent",
+                   seqNum);
+      return 0;
     }
-    WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
-                 "Transport failed to resend packetID %u", packetID);
-    return -1;
+    length = _prevSentPacketsLength[index];
+    if (length > _maxPayloadLength || _ptrPrevSentPackets[index] == 0) {
+      WEBRTC_TRACE(kTraceWarning,
+                   kTraceRtpRtcp,
+                   _id,
+                   "Failed to resend seqNum %u: length = %d index = %d",
+                   seqNum, length, index);
+      return -1;
+    }
+    if (length == 0) {
+      WEBRTC_TRACE(kTraceWarning,
+                   kTraceRtpRtcp,
+                   _id,
+                   "Resend packet length == 0 for seqNum %u",
+                   seqNum);
+      return -1;
+    }
+    if (_RTX) {
+      CriticalSectionScoped cs(_sendCritsect);
+      // Copy to local buffer for callback and add RTX header.
+      ModuleRTPUtility::RTPHeaderParser rtpParser(
+          reinterpret_cast<const WebRtc_UWord8*>(_ptrPrevSentPackets[index]),
+          length);
+
+      WebRtcRTPHeader rtp_header;
+      rtpParser.Parse(rtp_header);
+
+      // Add original RTP header.
+      memcpy(dataBuffer, _ptrPrevSentPackets[index],
+        rtp_header.header.headerLength);
+
+      // Replace sequence number.
+      WebRtc_UWord8* ptr = dataBuffer + 2;
+      ModuleRTPUtility::AssignUWord16ToBuffer(ptr, _sequenceNumberRTX++);
+
+      // Replace SSRC.
+      ptr += 6;
+      ModuleRTPUtility::AssignUWord32ToBuffer(ptr, _ssrcRTX);
+
+      // Add OSN (original sequence number).
+      ptr = dataBuffer + rtp_header.header.headerLength;
+      ModuleRTPUtility::AssignUWord16ToBuffer(
+          ptr, rtp_header.header.sequenceNumber);
+      ptr += 2;
+
+      // Add original payload data.
+      memcpy(ptr,
+             _ptrPrevSentPackets[index] + rtp_header.header.headerLength,
+             length - rtp_header.header.headerLength);
+      length += 2;
+    } else {
+      // copy to local buffer for callback
+      memcpy(dataBuffer, _ptrPrevSentPackets[index], length);
+    }
+  }  // End of scope lock(_prevSentPacketsCritsect).
+  WebRtc_Word32 i = ReSendToNetwork(dataBuffer, length);
+
+  if (_storeSentPackets && i > 0) {
+    CriticalSectionScoped lock(_prevSentPacketsCritsect);
+
+    // Make sure the  packet is still in the array
+    if(_prevSentPacketsSeqNum[index] == packetID) {
+      // Store the time when the frame was last resent.
+      _prevSentPacketsResendTime[index]= _clock.GetTimeInMS();
+    }
+    return i; //bytes sent over network
+  }
+  WEBRTC_TRACE(kTraceWarning,
+               kTraceRtpRtcp,
+               _id,
+               "Transport failed to resend packetID %u",
+               packetID);
+  return -1;
+}
+
+WebRtc_Word32 RTPSender::ReSendToNetwork(const WebRtc_UWord8* packet,
+                                         const WebRtc_UWord32 size) {
+  WebRtc_Word32 i = -1;
+  {
+    CriticalSectionScoped lock(_transportCritsect);
+    if(_transport) {
+      i = _transport->SendPacket(_id, packet, size);
+    }
+  }
+  if(i > 0) {
+    CriticalSectionScoped cs(_sendCritsect);
+
+    Bitrate::Update(i);
+
+    _packetsSent++;
+    // We on purpose don't add to _payloadBytesSent since this is a re-transmit
+    // and not new payload data
+  }
+  return i;
 }
 
 int RTPSender::SelectiveRetransmissions() const {
@@ -1012,124 +1067,111 @@
 void
 RTPSender::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
                           const WebRtc_UWord16* nackSequenceNumbers,
-                          const WebRtc_UWord16 avgRTT)
-{
+                          const WebRtc_UWord16 avgRTT) {
     const WebRtc_UWord32 now = _clock.GetTimeInMS();
     WebRtc_UWord32 bytesReSent = 0;
 
-     // Enough bandwith to send NACK?
-    if(ProcessNACKBitRate(now))
-    {
-        for (WebRtc_UWord16 i = 0; i < nackSequenceNumbersLength; ++i)
-        {
-            const WebRtc_Word32 bytesSent = ReSendToNetwork(nackSequenceNumbers[i],
-                                                          5+avgRTT);
-            if (bytesSent > 0)
-            {
-                bytesReSent += bytesSent;
+  // Enough bandwith to send NACK?
+  if (!ProcessNACKBitRate(now)) {
+    WEBRTC_TRACE(kTraceStream,
+                 kTraceRtpRtcp,
+                 _id,
+                 "NACK bitrate reached. Skipp sending NACK response. Target %d",
+                 TargetSendBitrateKbit());
+    return;
+  }
 
-            } else if(bytesSent==0)
-            {
-                continue; // The packet has previously been resent. Try resending next packet in the list.
-
-            } else if(bytesSent<0) // Failed to send one Sequence number. Give up the rest in this nack.
-            {
-                WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Failed resending RTP packet %d, Discard rest of NACK RTP packets", nackSequenceNumbers[i]);
-                break;
-            }
-            // delay bandwidth estimate (RTT * BW)
-            if(TargetSendBitrateKbit() != 0 && avgRTT)
-            {
-                if(bytesReSent > (WebRtc_UWord32)(TargetSendBitrateKbit() * avgRTT)>>3 ) // kbits/s * ms= bits/8 = bytes
-                {
-                    break; // ignore the rest of the packets in the list
-                }
-            }
-        }
-        if (bytesReSent > 0)
-        {
-            UpdateNACKBitRate(bytesReSent,now); // Update the nack bit rate
-            _nackBitrate.Update(bytesReSent);
-        }
-    }else
-    {
-        WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "NACK bitrate reached. Skipp sending NACK response. Target %d",TargetSendBitrateKbit());
+  for (WebRtc_UWord16 i = 0; i < nackSequenceNumbersLength; ++i) {
+    const WebRtc_Word32 bytesSent = ReSendPacket(nackSequenceNumbers[i],
+                                                 5+avgRTT);
+    if (bytesSent > 0) {
+      bytesReSent += bytesSent;
+    } else if (bytesSent == 0) {
+      // The packet has previously been resent.
+      // Try resending next packet in the list.
+      continue;
+    } else if (bytesSent < 0) {
+      // Failed to send one Sequence number. Give up the rest in this nack.
+      WEBRTC_TRACE(kTraceWarning,
+                   kTraceRtpRtcp,
+                   _id,
+                   "Failed resending RTP packet %d, Discard rest of packets",
+                   nackSequenceNumbers[i]);
+      break;
     }
+    // delay bandwidth estimate (RTT * BW)
+    if (TargetSendBitrateKbit() != 0 && avgRTT) {
+      // kbits/s * ms = bits => bits/8 = bytes
+      WebRtc_UWord32 targetBytes =
+          (static_cast<WebRtc_UWord32>(TargetSendBitrateKbit()) * avgRTT) >> 3;
+      if (bytesReSent > targetBytes) {
+        break; // ignore the rest of the packets in the list
+      }
+    }
+  }
+  if (bytesReSent > 0) {
+    // TODO(pwestin) consolidate these two methods.
+    UpdateNACKBitRate(bytesReSent, now);
+    _nackBitrate.Update(bytesReSent);
+  }
 }
 
 /**
 *    @return true if the nack bitrate is lower than the requested max bitrate
 */
-bool
-RTPSender::ProcessNACKBitRate(const WebRtc_UWord32 now)
-{
-    WebRtc_UWord32 num = 0;
-    WebRtc_Word32 byteCount = 0;
-    const WebRtc_UWord32 avgInterval=1000;
+bool RTPSender::ProcessNACKBitRate(const WebRtc_UWord32 now) {
+  WebRtc_UWord32 num = 0;
+  WebRtc_Word32 byteCount = 0;
+  const WebRtc_UWord32 avgInterval=1000;
 
-    CriticalSectionScoped cs(_sendCritsect);
+  CriticalSectionScoped cs(_sendCritsect);
 
-    if(_targetSendBitrate == 0)
-    {
-        return true;
+  if (_targetSendBitrate == 0) {
+    return true;
+  }
+  for (num = 0; num < NACK_BYTECOUNT_SIZE; num++) {
+    if ((now - _nackByteCountTimes[num]) > avgInterval) {
+      // don't use data older than 1sec
+      break;
+    } else {
+      byteCount += _nackByteCount[num];
     }
-
-    for(num = 0; num < NACK_BYTECOUNT_SIZE; num++)
-    {
-        if((now - _nackByteCountTimes[num]) > avgInterval)
-        {
-            // don't use data older than 1sec
-            break;
-        } else
-        {
-            byteCount += _nackByteCount[num];
-        }
+  }
+  WebRtc_Word32 timeInterval = avgInterval;
+  if (num == NACK_BYTECOUNT_SIZE) {
+    // More than NACK_BYTECOUNT_SIZE nack messages has been received
+    // during the last msgInterval
+    timeInterval = now - _nackByteCountTimes[num-1];
+    if(timeInterval < 0) {
+      timeInterval = avgInterval;
     }
-    WebRtc_Word32 timeInterval = avgInterval;
-    if (num == NACK_BYTECOUNT_SIZE)
-    {
-        // More than NACK_BYTECOUNT_SIZE nack messages has been received
-        // during the last msgInterval
-        timeInterval = now - _nackByteCountTimes[num-1];
-        if(timeInterval < 0)
-        {
-            timeInterval = avgInterval;
-        }
-    }
-    return (byteCount*8) < (_targetSendBitrate * timeInterval);
+  }
+  return (byteCount*8) < (_targetSendBitrate * timeInterval);
 }
 
-void
-RTPSender::UpdateNACKBitRate(const WebRtc_UWord32 bytes,
-                             const WebRtc_UWord32 now)
-{
-    CriticalSectionScoped cs(_sendCritsect);
+void RTPSender::UpdateNACKBitRate(const WebRtc_UWord32 bytes,
+                                  const WebRtc_UWord32 now) {
+  CriticalSectionScoped cs(_sendCritsect);
 
-    // save bitrate statistics
-    if(bytes > 0)
-    {
-        if(now == 0)
-        {
-            // add padding length
-            _nackByteCount[0] += bytes;
-        } else
-        {
-            if(_nackByteCountTimes[0] == 0)
-            {
-                // first no shift
-            } else
-            {
-                // shift
-                for(int i = (NACK_BYTECOUNT_SIZE-2); i >= 0 ; i--)
-                {
-                    _nackByteCount[i+1] = _nackByteCount[i];
-                    _nackByteCountTimes[i+1] = _nackByteCountTimes[i];
-                }
-            }
-            _nackByteCount[0] = bytes;
-            _nackByteCountTimes[0] = now;
+  // save bitrate statistics
+  if(bytes > 0) {
+    if(now == 0) {
+      // add padding length
+      _nackByteCount[0] += bytes;
+    } else {
+      if(_nackByteCountTimes[0] == 0) {
+        // first no shift
+      } else {
+        // shift
+        for(int i = (NACK_BYTECOUNT_SIZE-2); i >= 0 ; i--) {
+          _nackByteCount[i+1] = _nackByteCount[i];
+          _nackByteCountTimes[i+1] = _nackByteCountTimes[i];
         }
+      }
+      _nackByteCount[0] = bytes;
+      _nackByteCountTimes[0] = now;
     }
+  }
 }
 
 WebRtc_Word32
diff --git a/src/modules/rtp_rtcp/source/rtp_sender.h b/src/modules/rtp_rtcp/source/rtp_sender.h
index 76b0f52..bfb79b0 100644
--- a/src/modules/rtp_rtcp/source/rtp_sender.h
+++ b/src/modules/rtp_rtcp/source/rtp_sender.h
@@ -93,11 +93,12 @@
     // callback
     WebRtc_Word32 RegisterSendTransport(Transport* outgoingTransport);
 
-    WebRtc_Word32 RegisterPayload(const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
-                                const WebRtc_Word8 payloadType,
-                                const WebRtc_UWord32 frequency,
-                                 const WebRtc_UWord8 channels,
-                                const WebRtc_UWord32 rate);
+    WebRtc_Word32 RegisterPayload(
+        const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
+        const WebRtc_Word8 payloadType,
+        const WebRtc_UWord32 frequency,
+        const WebRtc_UWord8 channels,
+        const WebRtc_UWord32 rate);
 
     WebRtc_Word32 DeRegisterSendPayload(const WebRtc_Word8 payloadType);
 
@@ -119,7 +120,8 @@
     WebRtc_Word32 ResetDataCounters();
 
     WebRtc_UWord32 StartTimestamp() const;
-    WebRtc_Word32 SetStartTimestamp( const WebRtc_UWord32 timestamp, const bool force = false);
+    WebRtc_Word32 SetStartTimestamp(const WebRtc_UWord32 timestamp,
+                                    const bool force = false);
 
     WebRtc_UWord32 GenerateNewSSRC();
     WebRtc_Word32 SetSSRC( const WebRtc_UWord32 ssrc);
@@ -132,20 +134,19 @@
     WebRtc_Word32 SetCSRCStatus(const bool include);
 
     WebRtc_Word32 SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
-                         const WebRtc_UWord8 arrLength);
+                           const WebRtc_UWord8 arrLength);
 
     WebRtc_Word32 SetMaxPayloadLength(const WebRtc_UWord16 length,
-                                    const WebRtc_UWord16 packetOverHead);
+                                      const WebRtc_UWord16 packetOverHead);
 
-    WebRtc_Word32
-    SendOutgoingData(const FrameType frameType,
-                     const WebRtc_Word8 payloadType,
-                     const WebRtc_UWord32 timeStamp,
-                     const WebRtc_UWord8* payloadData,
-                     const WebRtc_UWord32 payloadSize,
-                     const RTPFragmentationHeader* fragmentation,
-                     VideoCodecInformation* codecInfo = NULL,
-                     const RTPVideoTypeHeader* rtpTypeHdr = NULL);
+    WebRtc_Word32 SendOutgoingData(const FrameType frameType,
+                                   const WebRtc_Word8 payloadType,
+                                   const WebRtc_UWord32 timeStamp,
+                                   const WebRtc_UWord8* payloadData,
+                                   const WebRtc_UWord32 payloadSize,
+                                   const RTPFragmentationHeader* fragmentation,
+                                   VideoCodecInformation* codecInfo = NULL,
+                                   const RTPVideoTypeHeader* rtpTypeHdr = NULL);
 
     WebRtc_Word32 SendPadData(WebRtc_Word8 payload_type,
                               WebRtc_UWord32 capture_timestamp,
@@ -177,18 +178,19 @@
                         const WebRtc_UWord16* nackSequenceNumbers,
                         const WebRtc_UWord16 avgRTT);
 
-    WebRtc_Word32 SetStorePacketsStatus(const bool enable, const WebRtc_UWord16 numberToStore);
+    WebRtc_Word32 SetStorePacketsStatus(const bool enable,
+                                        const WebRtc_UWord16 numberToStore);
 
     bool StorePackets() const;
 
-    WebRtc_Word32 ReSendToNetwork(WebRtc_UWord16 packetID,
-                                WebRtc_UWord32 minResendTime=0);
+    WebRtc_Word32 ReSendPacket(WebRtc_UWord16 packetID,
+                               WebRtc_UWord32 minResendTime=0);
+
+    WebRtc_Word32 ReSendToNetwork(const WebRtc_UWord8* packet,
+                                  const WebRtc_UWord32 size);
 
     bool ProcessNACKBitRate(const WebRtc_UWord32 now);
 
-    void UpdateNACKBitRate( const WebRtc_UWord32 bytes,
-                            const WebRtc_UWord32 now);
-
     /*
     *    Keep alive
     */
@@ -208,6 +210,15 @@
     WebRtc_Word32 SendRTPKeepalivePacket();
 
     /*
+    *  RTX
+    */
+    void SetRTXStatus(const bool enable,
+                      const bool setSSRC,
+                      const WebRtc_UWord32 SSRC);
+
+    void RTXStatus(bool* enable, WebRtc_UWord32* SSRC) const;
+
+    /*
     * Functions wrapping RTPSenderInterface
     */
     virtual WebRtc_Word32 BuildRTPheader(WebRtc_UWord8* dataBuffer,
@@ -237,9 +248,9 @@
     WebRtc_Word32 RegisterAudioCallback(RtpAudioFeedback* messagesCallback);
 
     // Send a DTMF tone using RFC 2833 (4733)
-      WebRtc_Word32 SendTelephoneEvent(const WebRtc_UWord8 key,
-                                   const WebRtc_UWord16 time_ms,
-                                   const WebRtc_UWord8 level);
+    WebRtc_Word32 SendTelephoneEvent(const WebRtc_UWord8 key,
+                                     const WebRtc_UWord16 time_ms,
+                                     const WebRtc_UWord8 level);
 
     bool SendTelephoneEventActive(WebRtc_Word8& telephoneEvent) const;
 
@@ -293,6 +304,9 @@
     WebRtc_Word32 CheckPayloadType(const WebRtc_Word8 payloadType, RtpVideoCodecTypes& videoType);
 
 private:
+    void UpdateNACKBitRate(const WebRtc_UWord32 bytes,
+                           const WebRtc_UWord32 now);
+
     void StorePacket(const uint8_t* buffer, uint16_t length,
                      uint16_t sequence_number);
 
@@ -326,6 +340,7 @@
     bool                      _storeSentPackets;
     WebRtc_UWord16            _storeSentPacketsNumber;
     CriticalSectionWrapper*    _prevSentPacketsCritsect;
+
     WebRtc_Word32             _prevSentPacketsIndex;
     WebRtc_Word8**            _ptrPrevSentPackets;
     WebRtc_UWord16*           _prevSentPacketsSeqNum;
@@ -348,12 +363,15 @@
     WebRtc_UWord32            _remoteSSRC;
     bool                      _sequenceNumberForced;
     WebRtc_UWord16            _sequenceNumber;
+    WebRtc_UWord16            _sequenceNumberRTX;
     bool                      _ssrcForced;
     WebRtc_UWord32            _ssrc;
     WebRtc_UWord32            _timeStamp;
     WebRtc_UWord8             _CSRCs;
     WebRtc_UWord32            _CSRC[kRtpCsrcSize];
     bool                      _includeCSRCs;
+    bool                      _RTX;
+    WebRtc_UWord32            _ssrcRTX;
 };
 } // namespace webrtc
 
diff --git a/src/modules/rtp_rtcp/test/testAPI/test_api.cc b/src/modules/rtp_rtcp/test/testAPI/test_api.cc
new file mode 100644
index 0000000..00b0157
--- /dev/null
+++ b/src/modules/rtp_rtcp/test/testAPI/test_api.cc
@@ -0,0 +1,114 @@
+/*
+ *  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 <algorithm>
+#include <vector>
+#include <gtest/gtest.h>
+
+#include "test_api.h"
+
+#include "common_types.h"
+#include "rtp_rtcp.h"
+#include "rtp_rtcp_defines.h"
+
+using namespace webrtc;
+
+class RtpRtcpAPITest : public ::testing::Test {
+ protected:
+  RtpRtcpAPITest() {
+    test_CSRC[0] = 1234;
+    test_CSRC[2] = 2345;
+    test_id = 123;
+    test_ssrc = 3456;
+    test_timestamp = 4567;
+    test_sequence_number = 2345;
+  }
+  ~RtpRtcpAPITest() {}
+
+  virtual void SetUp() {
+    module = RtpRtcp::CreateRtpRtcp(test_id, true, &fake_clock);
+    EXPECT_EQ(0, module->InitReceiver());
+    EXPECT_EQ(0, module->InitSender());
+  }
+
+  virtual void TearDown() {
+    RtpRtcp::DestroyRtpRtcp(module);
+  }
+
+  int test_id;
+  RtpRtcp* module;
+  WebRtc_UWord32 test_ssrc;
+  WebRtc_UWord32 test_timestamp;
+  WebRtc_UWord16 test_sequence_number;
+  WebRtc_UWord32 test_CSRC[webrtc::kRtpCsrcSize];
+  FakeRtpRtcpClock fake_clock;
+};
+
+TEST_F(RtpRtcpAPITest, Basic) {
+  EXPECT_EQ(0, module->SetSequenceNumber(test_sequence_number));
+  EXPECT_EQ(test_sequence_number, module->SequenceNumber());
+
+  EXPECT_EQ(0, module->SetStartTimestamp(test_timestamp));
+  EXPECT_EQ(test_timestamp, module->StartTimestamp());
+
+  EXPECT_EQ(false, module->Sending());
+  EXPECT_EQ(0, module->SetSendingStatus(true));
+  EXPECT_EQ(true, module->Sending());
+}
+
+TEST_F(RtpRtcpAPITest, MTU) {
+  EXPECT_EQ(-1, module->SetMaxTransferUnit(10));
+  EXPECT_EQ(-1, module->SetMaxTransferUnit(IP_PACKET_SIZE + 1));
+  EXPECT_EQ(0, module->SetMaxTransferUnit(1234));
+  EXPECT_EQ(1234-20-8, module->MaxPayloadLength());
+
+  EXPECT_EQ(0, module->SetTransportOverhead(true, true, 12));
+  EXPECT_EQ(1234 - 20- 20 -20 - 12, module->MaxPayloadLength());
+
+  EXPECT_EQ(0, module->SetTransportOverhead(false, false, 0));
+  EXPECT_EQ(1234 - 20 - 8, module->MaxPayloadLength());
+}
+
+TEST_F(RtpRtcpAPITest, SSRC) {
+  EXPECT_EQ(0, module->SetSSRC(test_ssrc));
+  EXPECT_EQ(test_ssrc, module->SSRC());
+}
+
+TEST_F(RtpRtcpAPITest, CSRC) {
+  EXPECT_EQ(0, module->SetCSRCs(test_CSRC, 2));
+  WebRtc_UWord32 testOfCSRC[webrtc::kRtpCsrcSize];
+  EXPECT_EQ(2, module->CSRCs(testOfCSRC));
+  EXPECT_EQ(test_CSRC[0], testOfCSRC[0]);
+  EXPECT_EQ(test_CSRC[1], testOfCSRC[1]);
+}
+
+TEST_F(RtpRtcpAPITest, RTCP) {
+  EXPECT_EQ(kRtcpOff, module->RTCP());
+  EXPECT_EQ(0, module->SetRTCPStatus(kRtcpCompound));
+  EXPECT_EQ(kRtcpCompound, module->RTCP());
+
+  EXPECT_EQ(0, module->SetCNAME("john.doe@test.test"));
+  EXPECT_EQ(-1, module->SetCNAME(NULL));
+
+  WebRtc_Word8 cName[RTCP_CNAME_SIZE];
+  EXPECT_EQ(0, module->CNAME(cName));
+  EXPECT_STRCASEEQ(cName, "john.doe@test.test");
+  EXPECT_EQ(-1, module->CNAME(NULL));
+
+  EXPECT_EQ(false, module->TMMBR());
+  EXPECT_EQ(0, module->SetTMMBRStatus(true));
+  EXPECT_EQ(true, module->TMMBR());
+  EXPECT_EQ(0, module->SetTMMBRStatus(false));
+  EXPECT_EQ(false, module->TMMBR());
+
+  EXPECT_EQ(kNackOff, module->NACK());
+  EXPECT_EQ(0, module->SetNACKStatus(kNackRtcp));
+  EXPECT_EQ(kNackRtcp, module->NACK());
+}
diff --git a/src/modules/rtp_rtcp/test/testAPI/test_api.gypi b/src/modules/rtp_rtcp/test/testAPI/test_api.gypi
new file mode 100644
index 0000000..d47e6d4
--- /dev/null
+++ b/src/modules/rtp_rtcp/test/testAPI/test_api.gypi
@@ -0,0 +1,42 @@
+# 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.
+
+{
+  'targets': [
+    {
+      'target_name': 'test_rtp_rtcp_api',
+      'type': 'executable',
+      'dependencies': [
+        'rtp_rtcp',
+        '<(webrtc_root)/../test/test.gyp:test_support_main',
+        '<(webrtc_root)/../testing/gtest.gyp:gtest',
+      ],
+      
+      'include_dirs': [
+        '../../interface',
+        '../../source',
+        '../../../../system_wrappers/interface',
+      ],
+   
+      'sources': [
+        'test_api.cc',
+        'test_api_audio.cc',
+        'test_api_nack.cc',
+        'test_api_rtcp.cc',
+        'test_api_video.cc',
+      ],
+      
+    },
+  ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/src/modules/rtp_rtcp/test/testAPI/test_api.h b/src/modules/rtp_rtcp/test/testAPI/test_api.h
new file mode 100644
index 0000000..495e9ac
--- /dev/null
+++ b/src/modules/rtp_rtcp/test/testAPI/test_api.h
@@ -0,0 +1,85 @@
+/*
+ *  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 "common_types.h"
+#include "rtp_rtcp.h"
+#include "rtp_rtcp_defines.h"
+
+using namespace webrtc;
+
+class FakeRtpRtcpClock : public RtpRtcpClock {
+ public:
+  FakeRtpRtcpClock() {
+    time_in_ms_ = 123456;
+  }
+  // Return a timestamp in milliseconds relative to some arbitrary
+  // source; the source is fixed for this clock.
+  virtual WebRtc_UWord32 GetTimeInMS() {
+    return time_in_ms_;
+  }
+  // Retrieve an NTP absolute timestamp.
+  virtual void CurrentNTP(WebRtc_UWord32& secs, WebRtc_UWord32& frac) {
+    secs = time_in_ms_ / 1000;
+    frac = (time_in_ms_ % 1000) * 4294967;
+  }
+  void IncrementTime(WebRtc_UWord32 time_increment_ms) {
+    time_in_ms_ += time_increment_ms;
+  }
+ private:
+  WebRtc_UWord32 time_in_ms_;
+};
+
+// This class sends all its packet straight to the provided RtpRtcp module.
+// with optional packet loss.
+class LoopBackTransport : public webrtc::Transport {
+ public:
+  LoopBackTransport(RtpRtcp* rtpRtcpModule)
+    : _count(0),
+      _packetLoss(0),
+      _rtpRtcpModule(rtpRtcpModule) {
+  }
+  void DropEveryNthPacket(int n) {
+    _packetLoss = n;
+  }
+  virtual int SendPacket(int channel, const void *data, int len) {
+    _count++;
+    if (_packetLoss > 0) {
+      if ((_count % _packetLoss) == 0) {
+        return len;
+      }
+    }
+    if (_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) {
+      return len;
+    }
+    return -1;
+  }
+  virtual int SendRTCPPacket(int channel, const void *data, int len) {
+    if (_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) {
+      return len;
+    }
+    return -1;
+  }
+ private:
+  int _count;
+  int _packetLoss;
+  RtpRtcp* _rtpRtcpModule;
+};
+
+class RtpReceiver : public RtpData {
+ public:
+   virtual WebRtc_Word32 OnReceivedPayloadData(
+       const WebRtc_UWord8* payloadData,
+       const WebRtc_UWord16 payloadSize,
+       const webrtc::WebRtcRTPHeader* rtpHeader) {
+    return 0;
+  }
+};
+
+
diff --git a/src/modules/rtp_rtcp/test/testAPI/test_api_audio.cc b/src/modules/rtp_rtcp/test/testAPI/test_api_audio.cc
new file mode 100644
index 0000000..39baeae
--- /dev/null
+++ b/src/modules/rtp_rtcp/test/testAPI/test_api_audio.cc
@@ -0,0 +1,446 @@
+/*
+ *  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 <algorithm>
+#include <vector>
+#include <gtest/gtest.h>
+
+#include "test_api.h"
+
+#include "common_types.h"
+#include "rtp_rtcp.h"
+#include "rtp_rtcp_defines.h"
+
+using namespace webrtc;
+
+#define test_rate 64000u
+
+class VerifyingAudioReceiver : public RtpData {
+ public:
+  VerifyingAudioReceiver(RtpRtcp* rtpRtcpModule) {}
+
+  virtual WebRtc_Word32 OnReceivedPayloadData(
+      const WebRtc_UWord8* payloadData,
+      const WebRtc_UWord16 payloadSize,
+      const webrtc::WebRtcRTPHeader* rtpHeader) {
+    if (rtpHeader->header.payloadType == 98 ||
+        rtpHeader->header.payloadType == 99) {
+      EXPECT_EQ(4, payloadSize);
+      char str[5];
+      memcpy(str, payloadData, payloadSize);
+      str[4] = 0;
+      // All our test vectors for payload type 96 and 97 even the stereo is on
+      // a per channel base equal to the 4 chars "test".
+      // Note there is no null termination so we add that to use the
+      // test EXPECT_STRCASEEQ.
+      EXPECT_STRCASEEQ("test", str);
+      return 0;
+    }
+    if (rtpHeader->header.payloadType == 100 ||
+        rtpHeader->header.payloadType == 101 ||
+        rtpHeader->header.payloadType == 102) {
+      if (rtpHeader->type.Audio.channel == 1) {
+        if (payloadData[0] == 0xff) {
+          // All our test vectors for payload type 100, 101 and 102 have the
+          // first channel data being equal to 0xff.
+          return 0;
+        }
+      } else if (rtpHeader->type.Audio.channel == 2) {
+        if (payloadData[0] == 0x0) {
+          // All our test vectors for payload type 100, 101 and 102 have the
+          // second channel data being equal to 0x00.
+          return 0;
+        }
+      } else if (rtpHeader->type.Audio.channel == 3) {
+        // All our test vectors for payload type 100, 101 and 102 have the
+        // third channel data being equal to 0xaa.
+        if (payloadData[0] == 0xaa) {
+          return 0;
+        }
+      }
+      EXPECT_EQ(false, true) << "This code path should never happen.";
+      return -1;
+    }
+    return 0;
+  }
+};
+
+class RTPCallback : public RtpFeedback {
+ public:
+  virtual WebRtc_Word32 OnInitializeDecoder(
+      const WebRtc_Word32 id,
+      const WebRtc_Word8 payloadType,
+      const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
+      const int frequency,
+      const WebRtc_UWord8 channels,
+      const WebRtc_UWord32 rate) {
+    if (payloadType == 96) {
+      EXPECT_EQ(test_rate, rate) <<
+          "The rate should be 64K for this payloadType";
+    }
+    return 0;
+  }
+  virtual void OnPacketTimeout(const WebRtc_Word32 id) {
+  }
+  virtual void OnReceivedPacket(const WebRtc_Word32 id,
+                                const RtpRtcpPacketType packetType) {
+  }
+  virtual void OnPeriodicDeadOrAlive(const WebRtc_Word32 id,
+                                     const RTPAliveType alive) {
+  }
+  virtual void OnIncomingSSRCChanged(const WebRtc_Word32 id,
+                                     const WebRtc_UWord32 SSRC) {
+  }
+  virtual void OnIncomingCSRCChanged(const WebRtc_Word32 id,
+                                     const WebRtc_UWord32 CSRC,
+                                     const bool added) {
+  }
+};
+
+class AudioFeedback : public RtpAudioFeedback {
+  virtual void OnReceivedTelephoneEvent(const WebRtc_Word32 id,
+                                        const WebRtc_UWord8 event,
+                                        const bool end) {
+    static WebRtc_UWord8 expectedEvent = 0;
+
+    if (end) {
+      WebRtc_UWord8 oldEvent = expectedEvent-1;
+      if (expectedEvent == 32) {
+        oldEvent = 15;
+      }
+      EXPECT_EQ(oldEvent, event);
+    } else {
+      EXPECT_EQ(expectedEvent, event);
+      expectedEvent++;
+    }
+    if (expectedEvent == 16) {
+      expectedEvent = 32;
+    }
+  }
+  virtual void OnPlayTelephoneEvent(const WebRtc_Word32 id,
+                                    const WebRtc_UWord8 event,
+                                    const WebRtc_UWord16 lengthMs,
+                                    const WebRtc_UWord8 volume) {
+  };
+};
+
+class RtpRtcpAudioTest : public ::testing::Test {
+ protected:
+  RtpRtcpAudioTest() {
+    test_CSRC[0] = 1234;
+    test_CSRC[2] = 2345;
+    test_id = 123;
+    test_ssrc = 3456;
+    test_timestamp = 4567;
+    test_sequence_number = 2345;
+  }
+  ~RtpRtcpAudioTest() {}
+
+  virtual void SetUp() {
+    module1 = RtpRtcp::CreateRtpRtcp(test_id, true, &fake_clock);
+    module2 = RtpRtcp::CreateRtpRtcp(test_id+1, true, &fake_clock);
+
+    EXPECT_EQ(0, module1->InitReceiver());
+    EXPECT_EQ(0, module1->InitSender());
+    EXPECT_EQ(0, module2->InitReceiver());
+    EXPECT_EQ(0, module2->InitSender());
+    data_receiver1 = new VerifyingAudioReceiver(module1);
+    EXPECT_EQ(0, module1->RegisterIncomingDataCallback(data_receiver1));
+    data_receiver2 = new VerifyingAudioReceiver(module2);
+    EXPECT_EQ(0, module2->RegisterIncomingDataCallback(data_receiver2));
+    transport1 = new LoopBackTransport(module2);
+    EXPECT_EQ(0, module1->RegisterSendTransport(transport1));
+    transport2 = new LoopBackTransport(module1);
+    EXPECT_EQ(0, module2->RegisterSendTransport(transport2));
+    rtp_callback = new RTPCallback();
+    EXPECT_EQ(0, module2->RegisterIncomingRTPCallback(rtp_callback));
+  }
+
+  virtual void TearDown() {
+    RtpRtcp::DestroyRtpRtcp(module1);
+    RtpRtcp::DestroyRtpRtcp(module2);
+    delete transport1;
+    delete transport2;
+    delete data_receiver1;
+    delete data_receiver2;
+    delete rtp_callback;
+  }
+
+  int test_id;
+  RtpRtcp* module1;
+  RtpRtcp* module2;
+  VerifyingAudioReceiver* data_receiver1;
+  VerifyingAudioReceiver* data_receiver2;
+  LoopBackTransport* transport1;
+  LoopBackTransport* transport2;
+  RTPCallback* rtp_callback;
+  WebRtc_UWord32 test_ssrc;
+  WebRtc_UWord32 test_timestamp;
+  WebRtc_UWord16 test_sequence_number;
+  WebRtc_UWord32 test_CSRC[webrtc::kRtpCsrcSize];
+  FakeRtpRtcpClock fake_clock;
+};
+
+TEST_F(RtpRtcpAudioTest, Basic) {
+  EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
+  EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
+
+  EXPECT_EQ(false, module1->TelephoneEvent());
+
+  // Test detection at the end of a DTMF tone.
+  EXPECT_EQ(0, module2->SetTelephoneEventStatus(true, true, true));
+  EXPECT_EQ(true, module2->TelephoneEvent());
+
+  EXPECT_EQ(0, module1->SetSendingStatus(true));
+
+  // Start basic RTP test.
+
+  // Send an empty RTP packet.
+  // Should fail since we have not registerd the payload type.
+  EXPECT_EQ(-1, module1->SendOutgoingData(webrtc::kAudioFrameSpeech,
+                                          96, 0, NULL, 0));
+
+  CodecInst voiceCodec;
+  voiceCodec.pltype = 96;
+  voiceCodec.plfreq = 8000;
+  memcpy(voiceCodec.plname, "PCMU", 5);
+
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
+  voiceCodec.rate = test_rate;
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+  printf("4\n");
+
+  const WebRtc_UWord8 test[5] = "test";
+  EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96,
+                                         0, test, 4));
+
+  EXPECT_EQ(test_ssrc, module2->RemoteSSRC());
+  EXPECT_EQ(test_timestamp, module2->RemoteTimestamp());
+}
+
+TEST_F(RtpRtcpAudioTest, RED) {
+  CodecInst voiceCodec;
+  voiceCodec.pltype = 96;
+  voiceCodec.plfreq = 8000;
+  memcpy(voiceCodec.plname, "PCMU", 5);
+
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
+  voiceCodec.rate = test_rate;
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
+  EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
+  EXPECT_EQ(0, module1->SetSendingStatus(true));
+
+  voiceCodec.pltype = 127;
+  voiceCodec.plfreq = 8000;
+  memcpy(voiceCodec.plname, "RED", 4);
+
+  EXPECT_EQ(0, module1->SetSendREDPayloadType(voiceCodec.pltype));
+  WebRtc_Word8 red = 0;
+  EXPECT_EQ(0, module1->SendREDPayloadType(red));
+  EXPECT_EQ(voiceCodec.pltype, red);
+  EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  RTPFragmentationHeader fragmentation;
+  fragmentation.fragmentationVectorSize = 2;
+  fragmentation.fragmentationLength = new WebRtc_UWord32[2];
+  fragmentation.fragmentationLength[0] = 4;
+  fragmentation.fragmentationLength[1] = 4;
+  fragmentation.fragmentationOffset = new WebRtc_UWord32[2];
+  fragmentation.fragmentationOffset[0] = 0;
+  fragmentation.fragmentationOffset[1] = 4;
+  fragmentation.fragmentationTimeDiff = new WebRtc_UWord16[2];
+  fragmentation.fragmentationTimeDiff[0] = 0;
+  fragmentation.fragmentationTimeDiff[1] = 0;
+  fragmentation.fragmentationPlType = new WebRtc_UWord8[2];
+  fragmentation.fragmentationPlType[0] = 96;
+  fragmentation.fragmentationPlType[1] = 96;
+
+  const WebRtc_UWord8 test[5] = "test";
+  // Send a RTP packet.
+  EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech,
+                                         96, 160, test, 4,
+                                         &fragmentation));
+
+  EXPECT_EQ(0, module1->SetSendREDPayloadType(-1));
+  EXPECT_EQ(-1, module1->SendREDPayloadType(red));
+}
+
+TEST_F(RtpRtcpAudioTest, DTMF) {
+  CodecInst voiceCodec;
+  voiceCodec.pltype = 96;
+  voiceCodec.plfreq = 8000;
+  memcpy(voiceCodec.plname, "PCMU", 5);
+
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
+  voiceCodec.rate = test_rate;
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
+  EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
+  EXPECT_EQ(0, module1->SetSendingStatus(true));
+
+  AudioFeedback* audioFeedback = new AudioFeedback();
+  EXPECT_EQ(0, module2->RegisterAudioCallback(audioFeedback));
+
+  // Prepare for DTMF.
+  voiceCodec.pltype = 97;
+  voiceCodec.plfreq = 8000;
+  memcpy(voiceCodec.plname, "telephone-event", 16);
+
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  // Start DTMF test.
+  WebRtc_UWord32 timeStamp = 160;
+
+  // Send a DTMF tone using RFC 2833 (4733).
+  for (int i = 0; i < 16; i++) {
+    EXPECT_EQ(0, module1->SendTelephoneEventOutband(i, timeStamp, 10));
+  }
+  timeStamp += 160;  // Prepare for next packet.
+
+  const WebRtc_UWord8 test[9] = "test";
+
+  // Send RTP packets for 16 tones a 160 ms  100ms
+  // pause between = 2560ms + 1600ms = 4160ms
+  for (;timeStamp <= 250 * 160; timeStamp += 160) {
+    EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96,
+                                           timeStamp, test, 4));
+    fake_clock.IncrementTime(20);
+    module1->Process();
+  }
+  EXPECT_EQ(0, module1->SendTelephoneEventOutband(32, 9000, 10));
+
+  for (;timeStamp <= 740 * 160; timeStamp += 160) {
+    EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96,
+                                           timeStamp, test, 4));
+    fake_clock.IncrementTime(20);
+    module1->Process();
+  }
+  delete audioFeedback;
+}
+
+TEST_F(RtpRtcpAudioTest, Stereo) {
+  CodecInst voiceCodec;
+  voiceCodec.pltype = 96;
+  voiceCodec.plfreq = 8000;
+  memcpy(voiceCodec.plname, "PCMU", 5);
+
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
+  voiceCodec.rate = test_rate;
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
+  EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
+  EXPECT_EQ(0, module1->SetSendingStatus(true));
+
+  // Prepare for 3 channel audio 8 bits per sample.
+  voiceCodec.pltype = 98;
+  voiceCodec.channels = 3;
+  memcpy(voiceCodec.plname, "PCMA", 5);
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  // Prepare for 3 channel audio 16 bits per sample.
+  voiceCodec.pltype = 99;
+  memcpy(voiceCodec.plname, "L16", 4);
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  // Prepare for 3 channel audio 5 bits per sample.
+  voiceCodec.pltype = 100;
+  memcpy(voiceCodec.plname, "G726-40",8);
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  // Prepare for 3 channel audio 3 bits per sample.
+  voiceCodec.pltype = 101;
+  memcpy(voiceCodec.plname, "G726-24",8);
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  // Prepare for 3 channel audio 2 bits per sample.
+  voiceCodec.pltype = 102;
+  memcpy(voiceCodec.plname, "G726-16",8);
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  // Test sample based multi channel codec, 3 channels 8 bits.
+  WebRtc_UWord8 test3channels[13] = "ttteeesssttt";
+  WebRtc_UWord32 timeStamp = 160;
+  EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 98,
+                                         timeStamp, test3channels, 12));
+  fake_clock.IncrementTime(20);
+  module1->Process();
+  timeStamp += 160;  // Prepare for next packet.
+
+  // Test sample based multi channel codec, 3 channels 16 bits.
+  const WebRtc_UWord8 test3channels16[13] = "teteteststst";
+  EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 99,
+                                         timeStamp, test3channels16, 12));
+  fake_clock.IncrementTime(20);
+  module1->Process();
+  timeStamp += 160;  // Prepare for next packet.
+
+  // Test sample based multi channel codec, 3 channels 5 bits.
+  test3channels[0] = 0xf8;  // 5 ones 3 zeros.
+  test3channels[1] = 0x2b;  // 2 zeros 5 10 1 one.
+  test3channels[2] = 0xf0;  // 4 ones 4 zeros.
+  test3channels[3] = 0x2b;  // 1 zero 5 01 2 ones.
+  test3channels[4] = 0xe0;  // 3 ones 5 zeros.
+  test3channels[5] = 0x0;
+  test3channels[6] = 0x0;
+  test3channels[7] = 0x0;
+  test3channels[8] = 0x0;
+  test3channels[9] = 0x0;
+  test3channels[10] = 0x0;
+  test3channels[11] = 0x0;
+  test3channels[12] = 0x0;
+  test3channels[13] = 0x0;
+  test3channels[14] = 0x0;
+
+  EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 100,
+                                         timeStamp, test3channels, 15));
+  fake_clock.IncrementTime(20);
+  module1->Process();
+  timeStamp += 160;  // Prepare for next packet.
+
+  // Test sample based multi channel codec, 3 channels 3 bits.
+  test3channels[0] = 0xe2;  // 3 ones    3 zeros     2 10
+  test3channels[1] = 0xf0;  // 1 1       3 ones      3 zeros     1 0
+  test3channels[2] = 0xb8;  // 2 10      3 ones      3 zeros
+  test3channels[3] = 0xa0;  // 3 101     5 zeros
+  test3channels[4] = 0x0;
+  EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 101,
+                                         timeStamp, test3channels, 15));
+  fake_clock.IncrementTime(20);
+  module1->Process();
+  timeStamp += 160;  // Prepare for next packet.
+
+  // Test sample based multi channel codec, 3 channels 2 bits.
+  test3channels[0] = 0xcb;  // 2 ones    2 zeros     2 10        2 ones
+  test3channels[1] = 0x2c;  // 2 zeros   2 10        2 ones      2 zeros
+  test3channels[2] = 0xb2;  // 2 10      2 ones      2 zeros     2 10
+  test3channels[3] = 0xcb;  // 2 ones    2 zeros     2 10        2 ones
+  test3channels[4] = 0x2c;  // 2 zeros   2 10        2 ones      2 zeros
+  EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 102,
+                                         timeStamp, test3channels, 15));
+}
diff --git a/src/modules/rtp_rtcp/test/testAPI/test_api_nack.cc b/src/modules/rtp_rtcp/test/testAPI/test_api_nack.cc
new file mode 100644
index 0000000..fd3c3df
--- /dev/null
+++ b/src/modules/rtp_rtcp/test/testAPI/test_api_nack.cc
@@ -0,0 +1,249 @@
+/*
+ *  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 <algorithm>
+#include <vector>
+#include <gtest/gtest.h>
+
+#include "test_api.h"
+
+#include "common_types.h"
+#include "rtp_rtcp.h"
+#include "rtp_rtcp_defines.h"
+
+using namespace webrtc;
+ 
+const int kVideoNackListSize = 10;
+const int kTestId = 123;
+const WebRtc_UWord32 kTestSsrc = 3456;
+const WebRtc_UWord16 kTestSequenceNumber = 2345;
+const WebRtc_UWord32 kTestNumberOfPackets = 450;
+const int kTestNumberOfRtxPackets = 49;
+
+class VerifyingNackReceiver : public RtpData
+{
+ public:
+  VerifyingNackReceiver() {}
+
+  virtual WebRtc_Word32 OnReceivedPayloadData(
+      const WebRtc_UWord8* data,
+      const WebRtc_UWord16 size,
+      const webrtc::WebRtcRTPHeader* rtp_header) {
+    
+    EXPECT_EQ(kTestSsrc, rtp_header->header.ssrc);
+    EXPECT_EQ(find(sequence_numbers_.begin(),
+                    sequence_numbers_.end(),
+                    rtp_header->header.sequenceNumber),
+              sequence_numbers_.end());
+    sequence_numbers_.push_back(rtp_header->header.sequenceNumber);
+    return 0;
+  }
+  std::vector<WebRtc_UWord16 > sequence_numbers_;
+};
+
+class NackLoopBackTransport : public webrtc::Transport {
+ public:
+  NackLoopBackTransport(RtpRtcp* rtp_rtcp_module, uint32_t rtx_ssrc)
+    : count_(0),
+      packet_loss_(0),
+      rtx_ssrc_(rtx_ssrc),
+      count_rtx_ssrc_(0),
+      module_(rtp_rtcp_module) {
+  }
+  void DropEveryNthPacket(int n) {
+    packet_loss_ = n;
+  }
+  virtual int SendPacket(int channel, const void *data, int len) {
+    count_++;
+    const unsigned char* ptr = static_cast<const unsigned  char*>(data);
+    uint32_t ssrc = (ptr[8] << 24) + (ptr[9] << 16) + (ptr[10] << 8) + ptr[11];
+    if (ssrc == rtx_ssrc_) count_rtx_ssrc_++;
+
+    if (packet_loss_ > 0) {
+      if ((count_ % packet_loss_) == 0) {
+        return len;
+      }
+    }
+    if (module_->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) {
+      return len;
+    }
+    return -1;
+  }
+  virtual int SendRTCPPacket(int channel, const void *data, int len) {
+    if (module_->IncomingPacket((const WebRtc_UWord8*)data, len) == 0) {
+      return len;
+    }
+    return -1;
+  }
+  int count_;
+  int packet_loss_;
+  uint32_t rtx_ssrc_;
+  int count_rtx_ssrc_;
+  RtpRtcp* module_;
+};
+
+class RtpRtcpNackTest : public ::testing::Test {
+ protected:
+  RtpRtcpNackTest() {}
+  ~RtpRtcpNackTest() {}
+
+  virtual void SetUp() {
+    video_module_ = RtpRtcp::CreateRtpRtcp(kTestId, false, &fake_clock);
+    EXPECT_EQ(0, video_module_->InitReceiver());
+    EXPECT_EQ(0, video_module_->InitSender());
+    EXPECT_EQ(0, video_module_->SetRTCPStatus(kRtcpCompound));
+    EXPECT_EQ(0, video_module_->SetSSRC(kTestSsrc));
+    EXPECT_EQ(0, video_module_->SetNACKStatus(kNackRtcp));
+    EXPECT_EQ(0, video_module_->SetStorePacketsStatus(true));
+    EXPECT_EQ(0, video_module_->SetSendingStatus(true));
+    EXPECT_EQ(0, video_module_->SetSequenceNumber(kTestSequenceNumber));
+    EXPECT_EQ(0, video_module_->SetStartTimestamp(111111));
+
+    transport_ = new NackLoopBackTransport(video_module_, kTestSsrc + 1);
+    EXPECT_EQ(0, video_module_->RegisterSendTransport(transport_));
+
+    nack_receiver_ = new VerifyingNackReceiver();
+    EXPECT_EQ(0, video_module_->RegisterIncomingDataCallback(nack_receiver_));
+
+    VideoCodec video_codec;
+    memset(&video_codec, 0, sizeof(video_codec));
+    video_codec.plType = 123;
+    memcpy(video_codec.plName, "I420", 5);
+
+    EXPECT_EQ(0, video_module_->RegisterSendPayload(video_codec));
+    EXPECT_EQ(0, video_module_->RegisterReceivePayload(video_codec));
+
+    payload_data_length = sizeof(payload_data);
+
+    for (int n = 0; n < payload_data_length; n++) {
+      payload_data[n] = n % 10;
+    }
+  }
+
+  virtual void TearDown() {
+    RtpRtcp::DestroyRtpRtcp(video_module_);
+    delete transport_;
+    delete nack_receiver_;
+  }
+
+  RtpRtcp* video_module_;
+  NackLoopBackTransport* transport_;
+  VerifyingNackReceiver* nack_receiver_;
+  WebRtc_UWord8  payload_data[65000];
+  int payload_data_length;
+  FakeRtpRtcpClock fake_clock;
+};
+
+TEST_F(RtpRtcpNackTest, RTCP) {
+  WebRtc_UWord32 timestamp = 3000;
+  WebRtc_UWord16 nack_list[kVideoNackListSize];
+  transport_->DropEveryNthPacket(10);
+
+  for (int frame = 0; frame < 10; ++frame) {
+    EXPECT_EQ(0, video_module_->SendOutgoingData(webrtc::kVideoFrameDelta, 123,
+                                                timestamp,
+                                                payload_data,
+                                                payload_data_length));
+
+    std::sort(nack_receiver_->sequence_numbers_.begin(),
+              nack_receiver_->sequence_numbers_.end());
+
+    std::vector<WebRtc_UWord16> missing_sequence_numbers;
+    std::vector<WebRtc_UWord16>::iterator it =
+        nack_receiver_->sequence_numbers_.begin();
+
+    while (it != nack_receiver_->sequence_numbers_.end()) {
+      WebRtc_UWord16 sequence_number_1 = *it;
+      ++it;
+      if (it != nack_receiver_->sequence_numbers_.end()) {
+        WebRtc_UWord16 sequence_number_2 = *it;
+        // Add all missing sequence numbers to list
+        for (WebRtc_UWord16 i = sequence_number_1 + 1; i < sequence_number_2;
+            ++i) {
+          missing_sequence_numbers.push_back(i);
+        }
+      }
+    }
+    int n = 0;
+    for (it = missing_sequence_numbers.begin();
+        it != missing_sequence_numbers.end(); ++it) {
+      nack_list[n++] = (*it);
+    }
+    video_module_->SendNACK(nack_list, n);
+    fake_clock.IncrementTime(33);
+    video_module_->Process();
+
+    // Prepare next frame.
+    timestamp += 3000;
+  }
+  std::sort(nack_receiver_->sequence_numbers_.begin(),
+            nack_receiver_->sequence_numbers_.end());
+  EXPECT_EQ(kTestSequenceNumber, *(nack_receiver_->sequence_numbers_.begin()));
+  EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
+            *(nack_receiver_->sequence_numbers_.rbegin()));
+  EXPECT_EQ(kTestNumberOfPackets, nack_receiver_->sequence_numbers_.size());
+  EXPECT_EQ(0, transport_->count_rtx_ssrc_);
+}
+
+TEST_F(RtpRtcpNackTest, RTX) {
+  EXPECT_EQ(0, video_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
+  EXPECT_EQ(0, video_module_->SetRTXSendStatus(true, true, kTestSsrc + 1));
+
+  transport_->DropEveryNthPacket(10);
+
+  WebRtc_UWord32 timestamp = 3000;
+  WebRtc_UWord16 nack_list[kVideoNackListSize];
+
+  for (int frame = 0; frame < 10; ++frame) {
+    EXPECT_EQ(0, video_module_->SendOutgoingData(webrtc::kVideoFrameDelta, 123,
+                                               timestamp,
+                                               payload_data,
+                                               payload_data_length));
+
+    std::sort(nack_receiver_->sequence_numbers_.begin(),
+              nack_receiver_->sequence_numbers_.end());
+
+    std::vector<WebRtc_UWord16> missing_sequence_numbers;
+
+
+    std::vector<WebRtc_UWord16>::iterator it =
+        nack_receiver_->sequence_numbers_.begin();
+    while (it != nack_receiver_->sequence_numbers_.end()) {
+      int sequence_number_1 = *it;
+      ++it;
+      if (it != nack_receiver_->sequence_numbers_.end()) {
+        int sequence_number_2 = *it;
+        // Add all missing sequence numbers to list.
+        for (int i = sequence_number_1 + 1; i < sequence_number_2; ++i) {
+          missing_sequence_numbers.push_back(i);
+        }
+      }
+    }
+    int n = 0;
+    for (it = missing_sequence_numbers.begin();
+        it != missing_sequence_numbers.end(); ++it) {
+      nack_list[n++] = (*it);
+    }
+    video_module_->SendNACK(nack_list, n);
+    fake_clock.IncrementTime(33);
+    video_module_->Process();
+
+    // Prepare next frame.
+    timestamp += 3000;
+  }
+  std::sort(nack_receiver_->sequence_numbers_.begin(),
+            nack_receiver_->sequence_numbers_.end());
+  EXPECT_EQ(kTestSequenceNumber, *(nack_receiver_->sequence_numbers_.begin()));
+  EXPECT_EQ(kTestSequenceNumber + kTestNumberOfPackets - 1,
+            *(nack_receiver_->sequence_numbers_.rbegin()));
+  EXPECT_EQ(kTestNumberOfPackets, nack_receiver_->sequence_numbers_.size());
+  EXPECT_EQ(kTestNumberOfRtxPackets, transport_->count_rtx_ssrc_);
+}
+
diff --git a/src/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc b/src/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc
new file mode 100644
index 0000000..9766b45
--- /dev/null
+++ b/src/modules/rtp_rtcp/test/testAPI/test_api_rtcp.cc
@@ -0,0 +1,297 @@
+/*
+ *  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 <algorithm>
+#include <vector>
+#include <gtest/gtest.h>
+
+#include "test_api.h"
+
+#include "common_types.h"
+#include "rtp_rtcp.h"
+#include "rtp_rtcp_defines.h"
+
+using namespace webrtc;
+ 
+const WebRtc_UWord64 kTestPictureId = 12345678;
+
+class RtcpCallback : public RtcpFeedback {
+ public:
+  RtcpCallback(RtpRtcp* module) {
+    _rtpRtcpModule = module;
+  };
+  virtual void OnRTCPPacketTimeout(const WebRtc_Word32 id) {
+  }
+  virtual void OnLipSyncUpdate(const WebRtc_Word32 id,
+                               const WebRtc_Word32 audioVideoOffset) {
+  };
+  virtual void OnTMMBRReceived(const WebRtc_Word32 id,
+                               const WebRtc_UWord16 bwEstimateKbit) {
+  };
+  virtual void OnXRVoIPMetricReceived(
+      const WebRtc_Word32 id,
+      const RTCPVoIPMetric* metric,
+      const WebRtc_Word8 VoIPmetricBuffer[28]) {
+  };
+  virtual void OnSLIReceived(const WebRtc_Word32 id,
+                             const WebRtc_UWord8 pictureId) {
+    EXPECT_EQ(28, pictureId);
+  };
+
+  virtual void OnRPSIReceived(const WebRtc_Word32 id,
+                              const WebRtc_UWord64 pictureId) {
+    EXPECT_EQ(kTestPictureId, pictureId);
+  };
+  virtual void OnApplicationDataReceived(const WebRtc_Word32 id,
+                                         const WebRtc_UWord8 subType,
+                                         const WebRtc_UWord32 name,
+                                         const WebRtc_UWord16 length,
+                                         const WebRtc_UWord8* data) {
+    char print_name[5];
+    print_name[0] = static_cast<char>(name >> 24);
+    print_name[1] = static_cast<char>(name >> 16);
+    print_name[2] = static_cast<char>(name >> 8);
+    print_name[3] = static_cast<char>(name);
+    print_name[4] = 0;
+
+    EXPECT_STRCASEEQ("test", print_name);
+  };
+
+  virtual void OnSendReportReceived(const WebRtc_Word32 id,
+                                    const WebRtc_UWord32 senderSSRC) {
+    RTCPSenderInfo senderInfo;
+    EXPECT_EQ(0, _rtpRtcpModule->RemoteRTCPStat(&senderInfo));
+  };
+
+  virtual void OnReceiveReportReceived(const WebRtc_Word32 id,
+                                       const WebRtc_UWord32 senderSSRC) {
+  };
+ private:
+  RtpRtcp* _rtpRtcpModule;
+};
+
+class RtpRtcpRtcpTest : public ::testing::Test {
+ protected:
+  RtpRtcpRtcpTest() {
+    test_CSRC[0] = 1234;
+    test_CSRC[2] = 2345;
+    test_id = 123;
+    test_ssrc = 3456;
+    test_timestamp = 4567;
+    test_sequence_number = 2345;
+  }
+  ~RtpRtcpRtcpTest() {}
+
+  virtual void SetUp() {
+    module1 = RtpRtcp::CreateRtpRtcp(test_id, true, &fake_clock);
+    module2 = RtpRtcp::CreateRtpRtcp(test_id+1, true, &fake_clock);
+
+    EXPECT_EQ(0, module1->InitReceiver());
+    EXPECT_EQ(0, module1->InitSender());
+    EXPECT_EQ(0, module2->InitReceiver());
+    EXPECT_EQ(0, module2->InitSender());
+    receiver = new RtpReceiver();
+    EXPECT_EQ(0, module2->RegisterIncomingDataCallback(receiver));
+    transport1 = new LoopBackTransport(module2);
+    EXPECT_EQ(0, module1->RegisterSendTransport(transport1));
+    transport2 = new LoopBackTransport(module1);
+    EXPECT_EQ(0, module2->RegisterSendTransport(transport2));
+  }
+
+  virtual void TearDown() {
+    RtpRtcp::DestroyRtpRtcp(module1);
+    RtpRtcp::DestroyRtpRtcp(module2);
+    delete transport1;
+    delete transport2;
+    delete receiver;
+  }
+
+  int test_id;
+  RtpRtcp* module1;
+  RtpRtcp* module2;
+  RtpReceiver* receiver;
+  LoopBackTransport* transport1;
+  LoopBackTransport* transport2;
+  WebRtc_UWord32 test_ssrc;
+  WebRtc_UWord32 test_timestamp;
+  WebRtc_UWord16 test_sequence_number;
+  WebRtc_UWord32 test_CSRC[webrtc::kRtpCsrcSize];
+  FakeRtpRtcpClock fake_clock;
+};
+
+TEST_F(RtpRtcpRtcpTest, RTCP) {
+  RtcpCallback* myRTCPFeedback1 = new RtcpCallback(module1);
+  RtcpCallback* myRTCPFeedback2 = new RtcpCallback(module2);
+  EXPECT_EQ(0, module1->RegisterIncomingRTCPCallback(myRTCPFeedback1));
+  EXPECT_EQ(0, module2->RegisterIncomingRTCPCallback(myRTCPFeedback2));
+
+  EXPECT_EQ(0, module1->SetRTCPStatus(kRtcpCompound));
+  EXPECT_EQ(0, module2->SetRTCPStatus(kRtcpCompound));
+
+  EXPECT_EQ(0, module2->SetSSRC(test_ssrc + 1));
+  EXPECT_EQ(0, module1->SetSSRC(test_ssrc));
+  EXPECT_EQ(0, module1->SetSequenceNumber(test_sequence_number));
+  EXPECT_EQ(0, module1->SetStartTimestamp(test_timestamp));
+  EXPECT_EQ(0, module1->SetCSRCs(test_CSRC, 2));
+  EXPECT_EQ(0, module1->SetCNAME("john.doe@test.test"));
+
+  EXPECT_EQ(0, module1->SetSendingStatus(true));
+
+  CodecInst voiceCodec;
+  voiceCodec.pltype = 96;
+  voiceCodec.plfreq = 8000;
+  voiceCodec.rate = 64000;
+  memcpy(voiceCodec.plname, "PCMU", 5);
+
+  EXPECT_EQ(0, module1->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module1->RegisterReceivePayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterSendPayload(voiceCodec));
+  EXPECT_EQ(0, module2->RegisterReceivePayload(voiceCodec));
+
+  // We need to send one RTP packet to get the RTCP packet to be accepted by
+  // the receiving module.
+  // send RTP packet with the data "testtest"
+  const WebRtc_UWord8 test[9] = "testtest";
+  EXPECT_EQ(0, module1->SendOutgoingData(webrtc::kAudioFrameSpeech, 96,
+                                         0, test, 8));
+
+  EXPECT_EQ(0, module1->SendRTCPReferencePictureSelection(kTestPictureId));
+  EXPECT_EQ(0, module1->SendRTCPSliceLossIndication(156));
+
+  WebRtc_UWord32 testOfCSRC[webrtc::kRtpCsrcSize];
+  EXPECT_EQ(2, module2->RemoteCSRCs(testOfCSRC));
+  EXPECT_EQ(test_CSRC[0], testOfCSRC[0]);
+  EXPECT_EQ(test_CSRC[1], testOfCSRC[1]);
+
+  // Set cname of mixed.
+  EXPECT_EQ(0, module1->AddMixedCNAME(test_CSRC[0], "john@192.168.0.1"));
+  EXPECT_EQ(0, module1->AddMixedCNAME(test_CSRC[1], "jane@192.168.0.2"));
+  EXPECT_EQ(-1, module1->AddMixedCNAME(test_CSRC[0], NULL));
+
+  EXPECT_EQ(-1, module1->RemoveMixedCNAME(test_CSRC[0] + 1));
+  EXPECT_EQ(0, module1->RemoveMixedCNAME(test_CSRC[1]));
+  EXPECT_EQ(0, module1->AddMixedCNAME(test_CSRC[1], "jane@192.168.0.2"));
+
+  RTCPReportBlock reportBlock;
+  reportBlock.cumulativeLost = 1;
+  reportBlock.delaySinceLastSR = 2;
+  reportBlock.extendedHighSeqNum = 3;
+  reportBlock.fractionLost= 4;
+  reportBlock.jitter = 5;
+  reportBlock.lastSR = 6;
+
+  // Set report blocks.
+  EXPECT_EQ(-1, module1->AddRTCPReportBlock(test_CSRC[0], NULL));
+  EXPECT_EQ(0, module1->AddRTCPReportBlock(test_CSRC[0], &reportBlock));
+
+  reportBlock.lastSR= 7;
+  EXPECT_EQ(0, module1->AddRTCPReportBlock(test_CSRC[1], &reportBlock));
+
+  WebRtc_UWord32 name = 't' << 24;
+  name += 'e' << 16;
+  name += 's' << 8;
+  name += 't';
+  EXPECT_EQ(0, module1->SetRTCPApplicationSpecificData(
+      3,
+      name,
+      (const WebRtc_UWord8 *)"test test test test test test test test test"\
+          " test test test test test test test test test test test test test"\
+          " test test test test test test test test test test test test test"\
+          " test test test test test test test test test test test test test"\
+          " test test test test test test test test test test test test ",
+          300));
+
+  // send RTCP packet, triggered by timer
+  fake_clock.IncrementTime(7500);
+  module1->Process();
+  fake_clock.IncrementTime(100);
+  module2->Process();
+
+  WebRtc_UWord32 receivedNTPsecs = 0;
+  WebRtc_UWord32 receivedNTPfrac = 0;
+  WebRtc_UWord32 RTCPArrivalTimeSecs = 0;
+  WebRtc_UWord32 RTCPArrivalTimeFrac = 0;
+  WebRtc_Word8 cName[RTCP_CNAME_SIZE];
+
+  EXPECT_EQ(0, module2->RemoteNTP(&receivedNTPsecs, &receivedNTPfrac,
+                                  &RTCPArrivalTimeSecs, &RTCPArrivalTimeFrac));
+
+  EXPECT_EQ(-1, module2->RemoteCNAME(module2->RemoteSSRC() + 1, cName));
+  EXPECT_EQ(-1, module2->RemoteCNAME(module2->RemoteSSRC(), NULL));
+
+  // Check multiple CNAME.
+  EXPECT_EQ(0, module2->RemoteCNAME(module2->RemoteSSRC(), cName));
+  EXPECT_EQ(0, strncmp(cName, "john.doe@test.test", RTCP_CNAME_SIZE));
+
+  EXPECT_EQ(0, module2->RemoteCNAME(test_CSRC[0], cName));
+  EXPECT_EQ(0, strncmp(cName, "john@192.168.0.1", RTCP_CNAME_SIZE));
+
+  EXPECT_EQ(0, module2->RemoteCNAME(test_CSRC[1], cName));
+  EXPECT_EQ(0, strncmp(cName, "jane@192.168.0.2", RTCP_CNAME_SIZE));
+
+  // get all report blocks
+  RTCPReportBlock reportBlockReceived;
+  EXPECT_EQ(-1, module1->RemoteRTCPStat(test_ssrc, &reportBlockReceived));
+  EXPECT_EQ(-1, module1->RemoteRTCPStat(test_ssrc + 1, NULL));
+  EXPECT_EQ(0, module1->RemoteRTCPStat(test_ssrc + 1, &reportBlockReceived));
+  float secSinceLastReport =
+      static_cast<float>(reportBlockReceived.delaySinceLastSR) / 65536.0f;
+  EXPECT_GE(0.101f, secSinceLastReport);
+  EXPECT_LE(0.100f, secSinceLastReport);
+  EXPECT_EQ(test_sequence_number, reportBlockReceived.extendedHighSeqNum);
+  EXPECT_EQ(0, reportBlockReceived.fractionLost);
+
+  EXPECT_EQ(static_cast<WebRtc_UWord32>(0),
+            reportBlockReceived.cumulativeLost);
+
+  WebRtc_UWord8  fraction_lost = 0;  // scale 0 to 255
+  WebRtc_UWord32 cum_lost = 0;       // number of lost packets
+  WebRtc_UWord32 ext_max = 0;        // highest sequence number received
+  WebRtc_UWord32 jitter = 0;
+  WebRtc_UWord32 max_jitter = 0;
+  EXPECT_EQ(0, module2->StatisticsRTP(&fraction_lost,
+                                      &cum_lost,
+                                      &ext_max,
+                                      &jitter,
+                                      &max_jitter));
+  EXPECT_EQ(0, fraction_lost);
+  EXPECT_EQ((WebRtc_UWord32)0, cum_lost);
+  EXPECT_EQ(test_sequence_number, ext_max);
+  EXPECT_EQ(reportBlockReceived.jitter, jitter);
+
+  WebRtc_UWord16 RTT;
+  WebRtc_UWord16 avgRTT;
+  WebRtc_UWord16 minRTT;
+  WebRtc_UWord16 maxRTT;
+
+  // Get RoundTripTime.
+  EXPECT_EQ(0, module1->RTT(test_ssrc + 1, &RTT, &avgRTT, &minRTT, &maxRTT));
+  EXPECT_GE(10, RTT);
+  EXPECT_GE(10, avgRTT);
+  EXPECT_GE(10, minRTT);
+  EXPECT_GE(10, maxRTT);
+
+  // Set report blocks.
+  EXPECT_EQ(0, module1->AddRTCPReportBlock(test_CSRC[0], &reportBlock));
+
+  // Test receive report.
+  EXPECT_EQ(0, module1->SetSendingStatus(false));
+
+  // Test that BYE clears the CNAME
+  EXPECT_EQ(-1, module2->RemoteCNAME(module2->RemoteSSRC(), cName));
+
+  // Send RTCP packet, triggered by timer.
+  fake_clock.IncrementTime(5000);
+  module1->Process();
+  module2->Process();
+
+  delete myRTCPFeedback1;
+  delete myRTCPFeedback2;
+}
diff --git a/src/modules/rtp_rtcp/test/testAPI/test_api_video.cc b/src/modules/rtp_rtcp/test/testAPI/test_api_video.cc
new file mode 100644
index 0000000..7a06ef7
--- /dev/null
+++ b/src/modules/rtp_rtcp/test/testAPI/test_api_video.cc
@@ -0,0 +1,90 @@
+/*
+ *  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 <algorithm>
+#include <vector>
+#include <gtest/gtest.h>
+
+#include "test_api.h"
+
+#include "common_types.h"
+#include "rtp_rtcp.h"
+#include "rtp_rtcp_defines.h"
+
+using namespace webrtc;
+
+class RtpRtcpVideoTest : public ::testing::Test {
+ protected:
+  RtpRtcpVideoTest() {
+    test_id = 123;
+    test_ssrc = 3456;
+    test_timestamp = 4567;
+    test_sequence_number = 2345;
+  }
+  ~RtpRtcpVideoTest() {}
+
+  virtual void SetUp() {
+    video_module = RtpRtcp::CreateRtpRtcp(test_id, false, &fake_clock);
+    EXPECT_EQ(0, video_module->InitReceiver());
+    EXPECT_EQ(0, video_module->InitSender());
+    EXPECT_EQ(0, video_module->SetRTCPStatus(kRtcpCompound));
+    EXPECT_EQ(0, video_module->SetSSRC(test_ssrc));
+    EXPECT_EQ(0, video_module->SetNACKStatus(kNackRtcp));
+    EXPECT_EQ(0, video_module->SetStorePacketsStatus(true));
+    EXPECT_EQ(0, video_module->SetSendingStatus(true));
+
+    transport = new LoopBackTransport(video_module);
+    EXPECT_EQ(0, video_module->RegisterSendTransport(transport));
+
+    receiver = new RtpReceiver();
+    EXPECT_EQ(0, video_module->RegisterIncomingDataCallback(receiver));
+
+    VideoCodec video_codec;
+    memset(&video_codec, 0, sizeof(video_codec));
+    video_codec.plType = 123;
+    memcpy(video_codec.plName, "I420", 5);
+
+    EXPECT_EQ(0, video_module->RegisterSendPayload(video_codec));
+    EXPECT_EQ(0, video_module->RegisterReceivePayload(video_codec));
+
+    payload_data_length = sizeof(payload_data);
+
+    for (int n = 0; n < payload_data_length; n++) {
+      payload_data[n] = n%10;
+    }
+  }
+
+  virtual void TearDown() {
+    RtpRtcp::DestroyRtpRtcp(video_module);
+    delete transport;
+    delete receiver;
+  }
+
+  int test_id;
+  RtpRtcp* video_module;
+  LoopBackTransport* transport;
+  RtpReceiver* receiver;
+  WebRtc_UWord32 test_ssrc;
+  WebRtc_UWord32 test_timestamp;
+  WebRtc_UWord16 test_sequence_number;
+  WebRtc_UWord8  payload_data[65000];
+  int payload_data_length;
+  FakeRtpRtcpClock fake_clock;
+};
+
+TEST_F(RtpRtcpVideoTest, BasicVideo) {
+  WebRtc_UWord32 timestamp = 3000;
+  EXPECT_EQ(0, video_module->SendOutgoingData(webrtc::kVideoFrameDelta, 123,
+                                             timestamp,
+                                             payload_data,
+                                             payload_data_length));
+
+}
+
diff --git a/src/video_engine/vie_channel.cc b/src/video_engine/vie_channel.cc
index 8b29ee7..75271be 100644
--- a/src/video_engine/vie_channel.cc
+++ b/src/video_engine/vie_channel.cc
@@ -731,26 +731,40 @@
 }
 
 WebRtc_Word32 ViEChannel::SetSSRC(const WebRtc_UWord32 SSRC,
-                                  const StreamType /*usage*/,
-                                  const unsigned char simulcast_idx) {
-  // TODO(pwestin) add support for stream_type when we add RTX.
-  WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
-               "%s(SSRC: %u, idx:%u)", __FUNCTION__, SSRC, simulcast_idx);
-
+                                  const StreamType usage,
+                                  const uint8_t simulcast_idx) {
+  WEBRTC_TRACE(webrtc::kTraceInfo,
+               webrtc::kTraceVideo,
+               ViEId(engine_id_, channel_id_),
+               "%s(usage:%d, SSRC: 0x%x, idx:%u)",
+               __FUNCTION__, usage, SSRC, simulcast_idx);
   if (simulcast_idx == 0) {
     return rtp_rtcp_.SetSSRC(SSRC);
   }
   std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
-  for (int i = 1; i < simulcast_idx; i++) {
-    it++;
-    if (it == simulcast_rtp_rtcp_.end()) {
+  for (int i = 1; i < simulcast_idx; ++i, ++it) {
+    if (it ==  simulcast_rtp_rtcp_.end()) {
       return -1;
     }
   }
   RtpRtcp* rtp_rtcp = *it;
+  if (usage == kViEStreamTypeRtx) {
+    return rtp_rtcp->SetRTXSendStatus(true, true, SSRC);
+  }
   return rtp_rtcp->SetSSRC(SSRC);
 }
 
+WebRtc_Word32 ViEChannel::SetRemoteSSRCType(const StreamType usage,
+                                            const uint32_t SSRC) const {
+  WEBRTC_TRACE(webrtc::kTraceInfo,
+               webrtc::kTraceVideo,
+               ViEId(engine_id_, channel_id_),
+               "%s(usage:%d, SSRC: 0x%x)",
+               __FUNCTION__, usage, SSRC);
+
+  return rtp_rtcp_.SetRTXReceiveStatus(true, SSRC);
+}
+
 WebRtc_Word32 ViEChannel::GetLocalSSRC(WebRtc_UWord32& SSRC) {
   WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
                "%s", __FUNCTION__);
diff --git a/src/video_engine/vie_channel.h b/src/video_engine/vie_channel.h
index 2c04bdd..6bcddeb 100644
--- a/src/video_engine/vie_channel.h
+++ b/src/video_engine/vie_channel.h
@@ -221,6 +221,8 @@
                               WebRtc_Word8* ip_address,
                               WebRtc_UWord32 ip_address_length);
 
+  WebRtc_Word32 SetRemoteSSRCType(const StreamType usage,
+                                  const uint32_t SSRC) const;
 
   WebRtc_Word32 StartSend();
   WebRtc_Word32 StopSend();
diff --git a/src/video_engine/vie_rtp_rtcp_impl.cc b/src/video_engine/vie_rtp_rtcp_impl.cc
index 4bba011..ebfa200 100644
--- a/src/video_engine/vie_rtp_rtcp_impl.cc
+++ b/src/video_engine/vie_rtp_rtcp_impl.cc
@@ -144,6 +144,33 @@
   return 0;
 }
 
+int ViERTP_RTCPImpl::SetRemoteSSRCType(const int videoChannel,
+                                       const StreamType usage,
+                                       const unsigned int SSRC) const {
+  WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo,
+               ViEId(instance_id_, videoChannel),
+               "%s(channel: %d, usage:%d SSRC: 0x%x)",
+               __FUNCTION__, usage, videoChannel, SSRC);
+
+  // Get the channel
+  ViEChannelManagerScoped cs(channel_manager_);
+  ViEChannel* ptrViEChannel = cs.Channel(videoChannel);
+  if (ptrViEChannel == NULL) {
+    // The channel doesn't exists
+    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo,
+                 ViEId(instance_id_, videoChannel),
+                 "%s: Channel %d doesn't exist",
+                 __FUNCTION__, videoChannel);
+    SetLastError(kViERtpRtcpInvalidChannelId);
+    return -1;
+  }
+  if (ptrViEChannel->SetRemoteSSRCType(usage, SSRC) != 0) {
+    SetLastError(kViERtpRtcpUnknownError);
+    return -1;
+  }
+  return 0;
+}
+
 int ViERTP_RTCPImpl::GetLocalSSRC(const int video_channel,
                                   unsigned int& SSRC) const {
   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_, video_channel),
@@ -163,13 +190,6 @@
   return 0;
 }
 
-int ViERTP_RTCPImpl::SetRemoteSSRCType(const int video_channel,
-                                       const StreamType usage,
-                                       const unsigned int SSRC) const {
-  // TODO(pwestin) add support for RTX.
-  return -1;
-}
-
 int ViERTP_RTCPImpl::GetRemoteSSRC(const int video_channel,
                                    unsigned int& SSRC) const {
   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, ViEId(instance_id_, video_channel),