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:
parent
f17d7d1dde
commit
e5b49a0472
@ -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_) {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user