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:
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user