diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc index 019f8422c8..c977ddfaee 100644 --- a/call/rtp_video_sender.cc +++ b/call/rtp_video_sender.cc @@ -16,6 +16,7 @@ #include #include "absl/memory/memory.h" +#include "api/array_view.h" #include "api/transport/field_trial_based_config.h" #include "call/rtp_transport_controller_send_interface.h" #include "modules/pacing/packet_router.h" @@ -323,18 +324,14 @@ RtpVideoSender::RtpVideoSender( fec_controller_->SetProtectionCallback(this); // Signal congestion controller this object is ready for OnPacket* callbacks. - if (fec_controller_->UseLossVectorMask()) { - transport_->RegisterPacketFeedbackObserver(this); - } + transport_->RegisterPacketFeedbackObserver(this); } RtpVideoSender::~RtpVideoSender() { for (const RtpStreamSender& stream : rtp_streams_) { transport_->packet_router()->RemoveSendRtpModule(stream.rtp_rtcp.get()); } - if (fec_controller_->UseLossVectorMask()) { - transport_->DeRegisterPacketFeedbackObserver(this); - } + transport_->DeRegisterPacketFeedbackObserver(this); } void RtpVideoSender::RegisterProcessThread( @@ -567,6 +564,7 @@ void RtpVideoSender::DeliverRtcp(const uint8_t* packet, size_t length) { void RtpVideoSender::ConfigureSsrcs(const RtpConfig& rtp_config) { // Configure regular SSRCs. + ssrc_to_acknowledged_packets_observers_.clear(); for (size_t i = 0; i < rtp_config.ssrcs.size(); ++i) { uint32_t ssrc = rtp_config.ssrcs[i]; RtpRtcp* const rtp_rtcp = rtp_streams_[i].rtp_rtcp.get(); @@ -576,6 +574,12 @@ void RtpVideoSender::ConfigureSsrcs(const RtpConfig& rtp_config) { auto it = suspended_ssrcs_.find(ssrc); if (it != suspended_ssrcs_.end()) rtp_rtcp->SetRtpState(it->second); + + AcknowledgedPacketsObserver* receive_observer = + rtp_rtcp->GetAcknowledgedPacketsObserver(); + if (receive_observer != nullptr) { + ssrc_to_acknowledged_packets_observers_[ssrc] = receive_observer; + } } // Set up RTX if available. @@ -791,15 +795,41 @@ void RtpVideoSender::OnPacketAdded(uint32_t ssrc, uint16_t seq_num) { void RtpVideoSender::OnPacketFeedbackVector( const std::vector& packet_feedback_vector) { - rtc::CritScope lock(&crit_); - // Lost feedbacks are not considered to be lost packets. + const bool use_loss_mask = fec_controller_->UseLossVectorMask(); + + std::vector loss_mask; + std::map> acked_packets; for (const PacketFeedback& packet : packet_feedback_vector) { - auto it = feedback_packet_seq_num_set_.find(packet.sequence_number); - if (it != feedback_packet_seq_num_set_.end()) { - const bool lost = packet.arrival_time_ms == PacketFeedback::kNotReceived; - loss_mask_vector_.push_back(lost); - feedback_packet_seq_num_set_.erase(it); + if (use_loss_mask) { + // Lost feedbacks are not considered to be lost packets. + auto it = feedback_packet_seq_num_set_.find(packet.sequence_number); + if (it != feedback_packet_seq_num_set_.end()) { + const bool lost = + packet.arrival_time_ms == PacketFeedback::kNotReceived; + loss_mask.push_back(lost); + feedback_packet_seq_num_set_.erase(it); + } } + if (packet.ssrc) { + if (ssrc_to_acknowledged_packets_observers_.find(*packet.ssrc) != + ssrc_to_acknowledged_packets_observers_.end()) { + acked_packets[*packet.ssrc].push_back(packet.rtp_sequence_number); + } + } + } + + if (use_loss_mask) { + rtc::CritScope cs(&crit_); + loss_mask_vector_.insert(loss_mask_vector_.end(), loss_mask.begin(), + loss_mask.end()); + } + for (const auto& kv : acked_packets) { + const uint32_t ssrc = kv.first; + rtc::ArrayView rtp_sequence_numbers(kv.second); + RTC_DCHECK(ssrc_to_acknowledged_packets_observers_.find(ssrc) != + ssrc_to_acknowledged_packets_observers_.end()); + ssrc_to_acknowledged_packets_observers_[ssrc]->OnPacketsAcknowledged( + rtp_sequence_numbers); } } diff --git a/call/rtp_video_sender.h b/call/rtp_video_sender.h index e17bb49a36..162875b204 100644 --- a/call/rtp_video_sender.h +++ b/call/rtp_video_sender.h @@ -172,7 +172,7 @@ class RtpVideoSender : public RtpVideoSenderInterface, std::map suspended_ssrcs_; std::unique_ptr flexfec_sender_; - std::unique_ptr fec_controller_; + const std::unique_ptr fec_controller_; // Rtp modules are assumed to be sorted in simulcast index order. const std::vector rtp_streams_; @@ -197,6 +197,12 @@ class RtpVideoSender : public RtpVideoSenderInterface, std::vector frame_counts_ RTC_GUARDED_BY(crit_); FrameCountObserver* const frame_count_observer_; + // Effectively const map from ssrc to AcknowledgedPacketsObserver. This + // map is set at construction time and never changed, but it's + // non-trivial to make it properly const. + std::map + ssrc_to_acknowledged_packets_observers_; + RTC_DISALLOW_COPY_AND_ASSIGN(RtpVideoSender); }; diff --git a/call/rtp_video_sender_unittest.cc b/call/rtp_video_sender_unittest.cc index 9416173c3c..65f4ca78ee 100644 --- a/call/rtp_video_sender_unittest.cc +++ b/call/rtp_video_sender_unittest.cc @@ -15,8 +15,13 @@ #include "api/task_queue/default_task_queue_factory.h" #include "call/rtp_transport_controller_send.h" #include "call/rtp_video_sender.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" +#include "modules/rtp_rtcp/source/rtp_packet.h" #include "modules/video_coding/fec_controller_default.h" #include "modules/video_coding/include/video_codec_interface.h" +#include "rtc_base/event.h" #include "rtc_base/rate_limiter.h" #include "test/field_trial.h" #include "test/gmock.h" @@ -27,6 +32,7 @@ #include "video/send_statistics_proxy.h" using ::testing::_; +using ::testing::Invoke; using ::testing::NiceMock; using ::testing::SaveArg; using ::testing::Unused; @@ -36,6 +42,8 @@ namespace { const int8_t kPayloadType = 96; const uint32_t kSsrc1 = 12345; const uint32_t kSsrc2 = 23456; +const uint32_t kRtxSsrc1 = 34567; +const uint32_t kRtxSsrc2 = 45678; const int16_t kInitialPictureId1 = 222; const int16_t kInitialPictureId2 = 44; const int16_t kInitialTl0PicIdx1 = 99; @@ -60,6 +68,7 @@ RtpSenderObservers CreateObservers( RtpSenderObservers observers; observers.rtcp_rtt_stats = rtcp_rtt_stats; observers.intra_frame_callback = intra_frame_callback; + observers.rtcp_loss_notification_observer = nullptr; observers.rtcp_stats = rtcp_stats; observers.rtp_stats = rtp_stats; observers.bitrate_observer = bitrate_observer; @@ -70,16 +79,43 @@ RtpSenderObservers CreateObservers( return observers; } +BitrateConstraints GetBitrateConfig() { + BitrateConstraints bitrate_config; + bitrate_config.min_bitrate_bps = 30000; + bitrate_config.start_bitrate_bps = 300000; + bitrate_config.max_bitrate_bps = 3000000; + return bitrate_config; +} + +VideoSendStream::Config CreateVideoSendStreamConfig( + Transport* transport, + const std::vector& ssrcs, + const std::vector& rtx_ssrcs, + int payload_type) { + VideoSendStream::Config config(transport); + config.rtp.ssrcs = ssrcs; + config.rtp.rtx.ssrcs = rtx_ssrcs; + config.rtp.payload_type = payload_type; + config.rtp.rtx.payload_type = payload_type + 1; + config.rtp.nack.rtp_history_ms = 1000; + return config; +} + class RtpVideoSenderTestFixture { public: RtpVideoSenderTestFixture( const std::vector& ssrcs, + const std::vector& rtx_ssrcs, int payload_type, const std::map& suspended_payload_states, FrameCountObserver* frame_count_observer) : clock_(1000000), - config_(&transport_), + config_(CreateVideoSendStreamConfig(&transport_, + ssrcs, + rtx_ssrcs, + payload_type)), send_delay_stats_(&clock_), + bitrate_config_(GetBitrateConfig()), task_queue_factory_(CreateDefaultTaskQueueFactory()), transport_controller_(&clock_, &event_log_, @@ -94,10 +130,6 @@ class RtpVideoSenderTestFixture { config_, VideoEncoderConfig::ContentType::kRealtimeVideo), retransmission_rate_limiter_(&clock_, kRetransmitWindowSizeMs) { - for (uint32_t ssrc : ssrcs) { - config_.rtp.ssrcs.push_back(ssrc); - } - config_.rtp.payload_type = payload_type; std::map suspended_ssrcs; router_ = absl::make_unique( &clock_, suspended_ssrcs, suspended_payload_states, config_.rtp, @@ -111,14 +143,18 @@ class RtpVideoSenderTestFixture { } RtpVideoSenderTestFixture( const std::vector& ssrcs, + const std::vector& rtx_ssrcs, int payload_type, const std::map& suspended_payload_states) : RtpVideoSenderTestFixture(ssrcs, + rtx_ssrcs, payload_type, suspended_payload_states, /*frame_count_observer=*/nullptr) {} RtpVideoSender* router() { return router_.get(); } + MockTransport& transport() { return transport_; } + SimulatedClock& clock() { return clock_; } private: NiceMock transport_; @@ -148,7 +184,7 @@ TEST(RtpVideoSenderTest, SendOnOneModule) { encoded_image.data()[0] = kPayload; encoded_image.set_size(1); - RtpVideoSenderTestFixture test({kSsrc1}, kPayloadType, {}); + RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {}); EXPECT_NE( EncodedImageCallback::Result::OK, test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error); @@ -179,7 +215,8 @@ TEST(RtpVideoSenderTest, SendSimulcastSetActive) { encoded_image_1.data()[0] = kPayload; encoded_image_1.set_size(1); - RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {}); + RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2}, + kPayloadType, {}); CodecSpecificInfo codec_info; codec_info.codecType = kVideoCodecVP8; @@ -226,7 +263,8 @@ TEST(RtpVideoSenderTest, SendSimulcastSetActiveModules) { EncodedImage encoded_image_2(encoded_image_1); encoded_image_2.SetSpatialIndex(1); - RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {}); + RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2}, + kPayloadType, {}); CodecSpecificInfo codec_info; codec_info.codecType = kVideoCodecVP8; @@ -256,7 +294,8 @@ TEST(RtpVideoSenderTest, SendSimulcastSetActiveModules) { } TEST(RtpVideoSenderTest, CreateWithNoPreviousStates) { - RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {}); + RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2}, + kPayloadType, {}); test.router()->SetActive(true); std::map initial_states = @@ -280,7 +319,8 @@ TEST(RtpVideoSenderTest, CreateWithPreviousStates) { std::map states = {{kSsrc1, state1}, {kSsrc2, state2}}; - RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, kPayloadType, states); + RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2}, + kPayloadType, states); test.router()->SetActive(true); std::map initial_states = @@ -301,7 +341,8 @@ TEST(RtpVideoSenderTest, FrameCountCallbacks) { void(const FrameCounts& frame_counts, uint32_t ssrc)); } callback; - RtpVideoSenderTestFixture test({kSsrc1}, kPayloadType, {}, &callback); + RtpVideoSenderTestFixture test({kSsrc1}, {kRtxSsrc1}, kPayloadType, {}, + &callback); constexpr uint8_t kPayload = 'a'; EncodedImage encoded_image; @@ -346,4 +387,86 @@ TEST(RtpVideoSenderTest, FrameCountCallbacks) { EXPECT_EQ(1, frame_counts.delta_frames); } +TEST(RtpVideoSenderTest, PropagatesTransportFeedbackToRtpSender) { + const int64_t kTimeoutMs = 500; + + RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2}, + kPayloadType, {}); + test.router()->SetActive(true); + + constexpr uint8_t kPayload = 'a'; + EncodedImage encoded_image; + encoded_image.SetTimestamp(1); + encoded_image.capture_time_ms_ = 2; + encoded_image._frameType = VideoFrameType::kVideoFrameKey; + encoded_image.Allocate(1); + encoded_image.data()[0] = kPayload; + encoded_image.set_size(1); + + // Send image, capture first RTP packet. + rtc::Event event; + uint16_t rtp_sequence_number = 0; + uint16_t transport_sequence_number = 0; + EXPECT_CALL(test.transport(), SendRtp(_, _, _)) + .WillOnce( + Invoke([&event, &rtp_sequence_number, &transport_sequence_number]( + const uint8_t* packet, size_t length, + const PacketOptions& options) { + RtpPacket rtp_packet; + EXPECT_TRUE(rtp_packet.Parse(packet, length)); + rtp_sequence_number = rtp_packet.SequenceNumber(); + transport_sequence_number = options.packet_id; + event.Set(); + return true; + })); + EXPECT_EQ( + EncodedImageCallback::Result::OK, + test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error); + test.clock().AdvanceTimeMilliseconds(33); + + ASSERT_TRUE(event.Wait(kTimeoutMs)); + + // Construct a NACK message for requesting retransmission of the packet. + std::vector nack_list; + nack_list.push_back(rtp_sequence_number); + rtcp::Nack nack; + nack.SetMediaSsrc(kSsrc1); + nack.SetPacketIds(nack_list); + rtc::Buffer nack_buffer = nack.Build(); + + uint16_t retransmitted_rtp_sequence_number = 0; + EXPECT_CALL(test.transport(), SendRtp) + .WillOnce([&event, &retransmitted_rtp_sequence_number]( + const uint8_t* packet, size_t length, + const PacketOptions& options) { + RtpPacket rtp_packet; + EXPECT_TRUE(rtp_packet.Parse(packet, length)); + EXPECT_EQ(rtp_packet.Ssrc(), kRtxSsrc1); + // Capture the retransmitted sequence number from the RTX header. + rtc::ArrayView payload = rtp_packet.payload(); + retransmitted_rtp_sequence_number = + ByteReader::ReadBigEndian(payload.data()); + event.Set(); + return true; + }); + test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size()); + ASSERT_TRUE(event.Wait(kTimeoutMs)); + EXPECT_EQ(retransmitted_rtp_sequence_number, rtp_sequence_number); + + // Simulate transport feedback indicating packet has been received. + PacketFeedback feedback(test.clock().TimeInMilliseconds(), + transport_sequence_number); + feedback.rtp_sequence_number = rtp_sequence_number; + feedback.ssrc = kSsrc1; + test.router()->OnPacketFeedbackVector( + std::vector(1, feedback)); + + // Advance time to make sure retranmission would be allowed and try again. + // This time the retranmission should not happen since the paket history + // has been notified of the ack and removed the packet. + test.clock().AdvanceTimeMilliseconds(33); + EXPECT_CALL(test.transport(), SendRtp).Times(0); + test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size()); + ASSERT_FALSE(event.Wait(kTimeoutMs)); +} } // namespace webrtc diff --git a/modules/rtp_rtcp/include/rtp_rtcp.h b/modules/rtp_rtcp/include/rtp_rtcp.h index 1c589f4c93..9fb26cbbea 100644 --- a/modules/rtp_rtcp/include/rtp_rtcp.h +++ b/modules/rtp_rtcp/include/rtp_rtcp.h @@ -275,6 +275,11 @@ class RtpRtcp : public Module, public RtcpFeedbackSenderInterface { virtual StreamDataCountersCallback* GetSendChannelRtpStatisticsCallback() const = 0; + // Returns a pointer to an observer that handles information about packets + // that have been received by the remote end, or nullptr if not applicable. + virtual AcknowledgedPacketsObserver* GetAcknowledgedPacketsObserver() + const = 0; + // ************************************************************************** // RTCP // ************************************************************************** diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h index 4a4b82555e..de73c3adfe 100644 --- a/modules/rtp_rtcp/include/rtp_rtcp_defines.h +++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h @@ -16,6 +16,7 @@ #include #include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "absl/types/variant.h" #include "api/audio_codecs/audio_format.h" #include "api/rtp_headers.h" @@ -276,7 +277,7 @@ struct PacketFeedback { PacedPacketInfo pacing_info; // The SSRC and RTP sequence number of the packet this feedback refers to. - uint32_t ssrc; + absl::optional ssrc; uint16_t rtp_sequence_number; }; @@ -313,6 +314,17 @@ class TransportFeedbackObserver { virtual void OnTransportFeedback(const rtcp::TransportFeedback& feedback) = 0; }; +class AcknowledgedPacketsObserver { + public: + AcknowledgedPacketsObserver() = default; + virtual ~AcknowledgedPacketsObserver() = default; + + // Indicates RTP sequence numbers for packets that have been acknowledged as + // received by the remote end. + virtual void OnPacketsAcknowledged( + rtc::ArrayView sequence_numbers) = 0; +}; + // Interface for PacketRouter to send rtcp feedback on behalf of // congestion controller. // TODO(bugs.webrtc.org/8239): Remove and use RtcpTransceiver directly diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h index 668d52707d..733ec28c47 100644 --- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h +++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -157,7 +157,9 @@ class MockRtpRtcp : public RtpRtcp { MOCK_METHOD1(RegisterSendChannelRtpStatisticsCallback, void(StreamDataCountersCallback*)); MOCK_CONST_METHOD0(GetSendChannelRtpStatisticsCallback, - StreamDataCountersCallback*(void)); + StreamDataCountersCallback*()); + MOCK_CONST_METHOD0(GetAcknowledgedPacketsObserver, + AcknowledgedPacketsObserver*()); MOCK_METHOD1(SetVideoBitrateAllocation, void(const VideoBitrateAllocation&)); MOCK_METHOD0(RtpSender, RTPSender*()); MOCK_CONST_METHOD0(RtpSender, const RTPSender*()); diff --git a/modules/rtp_rtcp/source/rtp_packet_history.cc b/modules/rtp_rtcp/source/rtp_packet_history.cc index ac39e22391..217a54243d 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history.cc +++ b/modules/rtp_rtcp/source/rtp_packet_history.cc @@ -232,6 +232,17 @@ std::unique_ptr RtpPacketHistory::GetBestFittingPacket( return absl::make_unique(*best_packet); } +void RtpPacketHistory::CullAcknowledgedPackets( + rtc::ArrayView sequence_numbers) { + rtc::CritScope cs(&lock_); + for (uint16_t sequence_number : sequence_numbers) { + auto stored_packet_it = packet_history_.find(sequence_number); + if (stored_packet_it != packet_history_.end()) { + RemovePacket(stored_packet_it); + } + } +} + void RtpPacketHistory::Reset() { packet_history_.clear(); packet_size_.clear(); diff --git a/modules/rtp_rtcp/source/rtp_packet_history.h b/modules/rtp_rtcp/source/rtp_packet_history.h index 5e6463ba30..cf87ddf205 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history.h +++ b/modules/rtp_rtcp/source/rtp_packet_history.h @@ -89,6 +89,9 @@ class RtpPacketHistory { std::unique_ptr GetBestFittingPacket( size_t packet_size) const; + // Cull packets that have been acknowledged as received by the remote end. + void CullAcknowledgedPackets(rtc::ArrayView sequence_numbers); + private: struct StoredPacket { StoredPacket(); @@ -133,6 +136,7 @@ class RtpPacketHistory { // Map from rtp sequence numbers to stored packet. std::map packet_history_ RTC_GUARDED_BY(lock_); + // Map from packet size to sequence number. std::map packet_size_ RTC_GUARDED_BY(lock_); // The earliest packet in the history. This might not be the lowest sequence diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index a15558d95a..97cc8798b2 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -867,6 +867,11 @@ ModuleRtpRtcpImpl::GetSendChannelRtpStatisticsCallback() const { return rtp_sender_->GetRtpStatisticsCallback(); } +AcknowledgedPacketsObserver* ModuleRtpRtcpImpl::GetAcknowledgedPacketsObserver() + const { + return rtp_sender_.get(); +} + void ModuleRtpRtcpImpl::SetVideoBitrateAllocation( const VideoBitrateAllocation& bitrate) { rtcp_sender_.SetVideoBitrateAllocation(bitrate); diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h index cb565f8f63..de0080013d 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -276,6 +276,7 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp { StreamDataCountersCallback* callback) override; StreamDataCountersCallback* GetSendChannelRtpStatisticsCallback() const override; + AcknowledgedPacketsObserver* GetAcknowledgedPacketsObserver() const override; void OnReceivedNack( const std::vector& nack_sequence_numbers) override; diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc index 2e198fc999..05b54bce58 100644 --- a/modules/rtp_rtcp/source/rtp_sender.cc +++ b/modules/rtp_rtcp/source/rtp_sender.cc @@ -1207,6 +1207,7 @@ void RTPSender::AddPacketToTransportFeedback( RtpPacketSendInfo packet_info; packet_info.ssrc = SSRC(); packet_info.transport_sequence_number = packet_id; + packet_info.has_rtp_sequence_number = true; packet_info.rtp_sequence_number = packet.SequenceNumber(); packet_info.length = packet_size; packet_info.pacing_info = pacing_info; @@ -1238,4 +1239,9 @@ void RTPSender::SetRtt(int64_t rtt_ms) { packet_history_.SetRtt(rtt_ms); flexfec_packet_history_.SetRtt(rtt_ms); } + +void RTPSender::OnPacketsAcknowledged( + rtc::ArrayView sequence_numbers) { + packet_history_.CullAcknowledgedPackets(sequence_numbers); +} } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h index 4d7e72b7b7..832a570a98 100644 --- a/modules/rtp_rtcp/source/rtp_sender.h +++ b/modules/rtp_rtcp/source/rtp_sender.h @@ -42,7 +42,7 @@ class RateLimiter; class RtcEventLog; class RtpPacketToSend; -class RTPSender { +class RTPSender : public AcknowledgedPacketsObserver { public: RTPSender(bool audio, Clock* clock, @@ -173,6 +173,9 @@ class RTPSender { void SetRtt(int64_t rtt_ms); + void OnPacketsAcknowledged( + rtc::ArrayView sequence_numbers) override; + private: // Maps capture time in milliseconds to send-side delay in milliseconds. // Send-side delay is the difference between transmission time and capture