Add SetRetransmissionMode() to FecController, this will be used to control RTX settings in FecController.

Currently FecController knows about network conditions, these information can be used to control RTX settings in-call.

Change-Id: I8f84164aeac48ea13b7f1cf82fd7424431f98ada
Bug: webrtc:15167
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/304800
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Commit-Queue: Ying Wang <yinwa@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40192}
This commit is contained in:
Ying Wang 2023-06-01 13:55:36 +08:00 committed by WebRTC LUCI CQ
parent 3d6e88e6ac
commit 2d598535aa
7 changed files with 104 additions and 2 deletions

View File

@ -31,6 +31,9 @@ class VCMProtectionCallback {
uint32_t* sent_nack_rate_bps,
uint32_t* sent_fec_rate_bps) = 0;
// 'retransmission_mode' is either a value of enum RetransmissionMode, or
// computed with bitwise operators on values of enum RetransmissionMode.
virtual void SetRetransmissionMode(int retransmission_mode) = 0;
protected:
virtual ~VCMProtectionCallback() {}
};

View File

@ -935,6 +935,13 @@ int RtpVideoSender::ProtectionRequest(const FecProtectionParams* delta_params,
return 0;
}
void RtpVideoSender::SetRetransmissionMode(int retransmission_mode) {
MutexLock lock(&mutex_);
for (const RtpStreamSender& stream : rtp_streams_) {
stream.sender_video->SetRetransmissionSetting(retransmission_mode);
}
}
void RtpVideoSender::SetFecAllowed(bool fec_allowed) {
MutexLock lock(&mutex_);
fec_allowed_ = fec_allowed;

View File

@ -120,6 +120,11 @@ class RtpVideoSender : public RtpVideoSenderInterface,
uint32_t* sent_fec_rate_bps)
RTC_LOCKS_EXCLUDED(mutex_) override;
// 'retransmission_mode' is either a value of enum RetransmissionMode, or
// computed with bitwise operators on values of enum RetransmissionMode.
void SetRetransmissionMode(int retransmission_mode)
RTC_LOCKS_EXCLUDED(mutex_) override;
// Implements FecControllerOverride.
void SetFecAllowed(bool fec_allowed) RTC_LOCKS_EXCLUDED(mutex_) override;

View File

@ -1160,4 +1160,82 @@ TEST(RtpVideoSenderTest, ClearsPendingPacketsOnInactivation) {
EXPECT_NE(sent_packets[0].Timestamp(), first_frame_timestamp);
}
// Integration test verifying that when retransmission mode is set to
// kRetransmitBaseLayer,only base layer is retransmitted.
TEST(RtpVideoSenderTest, RetransmitsBaseLayerOnly) {
RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, {kRtxSsrc1, kRtxSsrc2},
kPayloadType, {});
test.SetActiveModules({true, true});
test.router()->SetRetransmissionMode(kRetransmitBaseLayer);
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.SetEncodedData(EncodedImageBuffer::Create(&kPayload, 1));
// Send two tiny images, mapping to two RTP packets. Capture sequence numbers.
std::vector<uint16_t> rtp_sequence_numbers;
std::vector<uint16_t> transport_sequence_numbers;
std::vector<uint16_t> base_sequence_numbers;
EXPECT_CALL(test.transport(), SendRtp)
.Times(2)
.WillRepeatedly([&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);
return true;
});
CodecSpecificInfo key_codec_info;
key_codec_info.codecType = kVideoCodecVP8;
key_codec_info.codecSpecific.VP8.temporalIdx = 0;
EXPECT_EQ(EncodedImageCallback::Result::OK,
test.router()->OnEncodedImage(
encoded_image, &key_codec_info).error);
encoded_image.SetTimestamp(2);
encoded_image.capture_time_ms_ = 3;
encoded_image._frameType = VideoFrameType::kVideoFrameDelta;
CodecSpecificInfo delta_codec_info;
delta_codec_info.codecType = kVideoCodecVP8;
delta_codec_info.codecSpecific.VP8.temporalIdx = 1;
EXPECT_EQ(EncodedImageCallback::Result::OK,
test.router()->OnEncodedImage(
encoded_image, &delta_codec_info).error);
test.AdvanceTime(TimeDelta::Millis(33));
// 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(1)
.WillRepeatedly([&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()));
return true;
});
test.router()->DeliverRtcp(nack_buffer.data(), nack_buffer.size());
test.AdvanceTime(TimeDelta::Millis(33));
// Verify that only base layer packet was retransmitted.
std::vector<uint16_t> base_rtp_sequence_numbers(rtp_sequence_numbers.begin(),
rtp_sequence_numbers.begin() + 1);
EXPECT_EQ(retransmitted_rtp_sequence_numbers, base_rtp_sequence_numbers);
}
} // namespace webrtc

View File

@ -223,6 +223,11 @@ size_t RTPSenderVideo::FecPacketOverhead() const {
return overhead;
}
void RTPSenderVideo::SetRetransmissionSetting(int32_t retransmission_settings) {
RTC_DCHECK_RUNS_SERIALIZED(&send_checker_);
retransmission_settings_ = retransmission_settings;
}
void RTPSenderVideo::SetVideoStructure(
const FrameDependencyStructure* video_structure) {
if (frame_transformer_delegate_) {

View File

@ -149,6 +149,10 @@ class RTPSenderVideo : public RTPVideoFrameSenderInterface {
// place as the other rate stats.
DataRate PostEncodeOverhead() const;
// 'retransmission_mode' is either a value of enum RetransmissionMode, or
// computed with bitwise operators on values of enum RetransmissionMode.
void SetRetransmissionSetting(int32_t retransmission_settings);
protected:
static uint8_t GetTemporalId(const RTPVideoHeader& header);
bool AllowRetransmission(uint8_t temporal_id,
@ -201,11 +205,10 @@ class RTPSenderVideo : public RTPVideoFrameSenderInterface {
RTPSender* const rtp_sender_;
Clock* const clock_;
const int32_t retransmission_settings_;
// These members should only be accessed from within SendVideo() to avoid
// potential race conditions.
rtc::RaceChecker send_checker_;
int32_t retransmission_settings_ RTC_GUARDED_BY(send_checker_);
VideoRotation last_rotation_ RTC_GUARDED_BY(send_checker_);
absl::optional<ColorSpace> last_color_space_ RTC_GUARDED_BY(send_checker_);
bool transmit_color_space_next_frame_ RTC_GUARDED_BY(send_checker_);

View File

@ -41,6 +41,7 @@ class ProtectionBitrateCalculatorTest : public ::testing::Test {
*sent_fec_rate_bps = fec_rate_bps_;
return 0;
}
void SetRetransmissionMode(int retransmission_mode) {}
uint32_t fec_rate_bps_ = 0;
uint32_t nack_rate_bps_ = 0;