Update timestamp offset for re-transmitted packets.

BUG=1059
Review URL: https://webrtc-codereview.appspot.com/930011

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3046 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
asapersson@webrtc.org 2012-11-06 13:09:39 +00:00
parent f17d7d1dde
commit e5b49a0472
5 changed files with 125 additions and 26 deletions

View File

@ -151,6 +151,46 @@ int32_t RTPPacketHistory::PutRTPPacket(const uint8_t* packet,
return 0;
}
int32_t RTPPacketHistory::ReplaceRTPHeader(const uint8_t* packet,
uint16_t sequence_number,
uint16_t rtp_header_length) {
CriticalSectionScoped cs(critsect_);
if (!store_) {
return 0;
}
assert(packet);
assert(rtp_header_length > 3);
if (rtp_header_length > max_packet_length_) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
"Failed to replace RTP packet, length: %d", rtp_header_length);
return -1;
}
int32_t index = 0;
bool found = FindSeqNum(sequence_number, &index);
if (!found) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
"No match for getting seqNum %u", sequence_number);
return -1;
}
uint16_t length = stored_lengths_.at(index);
if (length == 0 || length > max_packet_length_) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
"No match for getting seqNum %u, len %d", sequence_number, length);
return -1;
}
assert(stored_seq_nums_[index] == sequence_number);
// Update RTP header.
std::vector<std::vector<uint8_t> >::iterator it =
stored_packets_.begin() + index;
std::copy(packet, packet + rtp_header_length, it->begin());
return 0;
}
bool RTPPacketHistory::HasRTPPacket(uint16_t sequence_number) const {
CriticalSectionScoped cs(critsect_);
if (!store_) {

View File

@ -40,6 +40,14 @@ class RTPPacketHistory {
int64_t capture_time_ms,
StorageType type);
// Replaces the stored RTP packet with matching sequence number with the
// RTP header of the provided packet.
// Note: Calling this function assumes that the RTP header length should not
// have changed since the packet was stored.
int32_t ReplaceRTPHeader(const uint8_t* packet,
uint16_t sequence_number,
uint16_t rtp_header_length);
// Gets stored RTP packet corresponding to the input sequence number.
// The packet is copied to the buffer pointed to by ptr_rtp_packet.
// The rtp_packet_length should show the available buffer size.

View File

@ -178,6 +178,44 @@ TEST_F(RtpPacketHistoryTest, GetRtpPacket) {
}
}
TEST_F(RtpPacketHistoryTest, ReplaceRtpHeader) {
hist_->SetStorePacketsStatus(true, 10);
uint16_t len = 0;
int64_t capture_time_ms = 1;
CreateRtpPacket(kSeqNum, kSsrc, kPayload, kTimestamp, packet_, &len);
// Replace should fail, packet is not stored.
EXPECT_EQ(-1, hist_->ReplaceRTPHeader(packet_, kSeqNum, len));
EXPECT_EQ(0, hist_->PutRTPPacket(packet_, len, kMaxPacketLength,
capture_time_ms, kAllowRetransmission));
// Create modified packet and replace.
len = 0;
CreateRtpPacket(kSeqNum, kSsrc + 1, kPayload + 2, kTimestamp, packet_, &len);
EXPECT_EQ(0, hist_->ReplaceRTPHeader(packet_, kSeqNum, len));
uint16_t len_out = kMaxPacketLength;
int64_t time;
StorageType type;
EXPECT_TRUE(hist_->GetRTPPacket(kSeqNum, 0, packet_out_, &len_out, &time,
&type));
EXPECT_EQ(len, len_out);
EXPECT_EQ(kAllowRetransmission, type);
EXPECT_EQ(capture_time_ms, time);
for (int i = 0; i < len; i++) {
EXPECT_EQ(packet_[i], packet_out_[i]);
}
// Replace should fail, too large length.
EXPECT_EQ(-1, hist_->ReplaceRTPHeader(packet_, kSeqNum,
kMaxPacketLength + 1));
// Replace should fail, packet is not stored.
len = 0;
CreateRtpPacket(kSeqNum + 1, kSsrc, kPayload, kTimestamp, packet_, &len);
EXPECT_EQ(-1, hist_->ReplaceRTPHeader(packet_, kSeqNum + 1, len));
}
TEST_F(RtpPacketHistoryTest, NoCaptureTime) {
hist_->SetStorePacketsStatus(true, 10);
uint16_t len = 0;

View File

@ -843,7 +843,13 @@ void RTPSender::ProcessSendToNetwork() {
WebRtcRTPHeader rtp_header;
rtpParser.Parse(rtp_header);
UpdateTransmissionTimeOffset(data_buffer, length, rtp_header, diff_ms);
if (UpdateTransmissionTimeOffset(data_buffer, length, rtp_header,
diff_ms)) {
// Update stored packet in case of receiving a re-transmission request.
_packetHistory->ReplaceRTPHeader(data_buffer,
rtp_header.header.sequenceNumber,
rtp_header.header.headerLength);
}
// Send packet
WebRtc_Word32 bytes_sent = -1;
@ -868,15 +874,14 @@ void RTPSender::ProcessSendToNetwork() {
WebRtc_Word32
RTPSender::SendToNetwork(WebRtc_UWord8* buffer,
const WebRtc_UWord16 length,
const WebRtc_UWord16 rtpLength,
const WebRtc_UWord16 payload_length,
const WebRtc_UWord16 rtp_header_length,
int64_t capture_time_ms,
const StorageType storage)
{
// Used for NACK or to spead out the transmission of packets.
if (_packetHistory->PutRTPPacket(
buffer, rtpLength + length, _maxPayloadLength, capture_time_ms, storage)
!= 0) {
if (_packetHistory->PutRTPPacket(buffer, rtp_header_length + payload_length,
_maxPayloadLength, capture_time_ms, storage) != 0) {
return -1;
}
@ -884,7 +889,8 @@ RTPSender::SendToNetwork(WebRtc_UWord8* buffer,
const WebRtc_UWord16 sequenceNumber = (buffer[2] << 8) + buffer[3];
const WebRtc_UWord32 timestamp = (buffer[4] << 24) + (buffer[5] << 16) +
(buffer[6] << 8) + buffer[7];
_sendBucket.Fill(sequenceNumber, timestamp, rtpLength + length);
_sendBucket.Fill(sequenceNumber, timestamp,
rtp_header_length + payload_length);
// Packet will be sent at a later time.
return 0;
}
@ -893,12 +899,17 @@ RTPSender::SendToNetwork(WebRtc_UWord8* buffer,
// TODO(holmer): This should be changed all over Video Engine so that negative
// time is consider invalid, while 0 is considered a valid time.
if (capture_time_ms > 0) {
ModuleRTPUtility::RTPHeaderParser rtpParser(buffer, length);
ModuleRTPUtility::RTPHeaderParser rtpParser(buffer,
rtp_header_length + payload_length);
WebRtcRTPHeader rtp_header;
rtpParser.Parse(rtp_header);
int64_t time_now = _clock.GetTimeInMS();
UpdateTransmissionTimeOffset(buffer, length, rtp_header,
time_now - capture_time_ms);
if (UpdateTransmissionTimeOffset(buffer, rtp_header_length + payload_length,
rtp_header, time_now - capture_time_ms)) {
// Update stored packet in case of receiving a re-transmission request.
_packetHistory->ReplaceRTPHeader(buffer, rtp_header.header.sequenceNumber,
rtp_header.header.headerLength);
}
}
// Send packet
@ -906,7 +917,8 @@ RTPSender::SendToNetwork(WebRtc_UWord8* buffer,
{
CriticalSectionScoped cs(_transportCritsect);
if (_transport) {
bytes_sent = _transport->SendPacket(_id, buffer, length + rtpLength);
bytes_sent = _transport->SendPacket(_id, buffer,
payload_length + rtp_header_length);
}
}
@ -918,8 +930,8 @@ RTPSender::SendToNetwork(WebRtc_UWord8* buffer,
CriticalSectionScoped cs(_sendCritsect);
Bitrate::Update(bytes_sent);
_packetsSent++;
if (bytes_sent > rtpLength) {
_payloadBytesSent += bytes_sent - rtpLength;
if (bytes_sent > rtp_header_length) {
_payloadBytesSent += bytes_sent - rtp_header_length;
}
return 0;
}
@ -1146,7 +1158,7 @@ RTPSender::BuildTransmissionTimeOffsetExtension(WebRtc_UWord8* dataBuffer) const
return TRANSMISSION_TIME_OFFSET_LENGTH_IN_BYTES;
}
void RTPSender::UpdateTransmissionTimeOffset(
bool RTPSender::UpdateTransmissionTimeOffset(
WebRtc_UWord8* rtp_packet,
const WebRtc_UWord16 rtp_packet_length,
const WebRtcRTPHeader& rtp_header,
@ -1160,7 +1172,7 @@ void RTPSender::UpdateTransmissionTimeOffset(
if (transmission_block_pos < 0) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"Failed to update transmission time offset, not registered.");
return;
return false;
}
int block_pos = 12 + rtp_header.header.numCSRCs + transmission_block_pos;
@ -1168,7 +1180,7 @@ void RTPSender::UpdateTransmissionTimeOffset(
rtp_header.header.headerLength < block_pos + 4) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"Failed to update transmission time offset, invalid length.");
return;
return false;
}
// Verify that header contains extension.
@ -1176,7 +1188,7 @@ void RTPSender::UpdateTransmissionTimeOffset(
(rtp_packet[12 + rtp_header.header.numCSRCs + 1] == 0xDE))) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"Failed to update transmission time offset, hdr extension not found.");
return;
return false;
}
// Get id.
@ -1185,7 +1197,7 @@ void RTPSender::UpdateTransmissionTimeOffset(
&id) != 0) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"Failed to update transmission time offset, no id.");
return;
return false;
}
// Verify first byte in block.
@ -1193,12 +1205,13 @@ void RTPSender::UpdateTransmissionTimeOffset(
if (rtp_packet[block_pos] != first_block_byte) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id,
"Failed to update transmission time offset.");
return;
return false;
}
// Update transmission offset field.
ModuleRTPUtility::AssignUWord24ToBuffer(rtp_packet + block_pos + 1,
time_diff_ms * 90); // RTP timestamp.
return true;
}
WebRtc_Word32

