diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc b/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc index 791fbf96d0..b6de6ec774 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_history.cc @@ -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 >::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_) { diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_history.h b/webrtc/modules/rtp_rtcp/source/rtp_packet_history.h index 5efadcd055..f7fbf4ebcc 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_packet_history.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_history.h @@ -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. diff --git a/webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc index 7058fd705a..23f67650d9 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc @@ -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; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index d61acdc003..259f0bebe0 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -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 diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index 4c843a710a..542ad8cc03 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -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);