Remove packets from RtpPacketHistory if acked via TransportFeedback
If the receiver has indicated that a packet has been received, via a TransportFeedback RTCP message, it is safe to remove it from the RtpPacketHistory as we can be sure it won't be needed anymore. This will reduce memory usage, reduce the risk of overflow in the history at very high bitrates, and hopefully make payload based padding a little more useful. This is code stems partly from https://webrtc-review.googlesource.com/c/src/+/134208 but without the RtpPacketHistory changes which were landed in https://webrtc-review.googlesource.com/c/src/+/134307 Bug: webrtc:8975 Change-Id: Iea9d3d32bee5512473744e9ef3a18018567fc272 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/135160 Commit-Queue: Erik Språng <sprang@webrtc.org> Reviewed-by: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27868}
This commit is contained in:
parent
571791a63e
commit
490d76c9b3
@ -16,6 +16,7 @@
|
||||
#include <utility>
|
||||
|
||||
#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.
|
||||
RTC_CHECK(ssrc_to_acknowledged_packets_observers_.empty());
|
||||
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,11 @@ 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();
|
||||
RTC_DCHECK(receive_observer != nullptr);
|
||||
ssrc_to_acknowledged_packets_observers_[ssrc] = receive_observer;
|
||||
}
|
||||
|
||||
// Set up RTX if available.
|
||||
@ -791,16 +794,40 @@ void RtpVideoSender::OnPacketAdded(uint32_t ssrc, uint16_t seq_num) {
|
||||
|
||||
void RtpVideoSender::OnPacketFeedbackVector(
|
||||
const std::vector<PacketFeedback>& packet_feedback_vector) {
|
||||
rtc::CritScope lock(&crit_);
|
||||
// Lost feedbacks are not considered to be lost 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()) {
|
||||
if (fec_controller_->UseLossVectorMask()) {
|
||||
rtc::CritScope cs(&crit_);
|
||||
for (const PacketFeedback& packet : packet_feedback_vector) {
|
||||
const bool lost = packet.arrival_time_ms == PacketFeedback::kNotReceived;
|
||||
loss_mask_vector_.push_back(lost);
|
||||
feedback_packet_seq_num_set_.erase(it);
|
||||
// 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()) {
|
||||
loss_mask_vector_.push_back(lost);
|
||||
feedback_packet_seq_num_set_.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Map from SSRC to all acked packets for that RTP module.
|
||||
std::map<uint32_t, std::vector<uint16_t>> acked_packets_per_ssrc;
|
||||
for (const PacketFeedback& packet : packet_feedback_vector) {
|
||||
if (packet.ssrc && packet.arrival_time_ms != PacketFeedback::kNotReceived) {
|
||||
acked_packets_per_ssrc[*packet.ssrc].push_back(
|
||||
packet.rtp_sequence_number);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& kv : acked_packets_per_ssrc) {
|
||||
const uint32_t ssrc = kv.first;
|
||||
if (ssrc_to_acknowledged_packets_observers_.find(ssrc) ==
|
||||
ssrc_to_acknowledged_packets_observers_.end()) {
|
||||
// Packets not for a media SSRC, so likely RTX or FEC. If so, ignore
|
||||
// since there's no RTP history to clean up anyway.
|
||||
continue;
|
||||
}
|
||||
rtc::ArrayView<const uint16_t> rtp_sequence_numbers(kv.second);
|
||||
ssrc_to_acknowledged_packets_observers_[ssrc]->OnPacketsAcknowledged(
|
||||
rtp_sequence_numbers);
|
||||
}
|
||||
}
|
||||
|
||||
void RtpVideoSender::SetEncodingData(size_t width,
|
||||
|
||||
@ -172,7 +172,7 @@ class RtpVideoSender : public RtpVideoSenderInterface,
|
||||
std::map<uint32_t, RtpState> suspended_ssrcs_;
|
||||
|
||||
std::unique_ptr<FlexfecSender> flexfec_sender_;
|
||||
std::unique_ptr<FecController> fec_controller_;
|
||||
const std::unique_ptr<FecController> fec_controller_;
|
||||
// Rtp modules are assumed to be sorted in simulcast index order.
|
||||
const std::vector<webrtc_internal_rtp_video_sender::RtpStreamSender>
|
||||
rtp_streams_;
|
||||
@ -197,6 +197,12 @@ class RtpVideoSender : public RtpVideoSenderInterface,
|
||||
std::vector<FrameCounts> 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<uint32_t, AcknowledgedPacketsObserver*>
|
||||
ssrc_to_acknowledged_packets_observers_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(RtpVideoSender);
|
||||
};
|
||||
|
||||
|
||||
@ -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<uint32_t>& ssrcs,
|
||||
const std::vector<uint32_t>& 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<uint32_t>& ssrcs,
|
||||
const std::vector<uint32_t>& rtx_ssrcs,
|
||||
int payload_type,
|
||||
const std::map<uint32_t, RtpPayloadState>& 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<uint32_t, RtpState> suspended_ssrcs;
|
||||
router_ = absl::make_unique<RtpVideoSender>(
|
||||
&clock_, suspended_ssrcs, suspended_payload_states, config_.rtp,
|
||||
@ -111,14 +143,18 @@ class RtpVideoSenderTestFixture {
|
||||
}
|
||||
RtpVideoSenderTestFixture(
|
||||
const std::vector<uint32_t>& ssrcs,
|
||||
const std::vector<uint32_t>& rtx_ssrcs,
|
||||
int payload_type,
|
||||
const std::map<uint32_t, RtpPayloadState>& 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<MockTransport> 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<uint32_t, RtpPayloadState> initial_states =
|
||||
@ -280,7 +319,8 @@ TEST(RtpVideoSenderTest, CreateWithPreviousStates) {
|
||||
std::map<uint32_t, RtpPayloadState> 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<uint32_t, RtpPayloadState> 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,123 @@ TEST(RtpVideoSenderTest, FrameCountCallbacks) {
|
||||
EXPECT_EQ(1, frame_counts.delta_frames);
|
||||
}
|
||||
|
||||
// Integration test verifying that ack of packet via TransportFeedback means
|
||||
// that the packet is removed from RtpPacketHistory and won't be retranmistted
|
||||
// again.
|
||||
TEST(RtpVideoSenderTest, DoesNotRetrasmitAckedPackets) {
|
||||
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 two tiny images, mapping to two RTP packets. Capture sequence numbers.
|
||||
rtc::Event event;
|
||||
std::vector<uint16_t> rtp_sequence_numbers;
|
||||
std::vector<uint16_t> transport_sequence_numbers;
|
||||
EXPECT_CALL(test.transport(), SendRtp)
|
||||
.Times(2)
|
||||
.WillRepeatedly(
|
||||
[&event, &rtp_sequence_numbers, &transport_sequence_numbers](
|
||||
const uint8_t* packet, size_t length,
|
||||
const PacketOptions& options) {
|
||||
RtpPacket rtp_packet;
|
||||
EXPECT_TRUE(rtp_packet.Parse(packet, length));
|
||||
rtp_sequence_numbers.push_back(rtp_packet.SequenceNumber());
|
||||
transport_sequence_numbers.push_back(options.packet_id);
|
||||
if (transport_sequence_numbers.size() == 2) {
|
||||
event.Set();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
EXPECT_EQ(
|
||||
EncodedImageCallback::Result::OK,
|
||||
test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error);
|
||||
encoded_image.SetTimestamp(2);
|
||||
encoded_image.capture_time_ms_ = 3;
|
||||
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 both packet.
|
||||
rtcp::Nack nack;
|
||||
nack.SetMediaSsrc(kSsrc1);
|
||||
nack.SetPacketIds(rtp_sequence_numbers);
|
||||
rtc::Buffer nack_buffer = nack.Build();
|
||||
|
||||
std::vector<uint16_t> retransmitted_rtp_sequence_numbers;
|
||||
EXPECT_CALL(test.transport(), SendRtp)
|
||||
.Times(2)
|
||||
.WillRepeatedly([&event, &retransmitted_rtp_sequence_numbers](
|
||||
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<const uint8_t> payload = rtp_packet.payload();
|
||||
retransmitted_rtp_sequence_numbers.push_back(
|
||||
ByteReader<uint16_t>::ReadBigEndian(payload.data()));
|
||||
if (retransmitted_rtp_sequence_numbers.size() == 2) {
|
||||
event.Set();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
|
||||
ASSERT_TRUE(event.Wait(kTimeoutMs));
|
||||
|
||||
// Verify that both packets were retransmitted.
|
||||
EXPECT_EQ(retransmitted_rtp_sequence_numbers, rtp_sequence_numbers);
|
||||
|
||||
// Simulate transport feedback indicating fist packet received, next packet
|
||||
// lost.
|
||||
PacketFeedback received_packet_feedback(test.clock().TimeInMilliseconds(),
|
||||
transport_sequence_numbers[0]);
|
||||
received_packet_feedback.rtp_sequence_number = rtp_sequence_numbers[0];
|
||||
received_packet_feedback.ssrc = kSsrc1;
|
||||
|
||||
PacketFeedback lost_packet_feedback(PacketFeedback::kNotReceived,
|
||||
transport_sequence_numbers[1]);
|
||||
lost_packet_feedback.rtp_sequence_number = rtp_sequence_numbers[1];
|
||||
lost_packet_feedback.ssrc = kSsrc1;
|
||||
std::vector<PacketFeedback> feedback_vector = {received_packet_feedback,
|
||||
lost_packet_feedback};
|
||||
|
||||
test.router()->OnPacketFeedbackVector(feedback_vector);
|
||||
|
||||
// Advance time to make sure retransmission would be allowed and try again.
|
||||
// This time the retransmission should not happen for the first packet since
|
||||
// the history has been notified of the ack and removed the packet. The
|
||||
// second packet, included in the feedback but not marked as received, should
|
||||
// still be retransmitted.
|
||||
test.clock().AdvanceTimeMilliseconds(33);
|
||||
EXPECT_CALL(test.transport(), SendRtp)
|
||||
.WillOnce([&event, &lost_packet_feedback](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<const uint8_t> payload = rtp_packet.payload();
|
||||
EXPECT_EQ(lost_packet_feedback.rtp_sequence_number,
|
||||
ByteReader<uint16_t>::ReadBigEndian(payload.data()));
|
||||
event.Set();
|
||||
return true;
|
||||
});
|
||||
test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
|
||||
ASSERT_TRUE(event.Wait(kTimeoutMs));
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
@ -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
|
||||
// **************************************************************************
|
||||
|
||||
@ -16,7 +16,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "absl/types/variant.h"
|
||||
#include "api/array_view.h"
|
||||
#include "api/audio_codecs/audio_format.h"
|
||||
#include "api/rtp_headers.h"
|
||||
#include "api/transport/network_types.h"
|
||||
@ -276,7 +278,7 @@ struct PacketFeedback {
|
||||
PacedPacketInfo pacing_info;
|
||||
|
||||
// The SSRC and RTP sequence number of the packet this feedback refers to.
|
||||
uint32_t ssrc;
|
||||
absl::optional<uint32_t> ssrc;
|
||||
uint16_t rtp_sequence_number;
|
||||
};
|
||||
|
||||
@ -313,6 +315,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<const uint16_t> 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
|
||||
|
||||
@ -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*());
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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<uint16_t>& nack_sequence_numbers) override;
|
||||
|
||||
@ -1219,6 +1219,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;
|
||||
@ -1250,4 +1251,9 @@ void RTPSender::SetRtt(int64_t rtt_ms) {
|
||||
packet_history_.SetRtt(rtt_ms);
|
||||
flexfec_packet_history_.SetRtt(rtt_ms);
|
||||
}
|
||||
|
||||
void RTPSender::OnPacketsAcknowledged(
|
||||
rtc::ArrayView<const uint16_t> sequence_numbers) {
|
||||
packet_history_.CullAcknowledgedPackets(sequence_numbers);
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
@ -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<const uint16_t> 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user