From 9f5ebb525130f207229dfa350ce8c2bdd22163c7 Mon Sep 17 00:00:00 2001
From: "mflodman@webrtc.org"
 <mflodman@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>
Date: Fri, 12 Apr 2013 14:55:46 +0000
Subject: [PATCH] Adding a payload type for RTX.

BUG=736
TEST=Modified RTP unittests.

Review URL: https://webrtc-codereview.appspot.com/1278004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3843 4adac7df-926f-26a2-2b94-8c16560cd09d
---
 webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h  | 23 +++++++----
 .../rtp_rtcp/interface/rtp_rtcp_defines.h     |  2 +
 webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h | 20 ++++++----
 .../rtp_rtcp/source/nack_rtx_unittest.cc      | 13 ++++---
 .../rtp_rtcp/source/rtp_payload_registry.h    |  4 ++
 .../modules/rtp_rtcp/source/rtp_receiver.cc   | 32 +++++++++++++---
 webrtc/modules/rtp_rtcp/source/rtp_receiver.h |  7 +++-
 .../modules/rtp_rtcp/source/rtp_rtcp_impl.cc  | 34 ++++++++++-------
 .../modules/rtp_rtcp/source/rtp_rtcp_impl.h   | 12 ++++--
 webrtc/modules/rtp_rtcp/source/rtp_sender.cc  | 24 +++++++++---
 webrtc/modules/rtp_rtcp/source/rtp_sender.h   |  8 ++--
 .../modules/rtp_rtcp/test/testAPI/test_api.cc | 24 ++++++++++--
 webrtc/video_engine/include/vie_rtp_rtcp.h    |  8 ++++
 webrtc/video_engine/vie_channel.cc            | 27 ++++++++++++-
 webrtc/video_engine/vie_channel.h             |  3 ++
 webrtc/video_engine/vie_rtp_rtcp_impl.cc      | 38 +++++++++++++++++++
 webrtc/video_engine/vie_rtp_rtcp_impl.h       |  4 ++
 17 files changed, 222 insertions(+), 61 deletions(-)

diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
index 385520487..d7676d989 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -232,14 +232,18 @@ class RtpRtcp : public Module {
     /*
     * Turn on/off receiving RTX (RFC 4588) on a specific SSRC.
     */
-    virtual int32_t SetRTXReceiveStatus(const bool enable,
-                                        const uint32_t SSRC) = 0;
+    virtual int32_t SetRTXReceiveStatus(bool enable, uint32_t SSRC) = 0;
+
+    // Sets the payload type to expected for received RTX packets. Note
+    // that this doesn't enable RTX, only the payload type is set.
+    virtual void SetRtxReceivePayloadType(int payload_type) = 0;
 
     /*
     * Get status of receiving RTX (RFC 4588) on a specific SSRC.
     */
     virtual int32_t RTXReceiveStatus(bool* enable,
-                                     uint32_t* SSRC) const = 0;
+                                     uint32_t* SSRC,
+                                     int* payloadType) const = 0;
 
     /*
     *   called by the network module when we receive a packet
@@ -416,15 +420,18 @@ class RtpRtcp : public Module {
     /*
     * Turn on/off sending RTX (RFC 4588) on a specific SSRC.
     */
-    virtual int32_t SetRTXSendStatus(const RtxMode mode,
-                                     const bool setSSRC,
-                                     const uint32_t SSRC) = 0;
+    virtual int32_t SetRTXSendStatus(RtxMode mode, bool set_ssrc,
+                                     uint32_t ssrc) = 0;
+
+    // Sets the payload type to use when sending RTX packets. Note that this
+    // doesn't enable RTX, only the payload type is set.
+    virtual void SetRtxSendPayloadType(int payload_type) = 0;
 
     /*
     * Get status of sending RTX (RFC 4588) on a specific SSRC.
     */
