Support associated payload type when registering Rtx payload type.

Major changes include,
- Add associated payload type for SetRtxSendPayloadType & SetRtxReceivePayloadType.
- Receiver: Restore RTP packets by the new RTX-APT map.
- Sender: Send RTP packets by checking RTX-APT map.
- Add RTX payload type for RED in the default codec list.

BUG=4024
R=pbos@webrtc.org, stefan@webrtc.org
TBR=mflodman@webrtc.org

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

Patch from Changbin Shao <changbin.shao@intel.com>.

git-svn-id: http://webrtc.googlecode.com/svn/trunk@8028 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org
2015-01-09 15:16:10 +00:00
parent 8649fed1b8
commit 2a169640a3
39 changed files with 401 additions and 207 deletions

View File

@ -79,7 +79,7 @@ class RTPPayloadRegistry {
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,8 @@ class RTPPayloadRegistry {
int8_t last_received_payload_type_;
int8_t last_received_media_payload_type_;
bool rtx_;
int8_t payload_type_rtx_;
// Mapping rtx_apt_types_[rtx] = apt.
std::map<int, int> rtx_apt_types_;
uint32_t ssrc_rtx_;
};

View File

@ -228,7 +228,8 @@ class RtpRtcp : public Module {
// 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;
/*
* Get status of sending RTX (RFC 4588) on a specific SSRC.

View File

@ -101,8 +101,7 @@ class MockRtpRtcp : public RtpRtcp {
void(int* modes, uint32_t* ssrc, int* payload_type));
MOCK_METHOD1(SetRtxSsrc,
void(uint32_t));
MOCK_METHOD1(SetRtxSendPayloadType,
void(int));
MOCK_METHOD2(SetRtxSendPayloadType, void(int, int));
MOCK_METHOD1(SetSendingStatus,
int32_t(const bool sending));
MOCK_CONST_METHOD0(Sending,

View File

@ -32,6 +32,8 @@ const uint16_t kTestSequenceNumber = 2345;
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
{
@ -206,15 +208,17 @@ class RtpRtcpRtxNackTest : public ::testing::Test {
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;
@ -265,12 +269,9 @@ class RtpRtcpRtxNackTest : public ::testing::Test {
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));
int length = BuildNackList(nack_list);
if (length > 0)
rtp_rtcp_module_->SendNACK(nack_list, length);
@ -313,12 +314,9 @@ TEST_F(RtpRtcpRtxNackTest, LongNackList) {
// 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);

View File

@ -24,7 +24,6 @@ RTPPayloadRegistry::RTPPayloadRegistry(
last_received_payload_type_(-1),
last_received_media_payload_type_(-1),
rtx_(false),
payload_type_rtx_(-1),
ssrc_rtx_(0) {}
RTPPayloadRegistry::~RTPPayloadRegistry() {
@ -264,19 +263,25 @@ bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t** restored_packet,
RtpUtility::AssignUWord32ToBuffer(*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_apt_types_.empty()) {
LOG(LS_WARNING) << "No RTX is set, dropping packet.";
return false;
}
std::map<int, int>::const_iterator it =
rtx_apt_types_.find(header.payloadType);
if (it != rtx_apt_types_.end()) {
(*restored_packet)[1] = static_cast<uint8_t>(it->second);
if (header.markerBit) {
(*restored_packet)[1] |= kRtpMarkerBitMask; // Marker bit is set.
}
} else {
LOG(LS_WARNING) << "Incorrect RTX configuration, dropping packet.";
return false;
}
return true;
}
@ -292,10 +297,12 @@ bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
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;
assert(associated_payload_type >= 0);
rtx_apt_types_[payload_type] = associated_payload_type;
rtx_ = true;
}

View File

@ -257,8 +257,9 @@ void ModuleRtpRtcpImpl::SetRtxSsrc(uint32_t ssrc) {
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);
}
int32_t ModuleRtpRtcpImpl::IncomingRtcpPacket(

View File

@ -94,7 +94,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
virtual void SetRtxSsrc(uint32_t ssrc) OVERRIDE;
virtual void SetRtxSendPayloadType(int payload_type) OVERRIDE;
virtual void SetRtxSendPayloadType(int payload_type,
int associated_payload_type) OVERRIDE;
// Sends kRtcpByeCode when going from true to false.
virtual int32_t SetSendingStatus(bool sending) OVERRIDE;

View File

@ -691,7 +691,7 @@ TEST_F(RtpSendingTest, DISABLED_RoundRobinPaddingRtx) {
// as otherwise the timestmap used for BWE will be broken.
senders_[i]->RegisterSendRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
1);
senders_[i]->SetRtxSendPayloadType(96);
senders_[i]->SetRtxSendPayloadType(96, 100);
senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i);
senders_[i]->SetRTXSendStatus(kRtxRetransmitted);
}
@ -716,7 +716,7 @@ TEST_F(RtpSendingTest, DISABLED_RoundRobinPaddingRtx) {
TEST_F(RtpSendingTest, DISABLED_RoundRobinPaddingRtxRedundantPayloads) {
for (int i = 1; i < codec_.numberOfSimulcastStreams + 1; ++i) {
senders_[i]->SetRtxSendPayloadType(96);
senders_[i]->SetRtxSendPayloadType(96, 100);
senders_[i]->SetRtxSsrc(kSenderRtxSsrc + i);
senders_[i]->SetRTXSendStatus(kRtxRetransmitted | kRtxRedundantPayloads);
senders_[i]->SetStorePacketsStatus(true, 100);

View File

@ -147,7 +147,6 @@ RTPSender::RTPSender(int32_t id,
last_packet_marker_bit_(false),
csrcs_(),
rtx_(kRtxOff),
payload_type_rtx_(-1),
target_bitrate_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
target_bitrate_(0) {
memset(nack_byte_count_times_, 0, sizeof(nack_byte_count_times_));
@ -403,12 +402,17 @@ void RTPSender::RTXStatus(int* mode, uint32_t* ssrc,
CriticalSectionScoped cs(send_critsect_);
*mode = rtx_;
*ssrc = ssrc_rtx_;
*payload_type = payload_type_rtx_;
std::map<int, int>::const_iterator it = apt_rtx_types_.find(payload_type_);
*payload_type = (it == apt_rtx_types_.end()) ? -1 : it->second;
}
void RTPSender::SetRtxPayloadType(int payload_type) {
void RTPSender::SetRtxPayloadType(int payload_type,
int associated_payload_type) {
CriticalSectionScoped cs(send_critsect_);
payload_type_rtx_ = payload_type;
assert(payload_type >= 0);
assert(associated_payload_type >= 0);
apt_rtx_types_[associated_payload_type] = payload_type;
}
int32_t RTPSender::CheckPayloadType(int8_t payload_type,
@ -610,8 +614,14 @@ size_t RTPSender::SendPadData(uint32_t timestamp,
ssrc = ssrc_rtx_;
sequence_number = sequence_number_rtx_;
++sequence_number_rtx_;
payload_type = ((rtx_ & kRtxRedundantPayloads) > 0) ? payload_type_rtx_
: payload_type_;
if (apt_rtx_types_.empty())
return 0;
std::map<int, int>::const_iterator it =
apt_rtx_types_.find(payload_type_);
payload_type = it != apt_rtx_types_.end()
? it->second
: apt_rtx_types_.begin()->second;
over_rtx = true;
}
}
@ -1660,9 +1670,10 @@ void RTPSender::BuildRtxPacket(uint8_t* buffer, size_t* length,
// Add original RTP header.
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_);
std::map<int, int>::const_iterator it =
apt_rtx_types_.find(rtp_header.payloadType);
if (it != apt_rtx_types_.end()) {
data_buffer_rtx[1] = static_cast<uint8_t>(it->second);
if (rtp_header.markerBit)
data_buffer_rtx[1] |= kRtpMarkerBitMask;
}

View File

@ -191,7 +191,7 @@ class RTPSender : public RTPSenderInterface {
uint32_t RtxSsrc() const;
void SetRtxSsrc(uint32_t ssrc);
void SetRtxPayloadType(int payloadType);
void SetRtxPayloadType(int payloadType, int associated_payload_type);
// Functions wrapping RTPSenderInterface.
virtual int32_t BuildRTPheader(
@ -391,7 +391,8 @@ class RTPSender : public RTPSenderInterface {
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_);
// Mapping apt_rtx_types_[apt] = rtx.
std::map<int, int> apt_rtx_types_ GUARDED_BY(send_critsect_);
// Note: Don't access this variable directly, always go through
// SetTargetBitrateKbps or GetTargetBitrateKbps. Also remember

View File

@ -30,6 +30,7 @@ namespace {
const int kTransmissionTimeOffsetExtensionId = 1;
const int kAbsoluteSendTimeExtensionId = 14;
const int kPayload = 100;
const int kRtxPayload = 98;
const uint32_t kTimestamp = 10;
const uint16_t kSeqNum = 33;
const int kTimeOffset = 22222;
@ -654,6 +655,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) {
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, _, _, _, _, _)).
@ -1123,7 +1125,7 @@ TEST_F(RtpSenderTest, BytesReportedCorrectly) {
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(

View File

@ -106,33 +106,31 @@ TEST_F(RtpRtcpAPITest, RtxSender) {
unsigned int ssrc = 0;
int rtx_mode = kRtxOff;
const int kRtxPayloadType = 119;
int payload_type = -1;
const int kPayloadType = 100;
module->SetRTXSendStatus(kRtxRetransmitted);
module->SetRtxSendPayloadType(kRtxPayloadType);
module->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType);
module->SetRtxSsrc(1);
int payload_type;
module->RTXSendStatus(&rtx_mode, &ssrc, &payload_type);
EXPECT_EQ(kRtxRetransmitted, rtx_mode);
EXPECT_EQ(1u, ssrc);
EXPECT_EQ(kRtxPayloadType, payload_type);
rtx_mode = kRtxOff;
module->SetRTXSendStatus(kRtxOff);
payload_type = -1;
module->SetRtxSendPayloadType(kRtxPayloadType);
module->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType);
module->RTXSendStatus(&rtx_mode, &ssrc, &payload_type);
EXPECT_EQ(kRtxOff, rtx_mode);
EXPECT_EQ(kRtxPayloadType, payload_type);
module->SetRTXSendStatus(kRtxRetransmitted);
module->RTXSendStatus(&rtx_mode, &ssrc, &payload_type);
EXPECT_EQ(kRtxRetransmitted, rtx_mode);
EXPECT_EQ(kRtxPayloadType, payload_type);
}
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;