Fixes RTX related bugs.

- An RTX packet with no payload should be dropped prior to parsing RTX header since it doesn't have an RTX header. This can for example happen when sending padding-only packets over the RTX stream.
- The retransmit code path when the pacer is disabled doesn't properly update the abs-send-time and ts-offset header extensions.

TEST=trybots
R=mflodman@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5728 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2014-03-19 18:14:52 +00:00
parent 9af85c4ac2
commit 7c6ff2da26
3 changed files with 25 additions and 30 deletions

View File

@ -458,7 +458,7 @@ int RTPSender::SendRedundantPayloads(int payload_type, int bytes_to_send) {
&capture_time_ms)) { &capture_time_ms)) {
break; break;
} }
if (!PrepareAndSendPacket(buffer, length, capture_time_ms, true)) if (!PrepareAndSendPacket(buffer, length, capture_time_ms, true, false))
return -1; return -1;
ModuleRTPUtility::RTPHeaderParser rtp_parser(buffer, length); ModuleRTPUtility::RTPHeaderParser rtp_parser(buffer, length);
RTPHeader rtp_header; RTPHeader rtp_header;
@ -598,7 +598,6 @@ bool RTPSender::StorePackets() const {
int32_t RTPSender::ReSendPacket(uint16_t packet_id, uint32_t min_resend_time) { int32_t RTPSender::ReSendPacket(uint16_t packet_id, uint32_t min_resend_time) {
uint16_t length = IP_PACKET_SIZE; uint16_t length = IP_PACKET_SIZE;
uint8_t data_buffer[IP_PACKET_SIZE]; uint8_t data_buffer[IP_PACKET_SIZE];
uint8_t *buffer_to_send_ptr = data_buffer;
int64_t capture_time_ms; int64_t capture_time_ms;
if (!packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true, if (!packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true,
data_buffer, &length, data_buffer, &length,
@ -607,19 +606,15 @@ int32_t RTPSender::ReSendPacket(uint16_t packet_id, uint32_t min_resend_time) {
return 0; return 0;
} }
ModuleRTPUtility::RTPHeaderParser rtp_parser(data_buffer, length);
RTPHeader header;
if (!rtp_parser.Parse(header)) {
assert(false);
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
"Failed to parse RTP header of packet to be retransmitted.");
return -1;
}
TRACE_EVENT_INSTANT2("webrtc_rtp", "RTPSender::ReSendPacket",
"timestamp", header.timestamp,
"seqnum", header.sequenceNumber);
if (paced_sender_) { if (paced_sender_) {
ModuleRTPUtility::RTPHeaderParser rtp_parser(data_buffer, length);
RTPHeader header;
if (!rtp_parser.Parse(header)) {
assert(false);
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, id_,
"Failed to parse RTP header of packet to be retransmitted.");
return -1;
}
if (!paced_sender_->SendPacket(PacedSender::kHighPriority, if (!paced_sender_->SendPacket(PacedSender::kHighPriority,
header.ssrc, header.ssrc,
header.sequenceNumber, header.sequenceNumber,
@ -632,17 +627,8 @@ int32_t RTPSender::ReSendPacket(uint16_t packet_id, uint32_t min_resend_time) {
} }
} }
uint8_t data_buffer_rtx[IP_PACKET_SIZE]; return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
if ((rtx_ & kRtxRetransmitted) > 0) { (rtx_ & kRtxRetransmitted) > 0, true) ? 0 : -1;
BuildRtxPacket(data_buffer, &length, data_buffer_rtx);
buffer_to_send_ptr = data_buffer_rtx;
}
if (SendPacketToNetwork(buffer_to_send_ptr, length)) {
UpdateRtpStats(buffer_to_send_ptr, length, header, rtx_ != kRtxOff, true);
return length;
}
return -1;
} }
bool RTPSender::SendPacketToNetwork(const uint8_t *packet, uint32_t size) { bool RTPSender::SendPacketToNetwork(const uint8_t *packet, uint32_t size) {
@ -798,19 +784,21 @@ bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
UpdateDelayStatistics(capture_time_ms, clock_->TimeInMilliseconds()); UpdateDelayStatistics(capture_time_ms, clock_->TimeInMilliseconds());
} }
return PrepareAndSendPacket(data_buffer, length, capture_time_ms, return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
retransmission && (rtx_ & kRtxRetransmitted) > 0); retransmission && (rtx_ & kRtxRetransmitted) > 0,
retransmission);
} }
bool RTPSender::PrepareAndSendPacket(uint8_t* buffer, bool RTPSender::PrepareAndSendPacket(uint8_t* buffer,
uint16_t length, uint16_t length,
int64_t capture_time_ms, int64_t capture_time_ms,
bool send_over_rtx) { bool send_over_rtx,
bool is_retransmit) {
uint8_t *buffer_to_send_ptr = buffer; uint8_t *buffer_to_send_ptr = buffer;
ModuleRTPUtility::RTPHeaderParser rtp_parser(buffer, length); ModuleRTPUtility::RTPHeaderParser rtp_parser(buffer, length);
RTPHeader rtp_header; RTPHeader rtp_header;
rtp_parser.Parse(rtp_header); rtp_parser.Parse(rtp_header);
TRACE_EVENT_INSTANT2("webrtc_rtp", "RTPSender::TimeToSendPacket", TRACE_EVENT_INSTANT2("webrtc_rtp", "PrepareAndSendPacket",
"timestamp", rtp_header.timestamp, "timestamp", rtp_header.timestamp,
"seqnum", rtp_header.sequenceNumber); "seqnum", rtp_header.sequenceNumber);
@ -835,7 +823,8 @@ bool RTPSender::PrepareAndSendPacket(uint8_t* buffer,
} }
bool ret = SendPacketToNetwork(buffer_to_send_ptr, length); bool ret = SendPacketToNetwork(buffer_to_send_ptr, length);
UpdateRtpStats(buffer_to_send_ptr, length, rtp_header, false, false); UpdateRtpStats(buffer_to_send_ptr, length, rtp_header, send_over_rtx,
is_retransmit);
return ret; return ret;
} }

View File

@ -302,7 +302,8 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
bool PrepareAndSendPacket(uint8_t* buffer, bool PrepareAndSendPacket(uint8_t* buffer,
uint16_t length, uint16_t length,
int64_t capture_time_ms, int64_t capture_time_ms,
bool send_over_rtx); bool send_over_rtx,
bool is_retransmit);
int SendRedundantPayloads(int payload_type, int bytes); int SendRedundantPayloads(int payload_type, int bytes);

View File

@ -258,6 +258,11 @@ bool ViEReceiver::ParseAndHandleEncapsulatingHeader(const uint8_t* packet,
} }
return fec_receiver_->ProcessReceivedFec() == 0; return fec_receiver_->ProcessReceivedFec() == 0;
} else if (rtp_payload_registry_->IsRtx(header)) { } else if (rtp_payload_registry_->IsRtx(header)) {
if (header.headerLength + header.paddingLength == packet_length) {
// This is an empty packet and should be silently dropped before trying to
// parse the RTX header.
return true;
}
// Remove the RTX header and parse the original RTP header. // Remove the RTX header and parse the original RTP header.
if (packet_length < header.headerLength) if (packet_length < header.headerLength)
return false; return false;