Bug 1685245 - cherry pick upstream libwebrtc commit 6aba07e5fe. r=ng

Differential Revision: https://phabricator.services.mozilla.com/D176944
This commit is contained in:
Michael Froman 2023-05-03 14:41:38 +00:00
Родитель b6dfae8232
Коммит d76b172306
4 изменённых файлов: 117 добавлений и 12 удалений

Просмотреть файл

@ -558,6 +558,39 @@ std::unique_ptr<RtpPacketToSend> RTPSender::AllocatePacket() const {
return packet; return packet;
} }
size_t RTPSender::RtxPacketOverhead() const {
MutexLock lock(&send_mutex_);
if (rtx_ == kRtxOff) {
return 0;
}
size_t overhead = 0;
// Count space for the RTP header extensions that might need to be added to
// the RTX packet.
if (!always_send_mid_and_rid_ && (!rtx_ssrc_has_acked_ && ssrc_has_acked_)) {
// Prefer to reserve extra byte in case two byte header rtp header
// extensions are used.
static constexpr int kRtpExtensionHeaderSize = 2;
// Rtx packets hasn't been acked and would need to have mid and rrsid rtp
// header extensions, while media packets no longer needs to include mid and
// rsid extensions.
if (!mid_.empty()) {
overhead += (kRtpExtensionHeaderSize + mid_.size());
}
if (!rid_.empty()) {
overhead += (kRtpExtensionHeaderSize + rid_.size());
}
// RTP header extensions are rounded up to 4 bytes. Depending on already
// present extensions adding mid & rrsid may add up to 3 bytes of padding.
overhead += 3;
}
// Add two bytes for the original sequence number in the RTP payload.
overhead += kRtxHeaderSize;
return overhead;
}
void RTPSender::SetSendingMediaStatus(bool enabled) { void RTPSender::SetSendingMediaStatus(bool enabled) {
MutexLock lock(&send_mutex_); MutexLock lock(&send_mutex_);
sending_media_ = enabled; sending_media_ = enabled;

Просмотреть файл

@ -106,6 +106,9 @@ class RTPSender {
absl::optional<uint32_t> RtxSsrc() const RTC_LOCKS_EXCLUDED(send_mutex_) { absl::optional<uint32_t> RtxSsrc() const RTC_LOCKS_EXCLUDED(send_mutex_) {
return rtx_ssrc_; return rtx_ssrc_;
} }
// Returns expected size difference between an RTX packet and media packet
// that RTX packet is created from. Returns 0 if RTX is disabled.
size_t RtxPacketOverhead() const;
void SetRtxPayloadType(int payload_type, int associated_payload_type) void SetRtxPayloadType(int payload_type, int associated_payload_type)
RTC_LOCKS_EXCLUDED(send_mutex_); RTC_LOCKS_EXCLUDED(send_mutex_);

Просмотреть файл

@ -493,6 +493,13 @@ bool RTPSenderVideo::SendVideo(
// Backward compatibility for older receivers without temporal layer logic. // Backward compatibility for older receivers without temporal layer logic.
retransmission_settings = kRetransmitBaseLayer | kRetransmitHigherLayers; retransmission_settings = kRetransmitBaseLayer | kRetransmitHigherLayers;
} }
const uint8_t temporal_id = GetTemporalId(video_header);
// TODO(bugs.webrtc.org/10714): retransmission_settings_ should generally be
// replaced by expected_retransmission_time_ms.has_value().
const bool allow_retransmission =
expected_retransmission_time_ms.has_value() &&
AllowRetransmission(temporal_id, retransmission_settings,
*expected_retransmission_time_ms);
MaybeUpdateCurrentPlayoutDelay(video_header); MaybeUpdateCurrentPlayoutDelay(video_header);
if (video_header.frame_type == VideoFrameType::kVideoFrameKey) { if (video_header.frame_type == VideoFrameType::kVideoFrameKey) {
@ -514,16 +521,19 @@ bool RTPSenderVideo::SendVideo(
video_header.generic->frame_id, video_header.generic->chain_diffs); video_header.generic->frame_id, video_header.generic->chain_diffs);
} }
const uint8_t temporal_id = GetTemporalId(video_header);
// No FEC protection for upper temporal layers, if used. // No FEC protection for upper temporal layers, if used.
const bool use_fec = fec_type_.has_value() && const bool use_fec = fec_type_.has_value() &&
(temporal_id == 0 || temporal_id == kNoTemporalIdx); (temporal_id == 0 || temporal_id == kNoTemporalIdx);
// Maximum size of packet including rtp headers. // Maximum size of packet including rtp headers.
// Extra space left in case packet will be resent using fec or rtx. // Extra space left in case packet will be resent using fec or rtx.
int packet_capacity = rtp_sender_->MaxRtpPacketSize() - int packet_capacity = rtp_sender_->MaxRtpPacketSize();
(use_fec ? FecPacketOverhead() : 0) - if (use_fec) {
(rtp_sender_->RtxStatus() ? kRtxHeaderSize : 0); packet_capacity -= FecPacketOverhead();
}
if (allow_retransmission) {
packet_capacity -= rtp_sender_->RtxPacketOverhead();
}
absl::optional<Timestamp> capture_time; absl::optional<Timestamp> capture_time;
if (capture_time_ms > 0) { if (capture_time_ms > 0) {
@ -652,14 +662,6 @@ bool RTPSenderVideo::SendVideo(
std::unique_ptr<RtpPacketizer> packetizer = std::unique_ptr<RtpPacketizer> packetizer =
RtpPacketizer::Create(codec_type, payload, limits, video_header); RtpPacketizer::Create(codec_type, payload, limits, video_header);
// TODO(bugs.webrtc.org/10714): retransmission_settings_ should generally be
// replaced by expected_retransmission_time_ms.has_value(). For now, though,
// only VP8 with an injected frame buffer controller actually controls it.
const bool allow_retransmission =
expected_retransmission_time_ms.has_value()
? AllowRetransmission(temporal_id, retransmission_settings,
expected_retransmission_time_ms.value())
: false;
const size_t num_packets = packetizer->NumPackets(); const size_t num_packets = packetizer->NumPackets();
if (num_packets == 0) if (num_packets == 0)

Просмотреть файл

@ -29,6 +29,9 @@
#include "api/video/video_timing.h" #include "api/video/video_timing.h"
#include "modules/rtp_rtcp/include/rtp_cvo.h" #include "modules/rtp_rtcp/include/rtp_cvo.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" #include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
#include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h" #include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h"
#include "modules/rtp_rtcp/source/rtp_format_video_generic.h" #include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
#include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h" #include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h"
@ -57,6 +60,7 @@ using ::testing::ElementsAre;
using ::testing::ElementsAreArray; using ::testing::ElementsAreArray;
using ::testing::IsEmpty; using ::testing::IsEmpty;
using ::testing::NiceMock; using ::testing::NiceMock;
using ::testing::Not;
using ::testing::Return; using ::testing::Return;
using ::testing::ReturnArg; using ::testing::ReturnArg;
using ::testing::SaveArg; using ::testing::SaveArg;
@ -81,6 +85,7 @@ constexpr VideoCodecType kType = VideoCodecType::kVideoCodecGeneric;
constexpr uint32_t kTimestamp = 10; constexpr uint32_t kTimestamp = 10;
constexpr uint16_t kSeqNum = 33; constexpr uint16_t kSeqNum = 33;
constexpr uint32_t kSsrc = 725242; constexpr uint32_t kSsrc = 725242;
constexpr uint32_t kRtxSsrc = 912364;
constexpr int kMaxPacketLength = 1500; constexpr int kMaxPacketLength = 1500;
constexpr Timestamp kStartTime = Timestamp::Millis(123456789); constexpr Timestamp kStartTime = Timestamp::Millis(123456789);
constexpr int64_t kDefaultExpectedRetransmissionTimeMs = 125; constexpr int64_t kDefaultExpectedRetransmissionTimeMs = 125;
@ -182,6 +187,8 @@ class RtpSenderVideoTest : public ::testing::Test {
config.retransmission_rate_limiter = &retransmission_rate_limiter_; config.retransmission_rate_limiter = &retransmission_rate_limiter_;
config.field_trials = &field_trials_; config.field_trials = &field_trials_;
config.local_media_ssrc = kSsrc; config.local_media_ssrc = kSsrc;
config.rtx_send_ssrc = kRtxSsrc;
config.rid = "rid";
return config; return config;
}())), }())),
rtp_sender_video_( rtp_sender_video_(
@ -505,6 +512,66 @@ TEST_F(RtpSenderVideoTest, ConditionalRetransmitLimit) {
rtp_sender_video_->AllowRetransmission(header, kSettings, kRttMs)); rtp_sender_video_->AllowRetransmission(header, kSettings, kRttMs));
} }
TEST_F(RtpSenderVideoTest,
ReservesEnoughSpaceForRtxPacketWhenMidAndRsidAreRegistered) {
constexpr int kMediaPayloadId = 100;
constexpr int kRtxPayloadId = 101;
constexpr size_t kMaxPacketSize = 1'000;
rtp_module_->SetMaxRtpPacketSize(kMaxPacketSize);
rtp_module_->RegisterRtpHeaderExtension(RtpMid::Uri(), 1);
rtp_module_->RegisterRtpHeaderExtension(RtpStreamId::Uri(), 2);
rtp_module_->RegisterRtpHeaderExtension(RepairedRtpStreamId::Uri(), 3);
rtp_module_->RegisterRtpHeaderExtension(AbsoluteSendTime::Uri(), 4);
rtp_module_->SetMid("long_mid");
rtp_module_->SetRtxSendPayloadType(kRtxPayloadId, kMediaPayloadId);
rtp_module_->SetStorePacketsStatus(/*enable=*/true, 10);
rtp_module_->SetRtxSendStatus(kRtxRetransmitted);
RTPVideoHeader header;
header.codec = kVideoCodecVP8;
header.frame_type = VideoFrameType::kVideoFrameDelta;
auto& vp8_header = header.video_type_header.emplace<RTPVideoHeaderVP8>();
vp8_header.temporalIdx = 0;
uint8_t kPayload[kMaxPacketSize] = {};
EXPECT_TRUE(rtp_sender_video_->SendVideo(
kMediaPayloadId, /*codec_type=*/kVideoCodecVP8, /*rtp_timestamp=*/0,
/*capture_time_ms=*/1'000, kPayload, header,
/*expected_retransmission_time_ms=*/absl::nullopt, /*csrcs=*/{}));
ASSERT_THAT(transport_.sent_packets(), Not(IsEmpty()));
// Ack media ssrc, but not rtx ssrc.
rtcp::ReceiverReport rr;
rtcp::ReportBlock rb;
rb.SetMediaSsrc(kSsrc);
rb.SetExtHighestSeqNum(transport_.last_sent_packet().SequenceNumber());
rr.AddReportBlock(rb);
rtp_module_->IncomingRtcpPacket(rr.Build());
// Test for various frame size close to `kMaxPacketSize` to catch edge cases
// when rtx packet barely fit.
for (size_t frame_size = 800; frame_size < kMaxPacketSize; ++frame_size) {
SCOPED_TRACE(frame_size);
rtc::ArrayView<const uint8_t> payload(kPayload, frame_size);
EXPECT_TRUE(rtp_sender_video_->SendVideo(
kMediaPayloadId, /*codec_type=*/kVideoCodecVP8, /*rtp_timestamp=*/0,
/*capture_time_ms=*/1'000, payload, header,
/*expected_retransmission_time_ms=*/1'000, /*csrcs=*/{}));
const RtpPacketReceived& media_packet = transport_.last_sent_packet();
EXPECT_EQ(media_packet.Ssrc(), kSsrc);
rtcp::Nack nack;
nack.SetMediaSsrc(kSsrc);
nack.SetPacketIds({media_packet.SequenceNumber()});
rtp_module_->IncomingRtcpPacket(nack.Build());
const RtpPacketReceived& rtx_packet = transport_.last_sent_packet();
EXPECT_EQ(rtx_packet.Ssrc(), kRtxSsrc);
EXPECT_LE(rtx_packet.size(), kMaxPacketSize);
}
}
TEST_F(RtpSenderVideoTest, SendsDependencyDescriptorWhenVideoStructureIsSet) { TEST_F(RtpSenderVideoTest, SendsDependencyDescriptorWhenVideoStructureIsSet) {
const int64_t kFrameId = 100000; const int64_t kFrameId = 100000;
uint8_t kFrame[100]; uint8_t kFrame[100];