Add support for receiving CongestionControlFeedback to RTCPReceiver

Support for parsing the packet is gated behind field trial
WebRTC-RFC8888CongestionControlFeedback/Enabled/.

Bug: webrtc:15368
Change-Id: Ib4478e821fe5a43510af5131543e7861cf54d901
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/348664
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42215}
This commit is contained in:
Per K 2024-05-02 19:43:35 +00:00 committed by WebRTC LUCI CQ
parent 1a436f7e9e
commit 363917a1dd
9 changed files with 105 additions and 3 deletions

View File

@ -113,6 +113,9 @@ ACTIVE_FIELD_TRIALS: FrozenSet[FieldTrial] = frozenset([
FieldTrial('WebRTC-ReceiveBufferSize', FieldTrial('WebRTC-ReceiveBufferSize',
42225927, 42225927,
date(2024, 4, 1)), date(2024, 4, 1)),
FieldTrial('WebRTC-RFC8888CongestionControlFeedback',
42225697,
date(2025, 1, 30)),
FieldTrial('WebRTC-RtcEventLogEncodeDependencyDescriptor', FieldTrial('WebRTC-RtcEventLogEncodeDependencyDescriptor',
42225280, 42225280,
date(2024, 4, 1)), date(2024, 4, 1)),

View File

@ -299,6 +299,7 @@ rtc_library("rtp_rtcp") {
"../../api/rtc_event_log", "../../api/rtc_event_log",
"../../api/task_queue:pending_task_safety_flag", "../../api/task_queue:pending_task_safety_flag",
"../../api/task_queue:task_queue", "../../api/task_queue:task_queue",
"../../api/transport:field_trial_based_config",
"../../api/transport/rtp:dependency_descriptor", "../../api/transport/rtp:dependency_descriptor",
"../../api/transport/rtp:rtp_source", "../../api/transport/rtp:rtp_source",
"../../api/units:data_rate", "../../api/units:data_rate",
@ -715,6 +716,7 @@ if (rtc_include_tests) {
"../../test:mock_transport", "../../test:mock_transport",
"../../test:rtp_test_utils", "../../test:rtp_test_utils",
"../../test:run_loop", "../../test:run_loop",
"../../test:scoped_key_value_config",
"../../test:test_support", "../../test:test_support",
"../../test/time_controller:time_controller", "../../test/time_controller:time_controller",
"../video_coding:codec_globals_headers", "../video_coding:codec_globals_headers",

View File

@ -29,6 +29,7 @@
#include "api/units/time_delta.h" #include "api/units/time_delta.h"
#include "api/units/timestamp.h" #include "api/units/timestamp.h"
#include "modules/rtp_rtcp/include/report_block_data.h" #include "modules/rtp_rtcp/include/report_block_data.h"
#include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h"
#include "modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h" #include "modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h"
#include "system_wrappers/include/clock.h" #include "system_wrappers/include/clock.h"
@ -107,7 +108,7 @@ enum RTCPPacketType : uint32_t {
kRtcpXrReceiverReferenceTime = 0x40000, kRtcpXrReceiverReferenceTime = 0x40000,
kRtcpXrDlrrReportBlock = 0x80000, kRtcpXrDlrrReportBlock = 0x80000,
kRtcpTransportFeedback = 0x100000, kRtcpTransportFeedback = 0x100000,
kRtcpXrTargetBitrate = 0x200000 kRtcpXrTargetBitrate = 0x200000,
}; };
enum class KeyFrameReqMethod : uint8_t { enum class KeyFrameReqMethod : uint8_t {
@ -164,6 +165,10 @@ class NetworkLinkRtcpObserver {
virtual void OnTransportFeedback(Timestamp receive_time, virtual void OnTransportFeedback(Timestamp receive_time,
const rtcp::TransportFeedback& feedback) {} const rtcp::TransportFeedback& feedback) {}
// RFC 8888 congestion control feedback.
virtual void OnCongestionControlFeedback(
Timestamp receive_time,
const rtcp::CongestionControlFeedback& feedback) {}
virtual void OnReceiverEstimatedMaxBitrate(Timestamp receive_time, virtual void OnReceiverEstimatedMaxBitrate(Timestamp receive_time,
DataRate bitrate) {} DataRate bitrate) {}

View File

@ -32,6 +32,11 @@ class MockNetworkLinkRtcpObserver : public NetworkLinkRtcpObserver {
OnTransportFeedback, OnTransportFeedback,
(Timestamp receive_time, const rtcp::TransportFeedback& feedback), (Timestamp receive_time, const rtcp::TransportFeedback& feedback),
(override)); (override));
MOCK_METHOD(void,
OnCongestionControlFeedback,
(Timestamp receive_time,
const rtcp::CongestionControlFeedback& feedback),
(override));
MOCK_METHOD(void, MOCK_METHOD(void,
OnReceiverEstimatedMaxBitrate, OnReceiverEstimatedMaxBitrate,
(Timestamp receive_time, DataRate bitrate), (Timestamp receive_time, DataRate bitrate),

View File

@ -19,13 +19,16 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "api/transport/field_trial_based_config.h"
#include "api/units/time_delta.h" #include "api/units/time_delta.h"
#include "api/units/timestamp.h" #include "api/units/timestamp.h"
#include "api/video/video_bitrate_allocation.h" #include "api/video/video_bitrate_allocation.h"
#include "api/video/video_bitrate_allocator.h" #include "api/video/video_bitrate_allocator.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" #include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h" #include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h"
#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h" #include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
#include "modules/rtp_rtcp/source/rtcp_packet/fir.h" #include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h" #include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
@ -131,6 +134,7 @@ struct RTCPReceiver::PacketInformation {
absl::optional<TimeDelta> rtt; absl::optional<TimeDelta> rtt;
uint32_t receiver_estimated_max_bitrate_bps = 0; uint32_t receiver_estimated_max_bitrate_bps = 0;
std::unique_ptr<rtcp::TransportFeedback> transport_feedback; std::unique_ptr<rtcp::TransportFeedback> transport_feedback;
absl::optional<rtcp::CongestionControlFeedback> congestion_control_feedback;
absl::optional<VideoBitrateAllocation> target_bitrate_allocation; absl::optional<VideoBitrateAllocation> target_bitrate_allocation;
absl::optional<NetworkStateEstimate> network_state_estimate; absl::optional<NetworkStateEstimate> network_state_estimate;
std::unique_ptr<rtcp::LossNotification> loss_notification; std::unique_ptr<rtcp::LossNotification> loss_notification;
@ -140,6 +144,8 @@ RTCPReceiver::RTCPReceiver(const RtpRtcpInterface::Configuration& config,
ModuleRtpRtcpImpl2* owner) ModuleRtpRtcpImpl2* owner)
: clock_(config.clock), : clock_(config.clock),
receiver_only_(config.receiver_only), receiver_only_(config.receiver_only),
enable_congestion_controller_feedback_(FieldTrialBasedConfig().IsEnabled(
"WebRTC-RFC8888CongestionControlFeedback")),
rtp_rtcp_(owner), rtp_rtcp_(owner),
registered_ssrcs_(false, config), registered_ssrcs_(false, config),
network_link_rtcp_observer_(config.network_link_rtcp_observer), network_link_rtcp_observer_(config.network_link_rtcp_observer),
@ -167,6 +173,8 @@ RTCPReceiver::RTCPReceiver(const RtpRtcpInterface::Configuration& config,
ModuleRtpRtcp* owner) ModuleRtpRtcp* owner)
: clock_(config.clock), : clock_(config.clock),
receiver_only_(config.receiver_only), receiver_only_(config.receiver_only),
enable_congestion_controller_feedback_(FieldTrialBasedConfig().IsEnabled(
"WebRTC-RFC8888CongestionControlFeedback")),
rtp_rtcp_(owner), rtp_rtcp_(owner),
registered_ssrcs_(true, config), registered_ssrcs_(true, config),
network_link_rtcp_observer_(config.network_link_rtcp_observer), network_link_rtcp_observer_(config.network_link_rtcp_observer),
@ -438,6 +446,13 @@ bool RTCPReceiver::ParseCompoundPacket(rtc::ArrayView<const uint8_t> packet,
case rtcp::TransportFeedback::kFeedbackMessageType: case rtcp::TransportFeedback::kFeedbackMessageType:
HandleTransportFeedback(rtcp_block, packet_information); HandleTransportFeedback(rtcp_block, packet_information);
break; break;
case rtcp::CongestionControlFeedback::kFeedbackMessageType:
if (enable_congestion_controller_feedback_) {
valid = HandleCongestionControlFeedback(rtcp_block,
packet_information);
break;
}
ABSL_FALLTHROUGH_INTENDED;
default: default:
++num_skipped_packets_; ++num_skipped_packets_;
break; break;
@ -1048,6 +1063,17 @@ void RTCPReceiver::HandleTransportFeedback(
} }
} }
bool RTCPReceiver::HandleCongestionControlFeedback(
const CommonHeader& rtcp_block,
PacketInformation* packet_information) {
rtcp::CongestionControlFeedback feedback;
if (!feedback.Parse(rtcp_block)) {
return false;
}
packet_information->congestion_control_feedback.emplace(std::move(feedback));
return true;
}
void RTCPReceiver::NotifyTmmbrUpdated() { void RTCPReceiver::NotifyTmmbrUpdated() {
// Find bounding set. // Find bounding set.
std::vector<rtcp::TmmbItem> bounding = std::vector<rtcp::TmmbItem> bounding =
@ -1137,6 +1163,10 @@ void RTCPReceiver::TriggerCallbacksFromRtcpPacket(
network_link_rtcp_observer_->OnTransportFeedback( network_link_rtcp_observer_->OnTransportFeedback(
now, *packet_information.transport_feedback); now, *packet_information.transport_feedback);
} }
if (packet_information.congestion_control_feedback) {
network_link_rtcp_observer_->OnCongestionControlFeedback(
now, *packet_information.congestion_control_feedback);
}
} }
if ((packet_information.packet_type_flags & kRtcpSr) || if ((packet_information.packet_type_flags & kRtcpSr) ||

View File

@ -342,6 +342,9 @@ class RTCPReceiver final {
void HandleTransportFeedback(const rtcp::CommonHeader& rtcp_block, void HandleTransportFeedback(const rtcp::CommonHeader& rtcp_block,
PacketInformation* packet_information) PacketInformation* packet_information)
RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
bool HandleCongestionControlFeedback(const rtcp::CommonHeader& rtcp_block,
PacketInformation* packet_information)
RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
bool RtcpRrTimeoutLocked(Timestamp now) bool RtcpRrTimeoutLocked(Timestamp now)
RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
@ -351,6 +354,7 @@ class RTCPReceiver final {
Clock* const clock_; Clock* const clock_;
const bool receiver_only_; const bool receiver_only_;
const bool enable_congestion_controller_feedback_;
ModuleRtpRtcp* const rtp_rtcp_; ModuleRtpRtcp* const rtp_rtcp_;
// The set of registered local SSRCs. // The set of registered local SSRCs.
RegisteredSsrcs registered_ssrcs_; RegisteredSsrcs registered_ssrcs_;

View File

@ -26,6 +26,7 @@
#include "modules/rtp_rtcp/source/rtcp_packet/app.h" #include "modules/rtp_rtcp/source/rtcp_packet/app.h"
#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" #include "modules/rtp_rtcp/source/rtcp_packet/bye.h"
#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h" #include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/congestion_control_feedback.h"
#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h" #include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
#include "modules/rtp_rtcp/source/rtcp_packet/fir.h" #include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" #include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
@ -44,6 +45,7 @@
#include "system_wrappers/include/ntp_time.h" #include "system_wrappers/include/ntp_time.h"
#include "test/gmock.h" #include "test/gmock.h"
#include "test/gtest.h" #include "test/gtest.h"
#include "test/scoped_key_value_config.h"
namespace webrtc { namespace webrtc {
namespace { namespace {
@ -64,6 +66,7 @@ using ::testing::SizeIs;
using ::testing::StrEq; using ::testing::StrEq;
using ::testing::StrictMock; using ::testing::StrictMock;
using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAre;
using ::webrtc::test::ScopedKeyValueConfig;
class MockRtcpPacketTypeCounterObserver : public RtcpPacketTypeCounterObserver { class MockRtcpPacketTypeCounterObserver : public RtcpPacketTypeCounterObserver {
public: public:
@ -1740,6 +1743,54 @@ TEST(RtcpReceiverTest, NotifiesNetworkLinkObserverOnTransportFeedback) {
receiver.IncomingPacket(packet.Build()); receiver.IncomingPacket(packet.Build());
} }
TEST(RtcpReceiverTest, NotifiesNetworkLinkObserverOnCongestionControlFeedback) {
ScopedKeyValueConfig trials(
"WebRTC-RFC8888CongestionControlFeedback/Enabled/");
ReceiverMocks mocks;
RtpRtcpInterface::Configuration config = DefaultConfiguration(&mocks);
RTCPReceiver receiver(config, &mocks.rtp_rtcp_impl);
receiver.SetRemoteSSRC(kSenderSsrc);
rtcp::CongestionControlFeedback packet({{
.ssrc = 123,
.sequence_number = 1,
}},
/*report_timestamp_compact_ntp=*/324);
packet.SetSenderSsrc(kSenderSsrc);
EXPECT_CALL(
mocks.network_link_rtcp_observer,
OnCongestionControlFeedback(
mocks.clock.CurrentTime(),
Property(&rtcp::CongestionControlFeedback::packets, SizeIs(1))));
receiver.IncomingPacket(packet.Build());
}
TEST(RtcpReceiverTest, HandlesInvalidCongestionControlFeedback) {
ScopedKeyValueConfig trials(
"WebRTC-RFC8888CongestionControlFeedback/Enabled/");
ReceiverMocks mocks;
RtpRtcpInterface::Configuration config = DefaultConfiguration(&mocks);
RTCPReceiver receiver(config, &mocks.rtp_rtcp_impl);
receiver.SetRemoteSSRC(kSenderSsrc);
rtcp::CongestionControlFeedback packet({{
.ssrc = 123,
.sequence_number = 1,
}},
/*report_timestamp_compact_ntp=*/324);
packet.SetSenderSsrc(kSenderSsrc);
rtc::Buffer built_packet = packet.Build();
// Modify the CongestionControlFeedback packet so that it is invalid.
const size_t kNumReportsOffset = 14;
ByteWriter<uint16_t>::WriteBigEndian(&built_packet.data()[kNumReportsOffset],
42);
EXPECT_CALL(mocks.network_link_rtcp_observer, OnCongestionControlFeedback)
.Times(0);
receiver.IncomingPacket(built_packet);
}
TEST(RtcpReceiverTest, TEST(RtcpReceiverTest,
NotifiesNetworkLinkObserverOnTransportFeedbackOnRtxSsrc) { NotifiesNetworkLinkObserverOnTransportFeedbackOnRtxSsrc) {
ReceiverMocks mocks; ReceiverMocks mocks;

View File

@ -222,6 +222,7 @@ webrtc_fuzzer_test("rtcp_receiver_fuzzer") {
"../../modules/rtp_rtcp:rtp_rtcp_format", "../../modules/rtp_rtcp:rtp_rtcp_format",
"../../rtc_base:checks", "../../rtc_base:checks",
"../../system_wrappers", "../../system_wrappers",
"../../system_wrappers:field_trial",
] ]
seed_corpus = "corpora/rtcp-corpus" seed_corpus = "corpora/rtcp-corpus"
} }

View File

@ -10,8 +10,8 @@
#include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h" #include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
#include "modules/rtp_rtcp/source/rtcp_receiver.h" #include "modules/rtp_rtcp/source/rtcp_receiver.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_interface.h" #include "modules/rtp_rtcp/source/rtp_rtcp_interface.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/clock.h" #include "system_wrappers/include/clock.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc { namespace webrtc {
namespace { namespace {
@ -37,7 +37,8 @@ void FuzzOneInput(const uint8_t* data, size_t size) {
if (size > kMaxInputLenBytes) { if (size > kMaxInputLenBytes) {
return; return;
} }
field_trial::InitFieldTrialsFromString(
"WebRTC-RFC8888CongestionControlFeedback/Enabled/");
NullModuleRtpRtcp rtp_rtcp_module; NullModuleRtpRtcp rtp_rtcp_module;
SimulatedClock clock(1234); SimulatedClock clock(1234);