View File

@ -56,9 +56,9 @@ public:
virtual WebRtc_UWord16 PacketOverHead() const = 0;
virtual WebRtc_UWord16 ActualSendBitrateKbit() const = 0;
virtual WebRtc_Word32 SendToNetwork(WebRtc_UWord8* dataBuffer,
const WebRtc_UWord16 payloadLength,
const WebRtc_UWord16 rtpHeaderLength,
virtual WebRtc_Word32 SendToNetwork(WebRtc_UWord8* data_buffer,
const WebRtc_UWord16 payload_length,
const WebRtc_UWord16 rtp_header_length,
int64_t capture_time_ms,
const StorageType storage) = 0;
};
@ -163,7 +163,7 @@ public:
WebRtc_UWord8 BuildTransmissionTimeOffsetExtension(
WebRtc_UWord8* dataBuffer) const;
void UpdateTransmissionTimeOffset(WebRtc_UWord8* rtp_packet,
bool UpdateTransmissionTimeOffset(WebRtc_UWord8* rtp_packet,
const WebRtc_UWord16 rtp_packet_length,
const WebRtcRTPHeader& rtp_header,
const WebRtc_Word64 time_diff_ms) const;
@ -222,9 +222,9 @@ public:
virtual WebRtc_UWord32 Timestamp() const;
virtual WebRtc_UWord32 SSRC() const;
virtual WebRtc_Word32 SendToNetwork(WebRtc_UWord8* dataBuffer,
const WebRtc_UWord16 payloadLength,
const WebRtc_UWord16 rtpHeaderLength,
virtual WebRtc_Word32 SendToNetwork(WebRtc_UWord8* data_buffer,
const WebRtc_UWord16 payload_length,
const WebRtc_UWord16 rtp_header_length,
int64_t capture_time_ms,
const StorageType storage);