-    virtual int32_t RTXSendStatus(RtxMode* mode,
-                                  uint32_t* SSRC) const = 0;
+    virtual int32_t RTXSendStatus(RtxMode* mode, uint32_t* ssrc,
+                                  int* payloadType) const = 0;
 
     /*
     *   sends kRtcpByeCode when going from true to false
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
index 616e5345d..3da5d7526 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
@@ -113,6 +113,8 @@ enum RtxMode {
   kRtxAll = 2  // Apply RTX to all packets (source + retransmissions).
 };
 
+const int kRtxHeaderSize = 2;
+
 struct RTCPSenderInfo
 {
     uint32_t NTPseconds;
diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 76cc31680..2d0206296 100644
--- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -76,11 +76,14 @@ class MockRtpRtcp : public RtpRtcp {
   MOCK_METHOD2(SetSSRCFilter,
       int32_t(const bool enable, const uint32_t allowedSSRC));
   MOCK_METHOD2(SetRTXReceiveStatus,
-      int32_t(const bool enable, const uint32_t SSRC));
-  MOCK_CONST_METHOD2(RTXReceiveStatus,
-      int32_t(bool* enable, uint32_t* SSRC));
+      int32_t(bool enable, uint32_t ssrc));
+  MOCK_CONST_METHOD3(RTXReceiveStatus,
+      int32_t(bool* enable, uint32_t* ssrc, int* payload_type));
+  MOCK_METHOD1(SetRtxReceivePayloadType,
+      void(int));
   MOCK_METHOD2(IncomingPacket,
-      int32_t(const uint8_t* incomingPacket, const uint16_t packetLength));
+      int32_t(const WebRtc_UWord8* incomingPacket,
+              const WebRtc_UWord16 packetLength));
   MOCK_METHOD4(IncomingAudioNTP,
       int32_t(const uint32_t audioReceivedNTPsecs,
               const uint32_t audioReceivedNTPfrac,
@@ -128,10 +131,11 @@ class MockRtpRtcp : public RtpRtcp {
   MOCK_METHOD1(SetCSRCStatus,
       int32_t(const bool include));
   MOCK_METHOD3(SetRTXSendStatus,
-      int32_t(const RtxMode mode, const bool setSSRC,
-              const uint32_t SSRC));
- MOCK_CONST_METHOD2(RTXSendStatus,
-      int32_t(RtxMode* mode, uint32_t* SSRC));
+      int32_t(RtxMode mode, bool setSSRC, uint32_t ssrc));
+  MOCK_CONST_METHOD3(RTXSendStatus,
+      int32_t(RtxMode* mode, uint32_t* ssrc, int* payload_type));
+  MOCK_METHOD1(SetRtxSendPayloadType,
+      void(int));
   MOCK_METHOD1(SetSendingStatus,
       int32_t(const bool sending));
   MOCK_CONST_METHOD0(Sending,
diff --git a/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc b/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc
index 925db94e7..b1d494c6e 100644
--- a/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/nack_rtx_unittest.cc
@@ -193,8 +193,10 @@ TEST_F(RtpRtcpRtxNackTest, RTCP) {
 
 TEST_F(RtpRtcpRtxNackTest, RTXNack) {
   EXPECT_EQ(0, rtp_rtcp_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxRetransmitted,
-                                                  true, kTestSsrc + 1));
+  rtp_rtcp_module_->SetRtxReceivePayloadType(119);
+  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxRetransmitted, true,
+                                                  kTestSsrc + 1));
+  rtp_rtcp_module_->SetRtxSendPayloadType(119);
 
   transport_.DropEveryNthPacket(10);
 
@@ -251,8 +253,8 @@ TEST_F(RtpRtcpRtxNackTest, RTXNack) {
 
 TEST_F(RtpRtcpRtxNackTest, RTXAllNoLoss) {
   EXPECT_EQ(0, rtp_rtcp_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxAll,
-                                                  true, kTestSsrc + 1));
+  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxAll, true,
+                                                  kTestSsrc + 1));
   transport_.DropEveryNthPacket(0);
 
   uint32_t timestamp = 3000;
@@ -285,8 +287,7 @@ TEST_F(RtpRtcpRtxNackTest, RTXAllNoLoss) {
 
 TEST_F(RtpRtcpRtxNackTest, RTXAllWithLoss) {
   EXPECT_EQ(0, rtp_rtcp_module_->SetRTXReceiveStatus(true, kTestSsrc + 1));
-  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxAll,
-                                                  true,
+  EXPECT_EQ(0, rtp_rtcp_module_->SetRTXSendStatus(kRtxAll, true,
                                                   kTestSsrc + 1));
 
   int loss = 10;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h
index 7ba4c2517..465a4edd9 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.h
@@ -93,6 +93,10 @@ class RTPPayloadRegistry {
     last_received_payload_type_ = last_received_payload_type;
   }
 
+  int8_t last_received_media_payload_type() const {
+    return last_received_media_payload_type_;
+  };
+
  private:
   // Prunes the payload type map of the specific payload type, if it exists.
   void DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc
index 6db157eee..7a811659a 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver.cc
@@ -94,7 +94,8 @@ RTPReceiver::RTPReceiver(const int32_t id,
       nack_method_(kNackOff),
       max_reordering_threshold_(kDefaultMaxReorderingThreshold),
       rtx_(false),
-      ssrc_rtx_(0) {
+      ssrc_rtx_(0),
+      payload_type_rtx_(-1) {
   assert(incoming_audio_messages_callback &&
          incoming_messages_callback &&
          incoming_payload_callback);
@@ -288,17 +289,23 @@ int32_t RTPReceiver::SetNACKStatus(const NACKMethod method,
   return 0;
 }
 
-void RTPReceiver::SetRTXStatus(const bool enable,
-                               const uint32_t ssrc) {
+void RTPReceiver::SetRTXStatus(bool enable, uint32_t ssrc) {
   CriticalSectionScoped lock(critical_section_rtp_receiver_);
   rtx_ = enable;
   ssrc_rtx_ = ssrc;
 }
 
-void RTPReceiver::RTXStatus(bool* enable, uint32_t* ssrc) const {
+void RTPReceiver::RTXStatus(bool* enable, uint32_t* ssrc,
+                            int* payload_type) const {
   CriticalSectionScoped lock(critical_section_rtp_receiver_);
   *enable = rtx_;
   *ssrc = ssrc_rtx_;
+  *payload_type = payload_type_rtx_;
+}
+
+void RTPReceiver::SetRtxPayloadType(int payload_type) {
+  CriticalSectionScoped cs(critical_section_rtp_receiver_);
+  payload_type_rtx_ = payload_type;
 }
 
 uint32_t RTPReceiver::SSRC() const {
@@ -350,10 +357,23 @@ int32_t RTPReceiver::IncomingRTPPacket(
   }
   if (rtx_) {
     if (ssrc_rtx_ == rtp_header->header.ssrc) {
-      // Sanity check.
-      if (rtp_header->header.headerLength + 2 > packet_length) {
+      // Sanity check, RTX packets has 2 extra header bytes.
+      if (rtp_header->header.headerLength + kRtxHeaderSize > packet_length) {
         return -1;
       }
+      // If a specific RTX payload type is negotiated, set back to the media
+      // payload type and treat it like a media packet from here.
+      if (payload_type_rtx_ != -1) {
+        if (payload_type_rtx_ == rtp_header->header.payloadType &&
+            rtp_payload_registry_->last_received_media_payload_type() != -1) {
+          rtp_header->header.payloadType =
+              rtp_payload_registry_->last_received_media_payload_type();
+        } else {
+          WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, id_,
+                       "Incorrect RTX configuration, dropping packet.");
+          return -1;
+        }
+      }
       rtp_header->header.ssrc = ssrc_;
       rtp_header->header.sequenceNumber =
         (packet[rtp_header->header.headerLength] << 8) +
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_receiver.h b/webrtc/modules/rtp_rtcp/source/rtp_receiver.h
index 8d794ced3..eaaab79c6 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_receiver.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_receiver.h
@@ -141,9 +141,11 @@ class RTPReceiver : public Bitrate {
   void GetHeaderExtensionMapCopy(RtpHeaderExtensionMap* map) const;
 
   // RTX.
-  void SetRTXStatus(const bool enable, const uint32_t ssrc);
+  void SetRTXStatus(bool enable, uint32_t ssrc);
 
-  void RTXStatus(bool* enable, uint32_t* ssrc) const;
+  void RTXStatus(bool* enable, uint32_t* ssrc, int* payload_type) const;
+
+  void SetRtxPayloadType(int payload_type);
 
   virtual int8_t REDPayloadType() const;
 
@@ -234,6 +236,7 @@ class RTPReceiver : public Bitrate {
 
   bool rtx_;
   uint32_t ssrc_rtx_;
+  int payload_type_rtx_;
 };
 
 } // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 1597ab2cd..bda7f1218 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -314,7 +314,7 @@ void ModuleRtpRtcpImpl::ProcessDeadOrAliveTimer() {
   bool do_callback = false;
 
   // Do operations on members under lock but avoid making the
-  // ProcessDeadOrAlive() callback under the same lock. 
+  // ProcessDeadOrAlive() callback under the same lock.
   {
     CriticalSectionScoped lock(critical_section_module_ptrs_.get());
     if (dead_or_alive_active_) {
@@ -325,7 +325,7 @@ void ModuleRtpRtcpImpl::ProcessDeadOrAliveTimer() {
 
         if (rtcp_receiver_.LastReceived() + 12000 > now)
           RTCPalive = true;
-        
+
         do_callback = true;
       }
     }
@@ -532,32 +532,38 @@ int32_t ModuleRtpRtcpImpl::RemoteCSRCs(
   return rtp_receiver_->CSRCs(arr_of_csrc);
 }
 
-int32_t ModuleRtpRtcpImpl::SetRTXSendStatus(
-    const RtxMode mode,
-    const bool set_ssrc,
-    const uint32_t ssrc) {
+int32_t ModuleRtpRtcpImpl::SetRTXSendStatus(RtxMode mode, bool set_ssrc,
+                                            uint32_t ssrc) {
   rtp_sender_.SetRTXStatus(mode, set_ssrc, ssrc);
   return 0;
 }
 
-int32_t ModuleRtpRtcpImpl::RTXSendStatus(RtxMode* mode, uint32_t* ssrc) const {
-  rtp_sender_.RTXStatus(mode, ssrc);
+int32_t ModuleRtpRtcpImpl::RTXSendStatus(RtxMode* mode, uint32_t* ssrc,
+                                         int* payload_type) const {
+  rtp_sender_.RTXStatus(mode, ssrc, payload_type);
   return 0;
 }
 
-int32_t ModuleRtpRtcpImpl::SetRTXReceiveStatus(
-    const bool enable,
-    const uint32_t ssrc) {
+int32_t ModuleRtpRtcpImpl::SetRTXReceiveStatus(bool enable,
+                                               uint32_t ssrc) {
   rtp_receiver_->SetRTXStatus(enable, ssrc);
   return 0;
 }
 
-int32_t ModuleRtpRtcpImpl::RTXReceiveStatus(bool* enable,
-                                            uint32_t* ssrc) const {
-  rtp_receiver_->RTXStatus(enable, ssrc);
+int32_t ModuleRtpRtcpImpl::RTXReceiveStatus(bool* enable, uint32_t* ssrc,
+                                            int* payload_type) const {
+  rtp_receiver_->RTXStatus(enable, ssrc, payload_type);
   return 0;
 }
 
+void ModuleRtpRtcpImpl::SetRtxSendPayloadType(int payload_type) {
+  rtp_sender_.SetRtxPayloadType(payload_type);
+}
+
+void ModuleRtpRtcpImpl::SetRtxReceivePayloadType(int payload_type) {
+  rtp_receiver_->SetRtxPayloadType(payload_type);
+}
+
 // Called by the network module when we receive a packet.
 int32_t ModuleRtpRtcpImpl::IncomingPacket(
     const uint8_t* incoming_packet,
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 3d0be8be4..8311388cb 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -103,8 +103,10 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
   virtual int32_t SetRTXReceiveStatus(const bool enable,
                                       const uint32_t ssrc);
 
-  virtual int32_t RTXReceiveStatus(bool* enable,
-                                   uint32_t* ssrc) const;
+  virtual int32_t RTXReceiveStatus(bool* enable, uint32_t* ssrc,
+                                   int* payloadType) const;
+
+  virtual void SetRtxReceivePayloadType(int payload_type);
 
   // Called by the network module when we receive a packet.
   virtual int32_t IncomingPacket(const uint8_t* incoming_packet,
@@ -161,7 +163,11 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
                                    const bool set_ssrc,
                                    const uint32_t ssrc);
 
-  virtual int32_t RTXSendStatus(RtxMode* mode, uint32_t* ssrc) const;
+  virtual int32_t RTXSendStatus(RtxMode* mode, uint32_t* ssrc,
+                                int* payloadType) const;
+
+
+  virtual void SetRtxSendPayloadType(int payload_type);
 
   // Sends kRtcpByeCode when going from true to false.
   virtual int32_t SetSendingStatus(const bool sending);
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
index 0e481c752..54c242d05 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -58,7 +58,7 @@ RTPSender::RTPSender(const int32_t id, const bool audio, Clock *clock,
       start_time_stamp_(0), ssrc_db_(*SSRCDatabase::GetSSRCDatabase()),
       remote_ssrc_(0), sequence_number_forced_(false), ssrc_forced_(false),
       time_stamp_(0), csrcs_(0), csrc_(), include_csrcs_(true),
-      rtx_(kRtxOff) {
+      rtx_(kRtxOff), payload_type_rtx_(-1) {
   memset(nack_byte_count_times_, 0, sizeof(nack_byte_count_times_));
   memset(nack_byte_count_, 0, sizeof(nack_byte_count_));
   memset(csrc_, 0, sizeof(csrc_));
@@ -255,8 +255,7 @@ uint16_t RTPSender::MaxPayloadLength() const {
 
 uint16_t RTPSender::PacketOverHead() const { return packet_over_head_; }
 
-void RTPSender::SetRTXStatus(const RtxMode mode, const bool set_ssrc,
-                             const uint32_t ssrc) {
+void RTPSender::SetRTXStatus(RtxMode mode, bool set_ssrc, uint32_t ssrc) {
   CriticalSectionScoped cs(send_critsect_);
   rtx_ = mode;
   if (rtx_ != kRtxOff) {
@@ -268,10 +267,18 @@ void RTPSender::SetRTXStatus(const RtxMode mode, const bool set_ssrc,
   }
 }
 
-void RTPSender::RTXStatus(RtxMode* mode, uint32_t *SSRC) const {
+void RTPSender::RTXStatus(RtxMode* mode, uint32_t* ssrc,
+                          int* payload_type) const {
   CriticalSectionScoped cs(send_critsect_);
   *mode = rtx_;
-  *SSRC = ssrc_rtx_;
+  *ssrc = ssrc_rtx_;
+  *payload_type = payload_type_rtx_;
+}
+
+
+void RTPSender::SetRtxPayloadType(int payload_type) {
+  CriticalSectionScoped cs(send_critsect_);
+  payload_type_rtx_ = payload_type;
 }
 
 int32_t RTPSender::CheckPayloadType(const int8_t payload_type,
@@ -1222,6 +1229,13 @@ void RTPSender::BuildRtxPacket(uint8_t* buffer, uint16_t* length,
   // Add original RTP header.
   memcpy(data_buffer_rtx, buffer, rtp_header.header.headerLength);
 
+  // Replace payload type, if a specific type is set for RTX.
+  if (payload_type_rtx_ != -1) {
+    data_buffer_rtx[1] = static_cast<uint8_t>(payload_type_rtx_);
+    if (rtp_header.header.markerBit)
+      data_buffer_rtx[1] |= kRtpMarkerBitMask;
+  }
+
   // Replace sequence number.
   uint8_t *ptr = data_buffer_rtx + 2;
   ModuleRTPUtility::AssignUWord16ToBuffer(ptr, sequence_number_rtx_++);
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h
index b57bcf484..0f4163279 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h
@@ -174,10 +174,11 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
   bool ProcessNACKBitRate(const uint32_t now);
 
   // RTX.
-  void SetRTXStatus(const RtxMode mode, const bool set_ssrc,
-                    const uint32_t SSRC);
+  void SetRTXStatus(RtxMode mode, bool set_ssrc, uint32_t ssrc);
 
-  void RTXStatus(RtxMode* mode, uint32_t *SSRC) const;
+  void RTXStatus(RtxMode* mode, uint32_t* ssrc, int* payload_type) const;
+
+  void SetRtxPayloadType(int payloadType);
 
   // Functions wrapping RTPSenderInterface.
   virtual int32_t BuildRTPheader(
@@ -310,6 +311,7 @@ class RTPSender : public Bitrate, public RTPSenderInterface {
   bool include_csrcs_;
   RtxMode rtx_;
   uint32_t ssrc_rtx_;
+  int payload_type_rtx_;
 };
 
 }  // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc b/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc
index 4a00935d6..1eaf0f02c 100644
--- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc
+++ b/webrtc/modules/rtp_rtcp/test/testAPI/test_api.cc
@@ -111,24 +111,40 @@ TEST_F(RtpRtcpAPITest, RTCP) {
 TEST_F(RtpRtcpAPITest, RTXSender) {
   unsigned int ssrc = 0;
   RtxMode rtx_mode = kRtxOff;
+  const int kRtxPayloadType = 119;
+  int payload_type = -1;
   EXPECT_EQ(0, module->SetRTXSendStatus(kRtxRetransmitted, true, 1));
-  EXPECT_EQ(0, module->RTXSendStatus(&rtx_mode, &ssrc));
+  module->SetRtxSendPayloadType(kRtxPayloadType);
+  EXPECT_EQ(0, module->RTXSendStatus(&rtx_mode, &ssrc, &payload_type));
   EXPECT_EQ(kRtxRetransmitted, rtx_mode);
   EXPECT_EQ(1u, ssrc);
+  EXPECT_EQ(kRtxPayloadType, payload_type);
   rtx_mode = kRtxOff;
   EXPECT_EQ(0, module->SetRTXSendStatus(kRtxOff, true, 0));
-  EXPECT_EQ(0, module->RTXSendStatus(&rtx_mode, &ssrc));
+  payload_type = -1;
+  module->SetRtxSendPayloadType(kRtxPayloadType);
+  EXPECT_EQ(0, module->RTXSendStatus(&rtx_mode, &ssrc, &payload_type));
   EXPECT_EQ(kRtxOff, rtx_mode);
+  EXPECT_EQ(kRtxPayloadType ,payload_type);
+  EXPECT_EQ(0, module->SetRTXSendStatus(kRtxRetransmitted, false, 1));
+  EXPECT_EQ(0, module->RTXSendStatus(&rtx_mode, &ssrc, &payload_type));
+  EXPECT_EQ(kRtxRetransmitted, rtx_mode);
+  EXPECT_EQ(kRtxPayloadType ,payload_type);
 }
 
 TEST_F(RtpRtcpAPITest, RTXReceiver) {
   bool enable = false;
   unsigned int ssrc = 0;
+  const int kRtxPayloadType = 119;
+  int payload_type = -1;
   EXPECT_EQ(0, module->SetRTXReceiveStatus(true, 1));
-  EXPECT_EQ(0, module->RTXReceiveStatus(&enable, &ssrc));
+  module->SetRtxReceivePayloadType(kRtxPayloadType);
+  EXPECT_EQ(0, module->RTXReceiveStatus(&enable, &ssrc, &payload_type));
   EXPECT_TRUE(enable);
   EXPECT_EQ(1u, ssrc);
+  EXPECT_EQ(kRtxPayloadType ,payload_type);
   EXPECT_EQ(0, module->SetRTXReceiveStatus(false, 0));
-  EXPECT_EQ(0, module->RTXReceiveStatus(&enable, &ssrc));
+  EXPECT_EQ(0, module->RTXReceiveStatus(&enable, &ssrc, &payload_type));
   EXPECT_FALSE(enable);
+  EXPECT_EQ(kRtxPayloadType ,payload_type);
 }
diff --git a/webrtc/video_engine/include/vie_rtp_rtcp.h b/webrtc/video_engine/include/vie_rtp_rtcp.h
index a178ea111..b1fd90c53 100644
--- a/webrtc/video_engine/include/vie_rtp_rtcp.h
+++ b/webrtc/video_engine/include/vie_rtp_rtcp.h
@@ -133,6 +133,14 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP {
   virtual int GetRemoteCSRCs(const int video_channel,
                              unsigned int CSRCs[kRtpCsrcSize]) const = 0;
 
+  // This sets a specific payload type for the RTX stream. Note that this
+  // doesn't enable RTX, SetLocalSSRC must still be called to enable RTX.
+  virtual int SetRtxSendPayloadType(const int video_channel,
+                                    const uint8_t payload_type) = 0;
+
+  virtual int SetRtxReceivePayloadType(const int video_channel,
+                                       const uint8_t payload_type) = 0;
+
   // This function enables manual initialization of the sequence number. The
   // start sequence number is normally a random number.
   virtual int SetStartSequenceNumber(const int video_channel,
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index a8fecbee9..7aeb6a14d 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -973,8 +973,31 @@ int32_t ViEChannel::GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]) {
   return 0;
 }
 
-int32_t ViEChannel::SetStartSequenceNumber(
-    uint16_t sequence_number) {
+int ViEChannel::SetRtxSendPayloadType(int payload_type) {
+  if (rtp_rtcp_->Sending()) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
+               "%s: already sending", __FUNCTION__);
+    return -1;
+  }
+  rtp_rtcp_->SetRtxSendPayloadType(payload_type);
+  CriticalSectionScoped cs(rtp_rtcp_cs_.get());
+  for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
+       it != simulcast_rtp_rtcp_.end(); it++) {
+    (*it)->SetRtxSendPayloadType(payload_type);
+  }
+  return 0;
+}
+
+void ViEChannel::SetRtxReceivePayloadType(int payload_type) {
+  rtp_rtcp_->SetRtxReceivePayloadType(payload_type);
+  CriticalSectionScoped cs(rtp_rtcp_cs_.get());
+  for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
+       it != simulcast_rtp_rtcp_.end(); it++) {
+    (*it)->SetRtxReceivePayloadType(payload_type);
+  }
+}
+
+int32_t ViEChannel::SetStartSequenceNumber(uint16_t sequence_number) {
   WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
                __FUNCTION__);
 
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index 3aacd9c37..620d64e28 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -139,6 +139,9 @@ class ViEChannel
   // Gets the CSRC for the incoming stream.
   int32_t GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]);
 
+  int SetRtxSendPayloadType(int payload_type);
+  void SetRtxReceivePayloadType(int payload_type);
+
   // Sets the starting sequence number, must be called before StartSend.
   int32_t SetStartSequenceNumber(uint16_t sequence_number);
 
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
index a23019349..4233894df 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
@@ -233,6 +233,44 @@ int ViERTP_RTCPImpl::GetRemoteCSRCs(const int video_channel,
   return 0;
 }
 
+int ViERTP_RTCPImpl::SetRtxSendPayloadType(const int video_channel,
+                                           const uint8_t payload_type) {
+  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
+               ViEId(shared_data_->instance_id(), video_channel),
+               "%s(channel: %d)", __FUNCTION__, video_channel);
+  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+  ViEChannel* vie_channel = cs.Channel(video_channel);
+  if (!vie_channel) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo,
+                 ViEId(shared_data_->instance_id(), video_channel),
+                 "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
+    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
+    return -1;
+  }
+  if (!vie_channel->SetRtxSendPayloadType(payload_type)) {
+    return -1;
+  }
+  return 0;
+}
+
+int ViERTP_RTCPImpl::SetRtxReceivePayloadType(const int video_channel,
+                                              const uint8_t payload_type) {
+  WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
+               ViEId(shared_data_->instance_id(), video_channel),
+               "%s(channel: %d)", __FUNCTION__, video_channel);
+  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+  ViEChannel* vie_channel = cs.Channel(video_channel);
+  if (!vie_channel) {
+    WEBRTC_TRACE(kTraceError, kTraceVideo,
+                 ViEId(shared_data_->instance_id(), video_channel),
+                 "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
+    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
+    return -1;
+  }
+  vie_channel->SetRtxReceivePayloadType(payload_type);
+  return 0;
+}
+
 int ViERTP_RTCPImpl::SetStartSequenceNumber(const int video_channel,
                                             uint16_t sequence_number) {
   WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.h b/webrtc/video_engine/vie_rtp_rtcp_impl.h
index 1c1971ae0..257974ce3 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.h
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.h
@@ -39,6 +39,10 @@ class ViERTP_RTCPImpl
                             unsigned int& SSRC) const;  // NOLINT
   virtual int GetRemoteCSRCs(const int video_channel,
                              unsigned int CSRCs[kRtpCsrcSize]) const;
+  virtual int SetRtxSendPayloadType(const int video_channel,
+                                    const uint8_t payload_type);
+  virtual int SetRtxReceivePayloadType(const int video_channel,
+                                       const uint8_t payload_type);
   virtual int SetStartSequenceNumber(const int video_channel,
                                      uint16_t sequence_number);
   virtual int SetRTCPStatus(const int video_channel,