зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1685245 - cherry pick upstream libwebrtc commit 6aba07e5fe. r=ng
Differential Revision: https://phabricator.services.mozilla.com/D176944
This commit is contained in:
Родитель
b6dfae8232
Коммит
d76b172306
|
@ -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];
|
||||||
|
|
Загрузка…
Ссылка в новой задаче