Add original SSRC to RtpPacketToSend and implement RtpPacketSendInfo::From method.

The purpose is to be able to create a RtpPacketSendInfo from Pacing and  RtpPacketSendInfo only.
This allow further refactoring where we directly in PacketRouter can notify BWE and early loss detection that a packet will be sent.
RtpPacketSendInfo::From is mostly added to be able to test conversion.


Bug: webrtc:15368
Change-Id: I5ebe2dc91d2eedf2c86e62c3f9738437082a49e4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/343766
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41961}
This commit is contained in:
Per K 2024-03-22 17:00:29 +01:00 committed by WebRTC LUCI CQ
parent 3a69bc38b7
commit ff7a557f2e
10 changed files with 230 additions and 61 deletions

View File

@ -210,6 +210,7 @@ rtc_library("rtp_rtcp") {
"source/rtp_header_extension_size.h",
"source/rtp_packet_history.cc",
"source/rtp_packet_history.h",
"source/rtp_packet_send_info.cc",
"source/rtp_packetizer_av1.cc",
"source/rtp_packetizer_av1.h",
"source/rtp_rtcp_config.h",
@ -610,6 +611,7 @@ if (rtc_include_tests) {
"source/rtp_header_extension_map_unittest.cc",
"source/rtp_header_extension_size_unittest.cc",
"source/rtp_packet_history_unittest.cc",
"source/rtp_packet_send_info_unittest.cc",
"source/rtp_packet_unittest.cc",
"source/rtp_packetizer_av1_unittest.cc",
"source/rtp_rtcp_impl2_unittest.cc",

View File

@ -13,6 +13,7 @@
#include <stddef.h>
#include <cstdint>
#include <memory>
#include <vector>
@ -185,6 +186,9 @@ enum class RtpPacketMediaType : size_t {
};
struct RtpPacketSendInfo {
static RtpPacketSendInfo From(const RtpPacketToSend& rtp_packet_to_send,
const PacedPacketInfo& pacing_info);
uint16_t transport_sequence_number = 0;
absl::optional<uint32_t> media_ssrc;
uint16_t rtp_sequence_number = 0; // Only valid if `media_ssrc` is set.

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2024 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <cstdint>
#include "absl/types/optional.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
namespace webrtc {
RtpPacketSendInfo RtpPacketSendInfo::From(const RtpPacketToSend& packet,
const PacedPacketInfo& pacing_info) {
RtpPacketSendInfo packet_info;
if (packet.transport_sequence_number()) {
packet_info.transport_sequence_number =
*packet.transport_sequence_number() & 0xFFFF;
} else {
absl::optional<uint16_t> packet_id =
packet.GetExtension<TransportSequenceNumber>();
if (packet_id) {
packet_info.transport_sequence_number = *packet_id;
}
}
packet_info.rtp_timestamp = packet.Timestamp();
packet_info.length = packet.size();
packet_info.pacing_info = pacing_info;
packet_info.packet_type = packet.packet_type();
switch (*packet_info.packet_type) {
case RtpPacketMediaType::kAudio:
case RtpPacketMediaType::kVideo:
packet_info.media_ssrc = packet.Ssrc();
packet_info.rtp_sequence_number = packet.SequenceNumber();
break;
case RtpPacketMediaType::kRetransmission:
RTC_DCHECK(packet.original_ssrc() &&
packet.retransmitted_sequence_number());
// For retransmissions, we're want to remove the original media packet
// if the retransmit arrives - so populate that in the packet info.
packet_info.media_ssrc = packet.original_ssrc().value_or(0);
packet_info.rtp_sequence_number =
packet.retransmitted_sequence_number().value_or(0);
break;
case RtpPacketMediaType::kPadding:
case RtpPacketMediaType::kForwardErrorCorrection:
// We're not interested in feedback about these packets being received
// or lost.
break;
}
return packet_info;
}
} // namespace webrtc

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2024 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <cstdint>
#include "absl/types/optional.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
RtpPacketToSend BuildPacket(RtpPacketMediaType type) {
RtpHeaderExtensionMap extension_manager;
RtpPacketToSend packet(&extension_manager);
packet.SetSsrc(1);
packet.SetSequenceNumber(89);
if (type == RtpPacketMediaType::kRetransmission) {
packet.set_original_ssrc(2);
packet.set_retransmitted_sequence_number(678);
}
packet.set_transport_sequence_number(0xFFFFFFFF01);
packet.SetTimestamp(123);
packet.SetPayloadSize(5);
packet.set_packet_type(type);
return packet;
}
void VerifyDefaultProperties(const RtpPacketSendInfo& send_info,
const RtpPacketToSend& packet,
const PacedPacketInfo& paced_info) {
EXPECT_EQ(send_info.length, packet.size());
EXPECT_EQ(send_info.rtp_timestamp, packet.Timestamp());
EXPECT_EQ(send_info.packet_type, packet.packet_type());
EXPECT_EQ(send_info.pacing_info, paced_info);
if (packet.transport_sequence_number()) {
EXPECT_EQ(send_info.transport_sequence_number,
*packet.transport_sequence_number() & 0xFFFF);
} else {
EXPECT_EQ(send_info.transport_sequence_number,
*packet.GetExtension<TransportSequenceNumber>());
}
}
TEST(RtpPacketSendInfoTest, FromConvertsMediaPackets) {
RtpPacketToSend packet = BuildPacket(RtpPacketMediaType::kAudio);
PacedPacketInfo paced_info;
paced_info.probe_cluster_id = 8;
RtpPacketSendInfo send_info = RtpPacketSendInfo::From(packet, paced_info);
EXPECT_EQ(send_info.media_ssrc, packet.Ssrc());
VerifyDefaultProperties(send_info, packet, paced_info);
}
TEST(RtpPacketSendInfoTest, FromConvertsPadding) {
RtpPacketToSend packet = BuildPacket(RtpPacketMediaType::kPadding);
PacedPacketInfo paced_info;
paced_info.probe_cluster_id = 8;
RtpPacketSendInfo send_info = RtpPacketSendInfo::From(packet, paced_info);
EXPECT_EQ(send_info.media_ssrc, absl::nullopt);
VerifyDefaultProperties(send_info, packet, paced_info);
}
TEST(RtpPacketSendInfoTest, FromConvertsFec) {
RtpPacketToSend packet =
BuildPacket(RtpPacketMediaType::kForwardErrorCorrection);
PacedPacketInfo paced_info;
paced_info.probe_cluster_id = 8;
RtpPacketSendInfo send_info = RtpPacketSendInfo::From(packet, paced_info);
EXPECT_EQ(send_info.media_ssrc, absl::nullopt);
VerifyDefaultProperties(send_info, packet, paced_info);
}
TEST(RtpPacketSendInfoTest, FromConvertsRetransmission) {
RtpPacketToSend packet = BuildPacket(RtpPacketMediaType::kRetransmission);
PacedPacketInfo paced_info;
paced_info.probe_cluster_id = 8;
RtpPacketSendInfo send_info = RtpPacketSendInfo::From(packet, paced_info);
EXPECT_EQ(send_info.media_ssrc, *packet.original_ssrc());
EXPECT_EQ(send_info.rtp_sequence_number,
*packet.retransmitted_sequence_number());
VerifyDefaultProperties(send_info, packet, paced_info);
}
TEST(RtpPacketSendInfoTest, FromFallbackToTranportSequenceHeaderExtension) {
RtpHeaderExtensionMap extension_manager;
extension_manager.Register<TransportSequenceNumber>(/*id=*/1);
PacedPacketInfo paced_info;
paced_info.probe_cluster_id = 8;
RtpPacketToSend packet(&extension_manager);
packet.SetSsrc(1);
packet.SetSequenceNumber(89);
const uint16_t kTransportSequenceNumber = 5555;
packet.SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
packet.SetTimestamp(123);
packet.AllocatePayload(5);
packet.set_packet_type(RtpPacketMediaType::kAudio);
RtpPacketSendInfo send_info = RtpPacketSendInfo::From(packet, paced_info);
VerifyDefaultProperties(send_info, packet, paced_info);
}
} // namespace
} // namespace webrtc

View File

@ -71,6 +71,11 @@ class RtpPacketToSend : public RtpPacket {
return retransmitted_sequence_number_;
}
// If this is a retransmission, indicates the SSRC of the original
// media packet that this packet represents.
void set_original_ssrc(uint32_t ssrc) { original_ssrc_ = ssrc; }
absl::optional<uint32_t> original_ssrc() const { return original_ssrc_; }
void set_allow_retransmission(bool allow_retransmission) {
allow_retransmission_ = allow_retransmission;
}
@ -149,6 +154,7 @@ class RtpPacketToSend : public RtpPacket {
webrtc::Timestamp capture_time_ = webrtc::Timestamp::Zero();
absl::optional<RtpPacketMediaType> packet_type_;
absl::optional<OriginalType> original_packet_type_;
absl::optional<uint32_t> original_ssrc_;
absl::optional<int64_t> transport_sequence_number_;
bool allow_retransmission_ = false;
absl::optional<uint16_t> retransmitted_sequence_number_;

View File

@ -291,6 +291,7 @@ int32_t RTPSender::ReSendPacket(uint16_t packet_id) {
if (retransmit_packet) {
retransmit_packet->set_retransmitted_sequence_number(
stored_packet.SequenceNumber());
retransmit_packet->set_original_ssrc(stored_packet.Ssrc());
}
return retransmit_packet;
});

View File

@ -269,8 +269,9 @@ void RtpSenderEgress::CompleteSendPacket(const Packet& compound_packet,
} else if (packet->transport_sequence_number()) {
options.packet_id = *packet->transport_sequence_number();
}
if (options.packet_id >= 0) {
AddPacketToTransportFeedback(options.packet_id, *packet, pacing_info);
if (options.packet_id >= 0 && transport_feedback_observer_) {
transport_feedback_observer_->OnAddPacket(
RtpPacketSendInfo::From(*packet, pacing_info));
}
if (packet->packet_type() != RtpPacketMediaType::kPadding &&
@ -415,42 +416,6 @@ bool RtpSenderEgress::HasCorrectSsrc(const RtpPacketToSend& packet) const {
return false;
}
void RtpSenderEgress::AddPacketToTransportFeedback(
uint16_t packet_id,
const RtpPacketToSend& packet,
const PacedPacketInfo& pacing_info) {
if (transport_feedback_observer_) {
RtpPacketSendInfo packet_info;
packet_info.transport_sequence_number = packet_id;
packet_info.rtp_timestamp = packet.Timestamp();
packet_info.length = packet.size();
packet_info.pacing_info = pacing_info;
packet_info.packet_type = packet.packet_type();
switch (*packet_info.packet_type) {
case RtpPacketMediaType::kAudio:
case RtpPacketMediaType::kVideo:
packet_info.media_ssrc = ssrc_;
packet_info.rtp_sequence_number = packet.SequenceNumber();
break;
case RtpPacketMediaType::kRetransmission:
// For retransmissions, we're want to remove the original media packet
// if the retransmit arrives - so populate that in the packet info.
packet_info.media_ssrc = ssrc_;
packet_info.rtp_sequence_number =
*packet.retransmitted_sequence_number();
break;
case RtpPacketMediaType::kPadding:
case RtpPacketMediaType::kForwardErrorCorrection:
// We're not interested in feedback about these packets being received
// or lost.
break;
}
transport_feedback_observer_->OnAddPacket(packet_info);
}
}
bool RtpSenderEgress::SendPacketToNetwork(const RtpPacketToSend& packet,
const PacketOptions& options,
const PacedPacketInfo& pacing_info) {

View File

@ -110,9 +110,6 @@ class RtpSenderEgress {
};
void CompleteSendPacket(const Packet& compound_packet, bool last_in_batch);
bool HasCorrectSsrc(const RtpPacketToSend& packet) const;
void AddPacketToTransportFeedback(uint16_t packet_id,
const RtpPacketToSend& packet,
const PacedPacketInfo& pacing_info);
// Sends packet on to `transport_`, leaving the RTP module.
bool SendPacketToNetwork(const RtpPacketToSend& packet,

View File

@ -10,6 +10,7 @@
#include "modules/rtp_rtcp/source/rtp_sender_egress.h"
#include <cstdint>
#include <string>
#include "absl/types/optional.h"
@ -201,7 +202,7 @@ TEST_F(RtpSenderEgressTest, TransportFeedbackObserverGetsCorrectByteCount) {
Field(&RtpPacketSendInfo::pacing_info, PacedPacketInfo()))));
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
packet->set_transport_sequence_number(kTransportSequenceNumber);
packet->AllocatePayload(kPayloadSize);
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
@ -277,6 +278,7 @@ TEST_F(RtpSenderEgressTest,
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_transport_sequence_number(1);
sender->SendPacket(std::move(packet), PacedPacketInfo());
EXPECT_TRUE(transport_.last_packet()->options.included_in_feedback);
}
@ -289,6 +291,7 @@ TEST_F(
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_transport_sequence_number(1);
sender->SendPacket(std::move(packet), PacedPacketInfo());
EXPECT_TRUE(transport_.last_packet()->options.included_in_allocation);
}
@ -397,7 +400,7 @@ TEST_F(RtpSenderEgressTest, OnSendPacketUpdated) {
send_packet_observer_,
OnSendPacket(Eq(kTransportSequenceNumber), clock_->CurrentTime(), kSsrc));
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
packet->set_transport_sequence_number(kTransportSequenceNumber);
sender->SendPacket(std::move(packet), PacedPacketInfo());
}
@ -417,9 +420,10 @@ TEST_F(RtpSenderEgressTest, OnSendPacketNotUpdatedForRetransmits) {
const uint16_t kTransportSequenceNumber = 1;
EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(0);
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
packet->set_transport_sequence_number(kTransportSequenceNumber);
packet->set_packet_type(RtpPacketMediaType::kRetransmission);
packet->set_retransmitted_sequence_number(packet->SequenceNumber());
packet->set_original_ssrc(packet->Ssrc());
sender->SendPacket(std::move(packet), PacedPacketInfo());
}
@ -794,14 +798,16 @@ TEST_F(RtpSenderEgressTest, SendPacketUpdatesExtensions) {
TEST_F(RtpSenderEgressTest, SendPacketSetsPacketOptions) {
const uint16_t kPacketId = 42;
const uint16_t kSequenceNumber = 456;
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->SetExtension<TransportSequenceNumber>(kPacketId);
uint32_t ssrc = packet->Ssrc();
packet->SetSequenceNumber(kSequenceNumber);
packet->set_transport_sequence_number(kPacketId);
EXPECT_CALL(send_packet_observer_, OnSendPacket);
auto packet_sequence_number = packet->SequenceNumber();
sender->SendPacket(std::move(packet), PacedPacketInfo());
PacketOptions packet_options = transport_.last_packet()->options;
@ -813,9 +819,10 @@ TEST_F(RtpSenderEgressTest, SendPacketSetsPacketOptions) {
// Send another packet as retransmission, verify options are populated.
std::unique_ptr<RtpPacketToSend> retransmission = BuildRtpPacket();
retransmission->SetExtension<TransportSequenceNumber>(kPacketId + 1);
retransmission->set_transport_sequence_number(kPacketId + 1);
retransmission->set_packet_type(RtpPacketMediaType::kRetransmission);
retransmission->set_retransmitted_sequence_number(packet_sequence_number);
retransmission->set_retransmitted_sequence_number(kSequenceNumber);
retransmission->set_original_ssrc(ssrc);
sender->SendPacket(std::move(retransmission), PacedPacketInfo());
EXPECT_TRUE(transport_.last_packet()->options.is_retransmit);
}
@ -879,20 +886,21 @@ TEST_F(RtpSenderEgressTest, SendPacketUpdatesStats) {
std::unique_ptr<RtpPacketToSend> video_packet = BuildRtpPacket();
video_packet->set_packet_type(RtpPacketMediaType::kVideo);
video_packet->SetPayloadSize(kPayloadSize);
video_packet->SetExtension<TransportSequenceNumber>(1);
video_packet->set_transport_sequence_number(1);
std::unique_ptr<RtpPacketToSend> rtx_packet = BuildRtpPacket();
rtx_packet->SetSsrc(kRtxSsrc);
rtx_packet->set_packet_type(RtpPacketMediaType::kRetransmission);
rtx_packet->set_original_ssrc(video_packet->Ssrc());
rtx_packet->set_retransmitted_sequence_number(video_packet->SequenceNumber());
rtx_packet->SetPayloadSize(kPayloadSize);
rtx_packet->SetExtension<TransportSequenceNumber>(2);
rtx_packet->set_transport_sequence_number(2);
std::unique_ptr<RtpPacketToSend> fec_packet = BuildRtpPacket();
fec_packet->SetSsrc(kFlexFecSsrc);
fec_packet->set_packet_type(RtpPacketMediaType::kForwardErrorCorrection);
fec_packet->SetPayloadSize(kPayloadSize);
fec_packet->SetExtension<TransportSequenceNumber>(3);
fec_packet->set_transport_sequence_number(3);
const int64_t kDiffMs = 25;
time_controller_.AdvanceTime(TimeDelta::Millis(kDiffMs));
@ -924,8 +932,8 @@ TEST_F(RtpSenderEgressTest, TransportFeedbackObserverWithRetransmission) {
TransportSequenceNumber::Uri());
std::unique_ptr<RtpPacketToSend> retransmission = BuildRtpPacket();
retransmission->set_packet_type(RtpPacketMediaType::kRetransmission);
retransmission->SetExtension<TransportSequenceNumber>(
kTransportSequenceNumber);
retransmission->set_transport_sequence_number(kTransportSequenceNumber);
retransmission->set_original_ssrc(kSsrc);
uint16_t retransmitted_seq = retransmission->SequenceNumber() - 2;
retransmission->set_retransmitted_sequence_number(retransmitted_seq);
@ -947,8 +955,8 @@ TEST_F(RtpSenderEgressTest, TransportFeedbackObserverWithRtxRetransmission) {
std::unique_ptr<RtpPacketToSend> rtx_retransmission = BuildRtpPacket();
rtx_retransmission->SetSsrc(kRtxSsrc);
rtx_retransmission->SetExtension<TransportSequenceNumber>(
kTransportSequenceNumber);
rtx_retransmission->set_transport_sequence_number(kTransportSequenceNumber);
rtx_retransmission->set_original_ssrc(kSsrc);
rtx_retransmission->set_packet_type(RtpPacketMediaType::kRetransmission);
uint16_t rtx_retransmitted_seq = rtx_retransmission->SequenceNumber() - 2;
rtx_retransmission->set_retransmitted_sequence_number(rtx_retransmitted_seq);
@ -971,7 +979,7 @@ TEST_F(RtpSenderEgressTest, TransportFeedbackObserverPadding) {
std::unique_ptr<RtpPacketToSend> padding = BuildRtpPacket();
padding->SetPadding(224);
padding->set_packet_type(RtpPacketMediaType::kPadding);
padding->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
padding->set_transport_sequence_number(kTransportSequenceNumber);
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
EXPECT_CALL(
@ -991,7 +999,7 @@ TEST_F(RtpSenderEgressTest, TransportFeedbackObserverRtxPadding) {
rtx_padding->SetPadding(224);
rtx_padding->SetSsrc(kRtxSsrc);
rtx_padding->set_packet_type(RtpPacketMediaType::kPadding);
rtx_padding->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
rtx_padding->set_transport_sequence_number(kTransportSequenceNumber);
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
EXPECT_CALL(
@ -1010,7 +1018,7 @@ TEST_F(RtpSenderEgressTest, TransportFeedbackObserverFec) {
std::unique_ptr<RtpPacketToSend> fec_packet = BuildRtpPacket();
fec_packet->SetSsrc(kFlexFecSsrc);
fec_packet->set_packet_type(RtpPacketMediaType::kForwardErrorCorrection);
fec_packet->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
fec_packet->set_transport_sequence_number(kTransportSequenceNumber);
const rtc::ArrayView<const RtpExtensionSize> kNoRtpHeaderExtensionSizes;
FlexfecSender flexfec(kFlexfectPayloadType, kFlexFecSsrc, kSsrc, /*mid=*/"",

View File

@ -1017,7 +1017,10 @@ TEST_F(RtpSenderTest, MarksRetransmittedPackets) {
// Build a media packet and put in the packet history.
std::unique_ptr<RtpPacketToSend> packet =
BuildRtpPacket(kPayload, true, 0, clock_->CurrentTime());
const uint16_t media_sequence_number = packet->SequenceNumber();
const uint32_t kMediaSsrc = 567;
const uint16_t kMediaSequenceNumber = 123;
packet->SetSsrc(kMediaSsrc);
packet->SetSequenceNumber(kMediaSequenceNumber);
packet->set_allow_retransmission(true);
packet_history_->PutRtpPacket(std::move(packet), clock_->CurrentTime());
@ -1028,9 +1031,10 @@ TEST_F(RtpSenderTest, MarksRetransmittedPackets) {
EnqueuePackets(ElementsAre(AllOf(
Pointee(Property(&RtpPacketToSend::packet_type,
RtpPacketMediaType::kRetransmission)),
Pointee(Property(&RtpPacketToSend::original_ssrc, kMediaSsrc)),
Pointee(Property(&RtpPacketToSend::retransmitted_sequence_number,
Eq(media_sequence_number)))))));
EXPECT_THAT(rtp_sender_->ReSendPacket(media_sequence_number), Gt(0));
Eq(kMediaSequenceNumber)))))));
EXPECT_THAT(rtp_sender_->ReSendPacket(kMediaSequenceNumber), Gt(0));
}
TEST_F(RtpSenderTest, GeneratedPaddingHasBweExtensions) {