Support handling multiple RTX but only generate SDP with RTX associated with VP8.
This implementation registers RTX-APT map inside RTP sender and receiver.
While it only generates SDP with RTX associated with VP8 to make it
compatible with previous Chrome versions.
Should add following changes after reaches stable,
* Use RTX-APT map for building and restoring RTP packets.
* Add RTX support for RED or VP9 in Video engine.
* Set RTX payload type for RED inside FecConfig in EndToEndTest.
BUG=4024
R=mflodman@webrtc.org, pbos@webrtc.org, pthatcher@webrtc.org, stefan@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/36889004
Cr-Original-Commit-Position: refs/heads/master@{#9040}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: e62202fedf57b74cc263246c0586ee353978caf8
diff --git a/config.h b/config.h
index e43a588..aae60e7 100644
--- a/config.h
+++ b/config.h
@@ -34,13 +34,19 @@
// Settings for forward error correction, see RFC 5109 for details. Set the
// payload types to '-1' to disable.
struct FecConfig {
- FecConfig() : ulpfec_payload_type(-1), red_payload_type(-1) {}
+ FecConfig()
+ : ulpfec_payload_type(-1),
+ red_payload_type(-1),
+ red_rtx_payload_type(-1) {}
std::string ToString() const;
// Payload type used for ULPFEC packets.
int ulpfec_payload_type;
// Payload type used for RED packets.
int red_payload_type;
+
+ // RTX payload type for RED payload.
+ int red_rtx_payload_type;
};
// RTP header extension to use for the video stream, see RFC 5285.
diff --git a/modules/rtp_rtcp/interface/rtp_payload_registry.h b/modules/rtp_rtcp/interface/rtp_payload_registry.h
index bc1ba2b..bcafdfb 100644
--- a/modules/rtp_rtcp/interface/rtp_payload_registry.h
+++ b/modules/rtp_rtcp/interface/rtp_payload_registry.h
@@ -79,7 +79,7 @@
bool GetRtxSsrc(uint32_t* ssrc) const;
- void SetRtxPayloadType(int payload_type);
+ void SetRtxPayloadType(int payload_type, int associated_payload_type);
bool IsRtx(const RTPHeader& header) const;
@@ -158,7 +158,11 @@
int8_t last_received_payload_type_;
int8_t last_received_media_payload_type_;
bool rtx_;
- int8_t payload_type_rtx_;
+ // TODO(changbin): Remove rtx_payload_type_ once interop with old clients that
+ // only understand one RTX PT is no longer needed.
+ int rtx_payload_type_;
+ // Mapping rtx_payload_type_map_[rtx] = associated.
+ std::map<int, int> rtx_payload_type_map_;
uint32_t ssrc_rtx_;
};
diff --git a/modules/rtp_rtcp/interface/rtp_rtcp.h b/modules/rtp_rtcp/interface/rtp_rtcp.h
index 1ece5e5..1623554 100644
--- a/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -235,10 +235,12 @@
// 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;
+ virtual void SetRtxSendPayloadType(int payload_type,
+ int associated_payload_type) = 0;
- // Gets the payload type to use when sending RTX packets.
- virtual int RtxSendPayloadType() const = 0;
+ // Gets the payload type pair of (RTX, associated) to use when sending RTX
+ // packets.
+ virtual std::pair<int, int> RtxSendPayloadType() const = 0;
/*
* sends kRtcpByeCode when going from true to false
diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 86a792a..0097d56 100644
--- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -97,10 +97,8 @@
MOCK_CONST_METHOD0(RtxSendStatus, int());
MOCK_METHOD1(SetRtxSsrc,
void(uint32_t));
- MOCK_METHOD1(SetRtxSendPayloadType,
- void(int));
- MOCK_CONST_METHOD0(RtxSendPayloadType,
- int());
+ MOCK_METHOD2(SetRtxSendPayloadType, void(int, int));
+ MOCK_CONST_METHOD0(RtxSendPayloadType, std::pair<int, int>());
MOCK_METHOD1(SetSendingStatus,
int32_t(const bool sending));
MOCK_CONST_METHOD0(Sending,
diff --git a/modules/rtp_rtcp/source/nack_rtx_unittest.cc b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
index e5c4faf..0dc3322 100644
--- a/modules/rtp_rtcp/source/nack_rtx_unittest.cc
+++ b/modules/rtp_rtcp/source/nack_rtx_unittest.cc
@@ -32,6 +32,8 @@
const uint32_t kTestNumberOfPackets = 1350;
const int kTestNumberOfRtxPackets = 149;
const int kNumFrames = 30;
+const int kPayloadType = 123;
+const int kRtxPayloadType = 98;
class VerifyingRtxReceiver : public NullRtpData
{
@@ -129,7 +131,10 @@
if (!parser->Parse(restored_packet_ptr, packet_length, &header)) {
return -1;
}
+ } else {
+ rtp_payload_registry_->SetIncomingPayloadType(header);
}
+
restored_packet_ptr += header.headerLength;
packet_length -= header.headerLength;
PayloadUnion payload_specific;
@@ -203,15 +208,17 @@
VideoCodec video_codec;
memset(&video_codec, 0, sizeof(video_codec));
- video_codec.plType = 123;
+ video_codec.plType = kPayloadType;
memcpy(video_codec.plName, "I420", 5);
EXPECT_EQ(0, rtp_rtcp_module_->RegisterSendPayload(video_codec));
+ rtp_rtcp_module_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType);
EXPECT_EQ(0, rtp_receiver_->RegisterReceivePayload(video_codec.plName,
video_codec.plType,
90000,
0,
video_codec.maxBitrate));
+ rtp_payload_registry_.SetRtxPayloadType(kRtxPayloadType, kPayloadType);
for (size_t n = 0; n < payload_data_length; n++) {
payload_data[n] = n % 10;
@@ -262,12 +269,9 @@
uint32_t timestamp = 3000;
uint16_t nack_list[kVideoNackListSize];
for (int frame = 0; frame < kNumFrames; ++frame) {
- EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(webrtc::kVideoFrameDelta,
- 123,
- timestamp,
- timestamp / 90,
- payload_data,
- payload_data_length));
+ EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(
+ webrtc::kVideoFrameDelta, kPayloadType, timestamp,
+ timestamp / 90, payload_data, payload_data_length));
// Min required delay until retransmit = 5 + RTT ms (RTT = 0).
fake_clock.AdvanceTimeMilliseconds(5);
int length = BuildNackList(nack_list);
@@ -310,12 +314,9 @@
// Send 30 frames which at the default size is roughly what we need to get
// enough packets.
for (int frame = 0; frame < kNumFrames; ++frame) {
- EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(webrtc::kVideoFrameDelta,
- 123,
- timestamp,
- timestamp / 90,
- payload_data,
- payload_data_length));
+ EXPECT_EQ(0, rtp_rtcp_module_->SendOutgoingData(
+ webrtc::kVideoFrameDelta, kPayloadType, timestamp,
+ timestamp / 90, payload_data, payload_data_length));
// Prepare next frame.
timestamp += 3000;
fake_clock.AdvanceTimeMilliseconds(33);
diff --git a/modules/rtp_rtcp/source/rtp_payload_registry.cc b/modules/rtp_rtcp/source/rtp_payload_registry.cc
index 24f6d24..df3067a 100644
--- a/modules/rtp_rtcp/source/rtp_payload_registry.cc
+++ b/modules/rtp_rtcp/source/rtp_payload_registry.cc
@@ -15,8 +15,7 @@
namespace webrtc {
-RTPPayloadRegistry::RTPPayloadRegistry(
- RTPPayloadStrategy* rtp_payload_strategy)
+RTPPayloadRegistry::RTPPayloadRegistry(RTPPayloadStrategy* rtp_payload_strategy)
: crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
rtp_payload_strategy_(rtp_payload_strategy),
red_payload_type_(-1),
@@ -25,8 +24,9 @@
last_received_payload_type_(-1),
last_received_media_payload_type_(-1),
rtx_(false),
- payload_type_rtx_(-1),
- ssrc_rtx_(0) {}
+ rtx_payload_type_(-1),
+ ssrc_rtx_(0) {
+}
RTPPayloadRegistry::~RTPPayloadRegistry() {
while (!payload_type_map_.empty()) {
@@ -256,18 +256,18 @@
ByteWriter<uint32_t>::WriteBigEndian(*restored_packet + 8, original_ssrc);
CriticalSectionScoped cs(crit_sect_.get());
+ if (!rtx_)
+ return true;
- if (payload_type_rtx_ != -1) {
- if (header.payloadType == payload_type_rtx_ &&
- incoming_payload_type_ != -1) {
- (*restored_packet)[1] = static_cast<uint8_t>(incoming_payload_type_);
- if (header.markerBit) {
- (*restored_packet)[1] |= kRtpMarkerBitMask; // Marker bit is set.
- }
- } else {
- LOG(LS_WARNING) << "Incorrect RTX configuration, dropping packet.";
- return false;
- }
+ if (rtx_payload_type_ == -1 || incoming_payload_type_ == -1) {
+ LOG(LS_WARNING) << "Incorrect RTX configuration, dropping packet.";
+ return false;
+ }
+ // TODO(changbin): Will use RTX APT map for restoring packets,
+ // thus incoming_payload_type_ should be removed in future.
+ (*restored_packet)[1] = static_cast<uint8_t>(incoming_payload_type_);
+ if (header.markerBit) {
+ (*restored_packet)[1] |= kRtpMarkerBitMask; // Marker bit is set.
}
return true;
}
@@ -284,11 +284,17 @@
return rtx_;
}
-void RTPPayloadRegistry::SetRtxPayloadType(int payload_type) {
+void RTPPayloadRegistry::SetRtxPayloadType(int payload_type,
+ int associated_payload_type) {
CriticalSectionScoped cs(crit_sect_.get());
- assert(payload_type >= 0);
- payload_type_rtx_ = payload_type;
+ if (payload_type < 0) {
+ LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
+ return;
+ }
+
+ rtx_payload_type_map_[payload_type] = associated_payload_type;
rtx_ = true;
+ rtx_payload_type_ = payload_type;
}
bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 4f76ef2..93b5f54 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -206,11 +206,12 @@
rtp_sender_.SetRtxSsrc(ssrc);
}
-void ModuleRtpRtcpImpl::SetRtxSendPayloadType(int payload_type) {
- rtp_sender_.SetRtxPayloadType(payload_type);
+void ModuleRtpRtcpImpl::SetRtxSendPayloadType(int payload_type,
+ int associated_payload_type) {
+ rtp_sender_.SetRtxPayloadType(payload_type, associated_payload_type);
}
-int ModuleRtpRtcpImpl::RtxSendPayloadType() const {
+std::pair<int, int> ModuleRtpRtcpImpl::RtxSendPayloadType() const {
return rtp_sender_.RtxPayloadType();
}
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 3390db3..77256b7 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -88,8 +88,9 @@
void SetRtxSsrc(uint32_t ssrc) override;
- void SetRtxSendPayloadType(int payload_type) override;
- int RtxSendPayloadType() const override;
+ void SetRtxSendPayloadType(int payload_type,
+ int associated_payload_type) override;
+ std::pair<int, int> RtxSendPayloadType() const override;
// Sends kRtcpByeCode when going from true to false.
int32_t SetSendingStatus(bool sending) override;
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index b8d44f1..508c0f5 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -11,7 +11,9 @@
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
#include <stdlib.h> // srand
+#include <utility>
+#include "webrtc/base/checks.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_cvo.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h"
@@ -155,7 +157,7 @@
last_packet_marker_bit_(false),
csrcs_(),
rtx_(kRtxOff),
- payload_type_rtx_(-1),
+ rtx_payload_type_(-1),
target_bitrate_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
target_bitrate_(0) {
memset(nack_byte_count_times_, 0, sizeof(nack_byte_count_times_));
@@ -421,14 +423,28 @@
return ssrc_rtx_;
}
-void RTPSender::SetRtxPayloadType(int payload_type) {
+void RTPSender::SetRtxPayloadType(int payload_type,
+ int associated_payload_type) {
CriticalSectionScoped cs(send_critsect_.get());
- payload_type_rtx_ = payload_type;
+ DCHECK_LE(payload_type, 127);
+ DCHECK_LE(associated_payload_type, 127);
+ if (payload_type < 0) {
+ LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
+ return;
+ }
+
+ rtx_payload_type_map_[associated_payload_type] = payload_type;
+ rtx_payload_type_ = payload_type;
}
-int RTPSender::RtxPayloadType() const {
+std::pair<int, int> RTPSender::RtxPayloadType() const {
CriticalSectionScoped cs(send_critsect_.get());
- return payload_type_rtx_;
+ for (const auto& kv : rtx_payload_type_map_) {
+ if (kv.second == rtx_payload_type_) {
+ return std::make_pair(rtx_payload_type_, kv.first);
+ }
+ }
+ return std::make_pair(-1, -1);
}
int32_t RTPSender::CheckPayloadType(int8_t payload_type,
@@ -637,8 +653,7 @@
ssrc = ssrc_rtx_;
sequence_number = sequence_number_rtx_;
++sequence_number_rtx_;
- payload_type = ((rtx_ & kRtxRedundantPayloads) > 0) ? payload_type_rtx_
- : payload_type_;
+ payload_type = rtx_payload_type_;
over_rtx = true;
}
}
@@ -1795,8 +1810,8 @@
memcpy(data_buffer_rtx, buffer, rtp_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 (rtx_payload_type_ != -1) {
+ data_buffer_rtx[1] = static_cast<uint8_t>(rtx_payload_type_);
if (rtp_header.markerBit)
data_buffer_rtx[1] |= kRtpMarkerBitMask;
}
diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
index 060dc64..ffe8ce5 100644
--- a/modules/rtp_rtcp/source/rtp_sender.h
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -10,7 +10,6 @@
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_SENDER_H_
-
#include <assert.h>
#include <math.h>
@@ -216,8 +215,8 @@
uint32_t RtxSsrc() const;
void SetRtxSsrc(uint32_t ssrc);
- void SetRtxPayloadType(int payloadType);
- int RtxPayloadType() const;
+ void SetRtxPayloadType(int payload_type, int associated_payload_type);
+ std::pair<int, int> RtxPayloadType() const;
// Functions wrapping RTPSenderInterface.
int32_t BuildRTPheader(uint8_t* data_buffer,
@@ -426,7 +425,11 @@
std::vector<uint32_t> csrcs_ GUARDED_BY(send_critsect_);
int rtx_ GUARDED_BY(send_critsect_);
uint32_t ssrc_rtx_ GUARDED_BY(send_critsect_);
- int payload_type_rtx_ GUARDED_BY(send_critsect_);
+ // TODO(changbin): Remove rtx_payload_type_ once interop with old clients that
+ // only understand one RTX PT is no longer needed.
+ int rtx_payload_type_ GUARDED_BY(send_critsect_);
+ // Mapping rtx_payload_type_map_[associated] = rtx.
+ std::map<int8_t, int8_t> rtx_payload_type_map_ GUARDED_BY(send_critsect_);
// Note: Don't access this variable directly, always go through
// SetTargetBitrateKbps or GetTargetBitrateKbps. Also remember
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 07fc5e3..9b168fe 100644
--- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -36,6 +36,7 @@
const int kAbsoluteSendTimeExtensionId = 14;
const int kTransportSequenceNumberExtensionId = 13;
const int kPayload = 100;
+const int kRtxPayload = 98;
const uint32_t kTimestamp = 10;
const uint16_t kSeqNum = 33;
const int kTimeOffset = 22222;
@@ -822,6 +823,7 @@
rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport, NULL,
&mock_paced_sender_, NULL, NULL, NULL));
rtp_sender_->SetSequenceNumber(kSeqNum);
+ rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
// Make all packets go through the pacer.
EXPECT_CALL(mock_paced_sender_,
SendPacket(PacedSender::kNormalPriority, _, _, _, _, _)).
@@ -1291,7 +1293,7 @@
const uint8_t kPayloadType = 127;
rtp_sender_->SetSSRC(1234);
rtp_sender_->SetRtxSsrc(4321);
- rtp_sender_->SetRtxPayloadType(kPayloadType - 1);
+ rtp_sender_->SetRtxPayloadType(kPayloadType - 1, kPayloadType);
rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
ASSERT_EQ(
diff --git a/modules/rtp_rtcp/test/testAPI/test_api.cc b/modules/rtp_rtcp/test/testAPI/test_api.cc
index 6b4e55d..5731efd 100644
--- a/modules/rtp_rtcp/test/testAPI/test_api.cc
+++ b/modules/rtp_rtcp/test/testAPI/test_api.cc
@@ -174,9 +174,10 @@
TEST_F(RtpRtcpAPITest, RtxReceiver) {
const uint32_t kRtxSsrc = 1;
const int kRtxPayloadType = 119;
+ const int kPayloadType = 100;
EXPECT_FALSE(rtp_payload_registry_->RtxEnabled());
rtp_payload_registry_->SetRtxSsrc(kRtxSsrc);
- rtp_payload_registry_->SetRtxPayloadType(kRtxPayloadType);
+ rtp_payload_registry_->SetRtxPayloadType(kRtxPayloadType, kPayloadType);
EXPECT_TRUE(rtp_payload_registry_->RtxEnabled());
RTPHeader rtx_header;
rtx_header.ssrc = kRtxSsrc;
diff --git a/test/call_test.cc b/test/call_test.cc
index 5d61143..e912982 100644
--- a/test/call_test.cc
+++ b/test/call_test.cc
@@ -160,6 +160,7 @@
const uint8_t CallTest::kFakeSendPayloadType = 125;
const uint8_t CallTest::kSendRtxPayloadType = 98;
const uint8_t CallTest::kRedPayloadType = 118;
+const uint8_t CallTest::kRtxRedPayloadType = 99;
const uint8_t CallTest::kUlpfecPayloadType = 119;
const uint32_t CallTest::kSendRtxSsrcs[kNumSsrcs] = {0xBADCAFD, 0xBADCAFE,
0xBADCAFF};
diff --git a/test/call_test.h b/test/call_test.h
index b8d13c4..ee1bafd 100644
--- a/test/call_test.h
+++ b/test/call_test.h
@@ -37,6 +37,7 @@
static const uint8_t kSendRtxPayloadType;
static const uint8_t kFakeSendPayloadType;
static const uint8_t kRedPayloadType;
+ static const uint8_t kRtxRedPayloadType;
static const uint8_t kUlpfecPayloadType;
static const uint32_t kSendRtxSsrcs[kNumSsrcs];
static const uint32_t kSendSsrcs[kNumSsrcs];
diff --git a/video/end_to_end_tests.cc b/video/end_to_end_tests.cc
index 956e821..389d773 100644
--- a/video/end_to_end_tests.cc
+++ b/video/end_to_end_tests.cc
@@ -71,7 +71,7 @@
}
};
- void DecodesRetransmittedFrame(bool retransmit_over_rtx);
+ void DecodesRetransmittedFrame(bool use_rtx, bool use_red);
void ReceivesPliAndRecovers(int rtp_history_ms);
void RespectsRtcpMode(newapi::RtcpMode rtcp_mode);
void TestXrReceiverReferenceTimeReport(bool enable_rrtr);
@@ -671,16 +671,16 @@
// This test drops second RTP packet with a marker bit set, makes sure it's
// retransmitted and renders. Retransmission SSRCs are also checked.
-void EndToEndTest::DecodesRetransmittedFrame(bool retransmit_over_rtx) {
+void EndToEndTest::DecodesRetransmittedFrame(bool use_rtx, bool use_red) {
static const int kDroppedFrameNumber = 2;
class RetransmissionObserver : public test::EndToEndTest,
public I420FrameCallback {
public:
- explicit RetransmissionObserver(bool expect_rtx)
+ explicit RetransmissionObserver(bool use_rtx, bool use_red)
: EndToEndTest(kDefaultTimeoutMs),
- retransmission_ssrc_(expect_rtx ? kSendRtxSsrcs[0] : kSendSsrcs[0]),
- retransmission_payload_type_(expect_rtx ? kSendRtxPayloadType
- : kFakeSendPayloadType),
+ payload_type_(GetPayloadType(false, use_red)),
+ retransmission_ssrc_(use_rtx ? kSendRtxSsrcs[0] : kSendSsrcs[0]),
+ retransmission_payload_type_(GetPayloadType(use_rtx, use_red)),
marker_bits_observed_(0),
retransmitted_timestamp_(0),
frame_retransmitted_(false) {}
@@ -698,7 +698,7 @@
}
EXPECT_EQ(kSendSsrcs[0], header.ssrc);
- EXPECT_EQ(kFakeSendPayloadType, header.payloadType);
+ EXPECT_EQ(payload_type_, header.payloadType);
// Found the second frame's final packet, drop this and expect a
// retransmission.
@@ -724,12 +724,20 @@
send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
(*receive_configs)[0].pre_render_callback = this;
(*receive_configs)[0].rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
+
+ if (payload_type_ == kRedPayloadType) {
+ send_config->rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
+ send_config->rtp.fec.red_payload_type = kRedPayloadType;
+ (*receive_configs)[0].rtp.fec.red_payload_type = kRedPayloadType;
+ (*receive_configs)[0].rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
+ }
+
if (retransmission_ssrc_ == kSendRtxSsrcs[0]) {
send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
- (*receive_configs)[0].rtp.rtx[kSendRtxPayloadType].ssrc =
+ (*receive_configs)[0].rtp.rtx[kFakeSendPayloadType].ssrc =
kSendRtxSsrcs[0];
- (*receive_configs)[0].rtp.rtx[kSendRtxPayloadType].payload_type =
+ (*receive_configs)[0].rtp.rtx[kFakeSendPayloadType].payload_type =
kSendRtxPayloadType;
}
}
@@ -739,22 +747,36 @@
<< "Timed out while waiting for retransmission to render.";
}
+ int GetPayloadType(bool use_rtx, bool use_red) {
+ return use_rtx ? kSendRtxPayloadType
+ : (use_red ? kRedPayloadType : kFakeSendPayloadType);
+ }
+
+ const int payload_type_;
const uint32_t retransmission_ssrc_;
const int retransmission_payload_type_;
int marker_bits_observed_;
uint32_t retransmitted_timestamp_;
bool frame_retransmitted_;
- } test(retransmit_over_rtx);
+ } test(use_rtx, use_red);
RunBaseTest(&test);
}
TEST_F(EndToEndTest, DecodesRetransmittedFrame) {
- DecodesRetransmittedFrame(false);
+ DecodesRetransmittedFrame(false, false);
}
TEST_F(EndToEndTest, DecodesRetransmittedFrameOverRtx) {
- DecodesRetransmittedFrame(true);
+ DecodesRetransmittedFrame(true, false);
+}
+
+TEST_F(EndToEndTest, DecodesRetransmittedFrameByRed) {
+ DecodesRetransmittedFrame(false, true);
+}
+
+TEST_F(EndToEndTest, DecodesRetransmittedFrameByRedOverRtx) {
+ DecodesRetransmittedFrame(true, true);
}
TEST_F(EndToEndTest, UsesFrameCallbacks) {
@@ -2589,5 +2611,4 @@
call->DestroyVideoReceiveStream(receive_stream);
}
}
-
} // namespace webrtc
diff --git a/video/loopback.cc b/video/loopback.cc
index 9ef0ec4..881fa49 100644
--- a/video/loopback.cc
+++ b/video/loopback.cc
@@ -39,7 +39,8 @@
static const uint32_t kSendRtxSsrc = 0x654322;
static const uint32_t kReceiverLocalSsrc = 0x123456;
-static const uint8_t kRtxPayloadType = 96;
+static const uint8_t kRtxVideoPayloadType = 96;
+static const uint8_t kVideoPayloadType = 124;
Loopback::Loopback(const Config& config)
: config_(config), clock_(Clock::GetRealTimeClock()) {
@@ -83,7 +84,7 @@
VideoSendStream::Config send_config;
send_config.rtp.ssrcs.push_back(kSendSsrc);
send_config.rtp.rtx.ssrcs.push_back(kSendRtxSsrc);
- send_config.rtp.rtx.payload_type = kRtxPayloadType;
+ send_config.rtp.rtx.payload_type = kRtxVideoPayloadType;
send_config.rtp.nack.rtp_history_ms = 1000;
send_config.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
@@ -101,7 +102,7 @@
}
send_config.encoder_settings.encoder = encoder.get();
send_config.encoder_settings.payload_name = config_.codec;
- send_config.encoder_settings.payload_type = 124;
+ send_config.encoder_settings.payload_type = kVideoPayloadType;
VideoEncoderConfig encoder_config(CreateEncoderConfig());
@@ -114,8 +115,8 @@
receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0];
receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
receive_config.rtp.nack.rtp_history_ms = 1000;
- receive_config.rtp.rtx[kRtxPayloadType].ssrc = kSendRtxSsrc;
- receive_config.rtp.rtx[kRtxPayloadType].payload_type = kRtxPayloadType;
+ receive_config.rtp.rtx[kVideoPayloadType].ssrc = kSendRtxSsrc;
+ receive_config.rtp.rtx[kVideoPayloadType].payload_type = kRtxVideoPayloadType;
receive_config.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
receive_config.renderer = loopback_video.get();
diff --git a/video/rampup_tests.cc b/video/rampup_tests.cc
index 7d8f981..4ba4cba 100644
--- a/video/rampup_tests.cc
+++ b/video/rampup_tests.cc
@@ -77,6 +77,8 @@
remote_bitrate_estimator_.reset(
rbe_factory->Create(this, clock, control_type,
kRemoteBitrateEstimatorMinBitrateBps));
+ payload_registry_->SetRtxPayloadType(RampUpTest::kSendRtxPayloadType,
+ RampUpTest::kFakeSendPayloadType);
}
void StreamObserver::set_expected_bitrate_bps(
@@ -137,11 +139,9 @@
uint8_t restored_packet[kMaxPacketSize];
uint8_t* restored_packet_ptr = restored_packet;
size_t restored_length = length;
- payload_registry_->RestoreOriginalPacket(&restored_packet_ptr,
- packet,
- &restored_length,
- rtx_media_ssrcs_[header.ssrc],
- header);
+ EXPECT_TRUE(payload_registry_->RestoreOriginalPacket(
+ &restored_packet_ptr, packet, &restored_length,
+ rtx_media_ssrcs_[header.ssrc], header));
length = restored_length;
EXPECT_TRUE(rtp_parser_->Parse(
restored_packet, static_cast<int>(length), &header));
@@ -367,10 +367,11 @@
return test_done_->Wait(test::CallTest::kLongTimeoutMs);
}
-void RampUpTest::RunRampUpTest(bool rtx,
- size_t num_streams,
+void RampUpTest::RunRampUpTest(size_t num_streams,
unsigned int start_bitrate_bps,
- const std::string& extension_type) {
+ const std::string& extension_type,
+ bool rtx,
+ bool red) {
std::vector<uint32_t> ssrcs(GenerateSsrcs(num_streams, 100));
std::vector<uint32_t> rtx_ssrcs(GenerateSsrcs(num_streams, 200));
StreamObserver::SsrcMap rtx_ssrc_map;
@@ -424,6 +425,10 @@
send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
send_config_.rtp.rtx.ssrcs = rtx_ssrcs;
}
+ if (red) {
+ send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
+ send_config_.rtp.fec.red_payload_type = kRedPayloadType;
+ }
if (num_streams == 1) {
// For single stream rampup until 1mbps
@@ -450,7 +455,9 @@
DestroyStreams();
}
-void RampUpTest::RunRampUpDownUpTest(size_t number_of_streams, bool rtx) {
+void RampUpTest::RunRampUpDownUpTest(size_t number_of_streams,
+ bool rtx,
+ bool red) {
test::DirectTransport receiver_transport;
LowRateStreamObserver stream_observer(
&receiver_transport, Clock::GetRealTimeClock(), number_of_streams, rtx);
@@ -469,6 +476,10 @@
send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
send_config_.rtp.rtx.ssrcs = GenerateSsrcs(number_of_streams, 200);
}
+ if (red) {
+ send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
+ send_config_.rtp.fec.red_payload_type = kRedPayloadType;
+ }
CreateStreams();
stream_observer.SetSendStream(send_stream_);
@@ -484,43 +495,68 @@
}
TEST_F(RampUpTest, SingleStream) {
- RunRampUpTest(false, 1, 0, RtpExtension::kTOffset);
+ RunRampUpTest(1, 0, RtpExtension::kTOffset, false, false);
}
TEST_F(RampUpTest, Simulcast) {
- RunRampUpTest(false, 3, 0, RtpExtension::kTOffset);
+ RunRampUpTest(3, 0, RtpExtension::kTOffset, false, false);
}
TEST_F(RampUpTest, SimulcastWithRtx) {
- RunRampUpTest(true, 3, 0, RtpExtension::kTOffset);
+ RunRampUpTest(3, 0, RtpExtension::kTOffset, true, false);
+}
+
+TEST_F(RampUpTest, SimulcastByRedWithRtx) {
+ RunRampUpTest(3, 0, RtpExtension::kTOffset, true, true);
}
TEST_F(RampUpTest, SingleStreamWithHighStartBitrate) {
- RunRampUpTest(false, 1, 0.9 * kSingleStreamTargetBps, RtpExtension::kTOffset);
+ RunRampUpTest(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kTOffset, false,
+ false);
}
-TEST_F(RampUpTest, UpDownUpOneStream) { RunRampUpDownUpTest(1, false); }
+TEST_F(RampUpTest, UpDownUpOneStream) {
+ RunRampUpDownUpTest(1, false, false);
+}
-TEST_F(RampUpTest, UpDownUpThreeStreams) { RunRampUpDownUpTest(3, false); }
+TEST_F(RampUpTest, UpDownUpThreeStreams) {
+ RunRampUpDownUpTest(3, false, false);
+}
-TEST_F(RampUpTest, UpDownUpOneStreamRtx) { RunRampUpDownUpTest(1, true); }
+TEST_F(RampUpTest, UpDownUpOneStreamRtx) {
+ RunRampUpDownUpTest(1, true, false);
+}
-TEST_F(RampUpTest, UpDownUpThreeStreamsRtx) { RunRampUpDownUpTest(3, true); }
+TEST_F(RampUpTest, UpDownUpThreeStreamsRtx) {
+ RunRampUpDownUpTest(3, true, false);
+}
+
+TEST_F(RampUpTest, UpDownUpOneStreamByRedRtx) {
+ RunRampUpDownUpTest(1, true, true);
+}
+
+TEST_F(RampUpTest, UpDownUpThreeStreamsByRedRtx) {
+ RunRampUpDownUpTest(3, true, true);
+}
TEST_F(RampUpTest, AbsSendTimeSingleStream) {
- RunRampUpTest(false, 1, 0, RtpExtension::kAbsSendTime);
+ RunRampUpTest(1, 0, RtpExtension::kAbsSendTime, false, false);
}
TEST_F(RampUpTest, AbsSendTimeSimulcast) {
- RunRampUpTest(false, 3, 0, RtpExtension::kAbsSendTime);
+ RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, false, false);
}
TEST_F(RampUpTest, AbsSendTimeSimulcastWithRtx) {
- RunRampUpTest(true, 3, 0, RtpExtension::kAbsSendTime);
+ RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, true, false);
+}
+
+TEST_F(RampUpTest, AbsSendTimeSimulcastByRedWithRtx) {
+ RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, true, true);
}
TEST_F(RampUpTest, AbsSendTimeSingleStreamWithHighStartBitrate) {
- RunRampUpTest(false, 1, 0.9 * kSingleStreamTargetBps,
- RtpExtension::kAbsSendTime);
+ RunRampUpTest(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kAbsSendTime,
+ false, false);
}
} // namespace webrtc
diff --git a/video/rampup_tests.h b/video/rampup_tests.h
index 4335fc1..ed0d795 100644
--- a/video/rampup_tests.h
+++ b/video/rampup_tests.h
@@ -147,12 +147,13 @@
class RampUpTest : public test::CallTest {
protected:
- void RunRampUpTest(bool rtx,
- size_t num_streams,
+ void RunRampUpTest(size_t num_streams,
unsigned int start_bitrate_bps,
- const std::string& extension_type);
+ const std::string& extension_type,
+ bool rtx,
+ bool red);
- void RunRampUpDownUpTest(size_t number_of_streams, bool rtx);
+ void RunRampUpDownUpTest(size_t number_of_streams, bool rtx, bool red);
};
} // namespace webrtc
#endif // WEBRTC_VIDEO_RAMPUP_TESTS_H_
diff --git a/video/video_receive_stream.cc b/video/video_receive_stream.cc
index a8dea5e..fd04079 100644
--- a/video/video_receive_stream.cc
+++ b/video/video_receive_stream.cc
@@ -164,12 +164,12 @@
vie_channel_->SetSSRC(config_.rtp.local_ssrc, kViEStreamTypeNormal, 0);
// TODO(pbos): Support multiple RTX, per video payload.
Config::Rtp::RtxMap::const_iterator it = config_.rtp.rtx.begin();
- if (it != config_.rtp.rtx.end()) {
+ for (; it != config_.rtp.rtx.end(); ++it) {
DCHECK(it->second.ssrc != 0);
DCHECK(it->second.payload_type != 0);
vie_channel_->SetRemoteSSRCType(kViEStreamTypeRtx, it->second.ssrc);
- vie_channel_->SetRtxReceivePayloadType(it->second.payload_type);
+ vie_channel_->SetRtxReceivePayloadType(it->second.payload_type, it->first);
}
// TODO(pbos): Remove channel_group_ usage from VideoReceiveStream. This
@@ -212,6 +212,11 @@
strcpy(codec.plName, "red");
codec.plType = config_.rtp.fec.red_payload_type;
CHECK_EQ(0, vie_channel_->SetReceiveCodec(codec));
+ if (config_.rtp.fec.red_rtx_payload_type != -1) {
+ vie_channel_->SetRtxReceivePayloadType(
+ config_.rtp.fec.red_rtx_payload_type,
+ config_.rtp.fec.red_payload_type);
+ }
}
if (config.rtp.rtcp_xr.receiver_reference_time_report)
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index 9949f50..59111fa 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -163,6 +163,7 @@
static_cast<unsigned char>(config_.rtp.fec.red_payload_type),
static_cast<unsigned char>(config_.rtp.fec.ulpfec_payload_type));
}
+ // TODO(changbin): Should set RTX for RED mapping in RTP sender in future.
} else {
rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
}
@@ -460,7 +461,8 @@
}
DCHECK_GE(config_.rtp.rtx.payload_type, 0);
- rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type);
+ rtp_rtcp_->SetRtxSendPayloadType(channel_, config_.rtp.rtx.payload_type,
+ config_.encoder_settings.payload_type);
}
std::map<uint32_t, RtpState> VideoSendStream::GetRtpStates() const {
diff --git a/video_engine/include/vie_rtp_rtcp.h b/video_engine/include/vie_rtp_rtcp.h
index a57e4f3..7b72b80 100644
--- a/video_engine/include/vie_rtp_rtcp.h
+++ b/video_engine/include/vie_rtp_rtcp.h
@@ -114,10 +114,13 @@
// 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;
+ const uint8_t payload_type,
+ const uint8_t associated_payload_type) = 0;
- virtual int SetRtxReceivePayloadType(const int video_channel,
- const uint8_t payload_type) = 0;
+ virtual int SetRtxReceivePayloadType(
+ const int video_channel,
+ const uint8_t payload_type,
+ const uint8_t associated_payload_type) = 0;
// This function enables manual initialization of the sequence number. The
// start sequence number is normally a random number.
diff --git a/video_engine/test/auto_test/source/vie_autotest_loopback.cc b/video_engine/test/auto_test/source/vie_autotest_loopback.cc
index ffc9757..52cf078 100644
--- a/video_engine/test/auto_test/source/vie_autotest_loopback.cc
+++ b/video_engine/test/auto_test/source/vie_autotest_loopback.cc
@@ -40,6 +40,7 @@
const uint32_t kSsrc = 0x01234567;
const uint32_t kRtxSsrc = 0x01234568;
const int kRtxPayloadType = 98;
+const int kPayloadType = 100;
#define VCM_RED_PAYLOAD_TYPE 96
#define VCM_ULPFEC_PAYLOAD_TYPE 97
@@ -244,14 +245,15 @@
return -1;
}
- error = ptrViERtpRtcp->SetRtxSendPayloadType(videoChannel, kRtxPayloadType);
+ error = ptrViERtpRtcp->SetRtxSendPayloadType(videoChannel, kRtxPayloadType,
+ kPayloadType);
if (error == -1) {
printf("ERROR in ViERTP_RTCP::SetRtxSendPayloadType\n");
return -1;
}
- error = ptrViERtpRtcp->SetRtxReceivePayloadType(videoChannel,
- kRtxPayloadType);
+ error = ptrViERtpRtcp->SetRtxReceivePayloadType(
+ videoChannel, kRtxPayloadType, kPayloadType);
if (error == -1) {
printf("ERROR in ViERTP_RTCP::SetRtxReceivePayloadType\n");
return -1;
diff --git a/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc b/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc
index 47dbae4..ee9c6a0 100644
--- a/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc
+++ b/video_engine/test/auto_test/source/vie_autotest_rtp_rtcp.cc
@@ -172,14 +172,15 @@
myTransport.ClearStats();
const uint8_t kRtxPayloadType = 96;
+ const uint8_t kPayloadType = 100;
// Temporarily disable pacing.
EXPECT_EQ(0, ViE.rtp_rtcp->SetTransmissionSmoothingStatus(
tbChannel.videoChannel, false));
EXPECT_EQ(0, ViE.rtp_rtcp->SetNACKStatus(tbChannel.videoChannel, true));
- EXPECT_EQ(0, ViE.rtp_rtcp->SetRtxSendPayloadType(tbChannel.videoChannel,
- kRtxPayloadType));
- EXPECT_EQ(0, ViE.rtp_rtcp->SetRtxReceivePayloadType(tbChannel.videoChannel,
- kRtxPayloadType));
+ EXPECT_EQ(0, ViE.rtp_rtcp->SetRtxSendPayloadType(
+ tbChannel.videoChannel, kRtxPayloadType, kPayloadType));
+ EXPECT_EQ(0, ViE.rtp_rtcp->SetRtxReceivePayloadType(
+ tbChannel.videoChannel, kRtxPayloadType, kPayloadType));
EXPECT_EQ(0, ViE.rtp_rtcp->SetLocalSSRC(tbChannel.videoChannel, 1234,
webrtc::kViEStreamTypeRtx, 0));
EXPECT_EQ(0, ViE.rtp_rtcp->SetRemoteSSRCType(tbChannel.videoChannel,
diff --git a/video_engine/vie_channel.cc b/video_engine/vie_channel.cc
index 353dc12..935e885 100644
--- a/video_engine/vie_channel.cc
+++ b/video_engine/vie_channel.cc
@@ -428,7 +428,10 @@
}
rtp_rtcp->SetSendingStatus(rtp_rtcp_->Sending());
rtp_rtcp->SetSendingMediaStatus(rtp_rtcp_->SendingMedia());
- rtp_rtcp->SetRtxSendPayloadType(rtp_rtcp_->RtxSendPayloadType());
+ std::pair<int, int> payload_type_value =
+ rtp_rtcp_->RtxSendPayloadType();
+ rtp_rtcp->SetRtxSendPayloadType(payload_type_value.first,
+ payload_type_value.second);
rtp_rtcp->SetRtxSendStatus(rtp_rtcp_->RtxSendStatus());
simulcast_rtp_rtcp_.push_back(rtp_rtcp);
@@ -1038,11 +1041,13 @@
return 0;
}
-int ViEChannel::SetRtxSendPayloadType(int payload_type) {
- rtp_rtcp_->SetRtxSendPayloadType(payload_type);
+int ViEChannel::SetRtxSendPayloadType(int payload_type,
+ int associated_payload_type) {
+ rtp_rtcp_->SetRtxSendPayloadType(payload_type, associated_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);
+ (*it)->SetRtxSendPayloadType(payload_type, associated_payload_type);
}
SetRtxSendStatus(true);
return 0;
@@ -1059,8 +1064,9 @@
}
}
-void ViEChannel::SetRtxReceivePayloadType(int payload_type) {
- vie_receiver_.SetRtxPayloadType(payload_type);
+void ViEChannel::SetRtxReceivePayloadType(int payload_type,
+ int associated_payload_type) {
+ vie_receiver_.SetRtxPayloadType(payload_type, associated_payload_type);
}
int32_t ViEChannel::SetStartSequenceNumber(uint16_t sequence_number) {
diff --git a/video_engine/vie_channel.h b/video_engine/vie_channel.h
index a3ad722..4bd27de 100644
--- a/video_engine/vie_channel.h
+++ b/video_engine/vie_channel.h
@@ -154,8 +154,8 @@
// Gets the CSRC for the incoming stream.
int32_t GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]);
- int SetRtxSendPayloadType(int payload_type);
- void SetRtxReceivePayloadType(int payload_type);
+ int SetRtxSendPayloadType(int payload_type, int associated_payload_type);
+ void SetRtxReceivePayloadType(int payload_type, int associated_payload_type);
// Sets the starting sequence number, must be called before StartSend.
int32_t SetStartSequenceNumber(uint16_t sequence_number);
diff --git a/video_engine/vie_receiver.cc b/video_engine/vie_receiver.cc
index e61c82b..0fe12b4 100644
--- a/video_engine/vie_receiver.cc
+++ b/video_engine/vie_receiver.cc
@@ -119,8 +119,10 @@
rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
}
-void ViEReceiver::SetRtxPayloadType(int payload_type) {
- rtp_payload_registry_->SetRtxPayloadType(payload_type);
+void ViEReceiver::SetRtxPayloadType(int payload_type,
+ int associated_payload_type) {
+ rtp_payload_registry_->SetRtxPayloadType(payload_type,
+ associated_payload_type);
}
void ViEReceiver::SetRtxSsrc(uint32_t ssrc) {
diff --git a/video_engine/vie_receiver.h b/video_engine/vie_receiver.h
index 5c09a3e..0a52293 100644
--- a/video_engine/vie_receiver.h
+++ b/video_engine/vie_receiver.h
@@ -47,7 +47,7 @@
bool RegisterPayload(const VideoCodec& video_codec);
void SetNackStatus(bool enable, int max_nack_reordering_threshold);
- void SetRtxPayloadType(int payload_type);
+ void SetRtxPayloadType(int payload_type, int associated_payload_type);
void SetRtxSsrc(uint32_t ssrc);
bool GetRtxSsrc(uint32_t* ssrc) const;
diff --git a/video_engine/vie_rtp_rtcp_impl.cc b/video_engine/vie_rtp_rtcp_impl.cc
index 4fbf11b..9b2a439 100644
--- a/video_engine/vie_rtp_rtcp_impl.cc
+++ b/video_engine/vie_rtp_rtcp_impl.cc
@@ -191,8 +191,10 @@
return 0;
}
-int ViERTP_RTCPImpl::SetRtxSendPayloadType(const int video_channel,
- const uint8_t payload_type) {
+int ViERTP_RTCPImpl::SetRtxSendPayloadType(
+ const int video_channel,
+ const uint8_t payload_type,
+ const uint8_t associated_payload_type) {
LOG_F(LS_INFO) << "channel: " << video_channel
<< " payload_type: " << static_cast<int>(payload_type);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
@@ -201,14 +203,17 @@
shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
return -1;
}
- if (vie_channel->SetRtxSendPayloadType(payload_type) != 0) {
+ if (vie_channel->SetRtxSendPayloadType(payload_type,
+ associated_payload_type) != 0) {
return -1;
}
return 0;
}
-int ViERTP_RTCPImpl::SetRtxReceivePayloadType(const int video_channel,
- const uint8_t payload_type) {
+int ViERTP_RTCPImpl::SetRtxReceivePayloadType(
+ const int video_channel,
+ const uint8_t payload_type,
+ const uint8_t associated_payload_type) {
LOG_F(LS_INFO) << "channel: " << video_channel
<< " payload_type: " << static_cast<int>(payload_type);
ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
@@ -217,7 +222,7 @@
shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
return -1;
}
- vie_channel->SetRtxReceivePayloadType(payload_type);
+ vie_channel->SetRtxReceivePayloadType(payload_type, associated_payload_type);
return 0;
}
diff --git a/video_engine/vie_rtp_rtcp_impl.h b/video_engine/vie_rtp_rtcp_impl.h
index 7894f59..e22747f 100644
--- a/video_engine/vie_rtp_rtcp_impl.h
+++ b/video_engine/vie_rtp_rtcp_impl.h
@@ -40,9 +40,11 @@
virtual int GetRemoteCSRCs(const int video_channel,
unsigned int CSRCs[kRtpCsrcSize]) const;
virtual int SetRtxSendPayloadType(const int video_channel,
- const uint8_t payload_type);
+ const uint8_t payload_type,
+ const uint8_t associated_payload_type);
virtual int SetRtxReceivePayloadType(const int video_channel,
- const uint8_t payload_type);
+ const uint8_t payload_type,
+ const uint8_t associated_payload_type);
virtual int SetStartSequenceNumber(const int video_channel,
uint16_t sequence_number);
void SetRtpStateForSsrc(int video_channel,