commit c7e5b8a6409ede1ce621710de2ec1af41de2fe76
parent e4acecf36c2155faf50a6cafaa09d05e66c91765
Author: Dan Baker <dbaker@mozilla.com>
Date: Mon, 1 Dec 2025 21:34:23 -0700
Bug 2000941 - Vendor libwebrtc from c12a00ea3b
Upstream commit: https://webrtc.googlesource.com/src/+/c12a00ea3ba2caa62dc0aa40c79ba93e50a700b0
Require field trial parameter offer:true to create offer with RFC8888
To both offer and answer with RFC 8888 support, use field trial string "WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/"
The purpose is to simplify rollout.
ie. first, an experiment with answering an offer with RFC 8888 can be rolled out. This should be a
noop. Later enabling sending an offer should enable using RFC8888.
Bug: webrtc:42225697
Change-Id: I2b4e52a9335303f2ef6a744027d83eb7f18e1edf
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/404041
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#45671}
Diffstat:
8 files changed, 94 insertions(+), 29 deletions(-)
diff --git a/third_party/libwebrtc/README.mozilla.last-vendor b/third_party/libwebrtc/README.mozilla.last-vendor
@@ -1,4 +1,4 @@
# ./mach python dom/media/webrtc/third_party_build/vendor-libwebrtc.py --from-local /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc --commit mozpatches libwebrtc
-libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2025-12-02T04:30:56.067111+00:00.
+libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2025-12-02T04:34:09.212126+00:00.
# base of lastest vendoring
-b83fd4628c
+c12a00ea3b
diff --git a/third_party/libwebrtc/moz-patch-stack/s0102.patch b/third_party/libwebrtc/moz-patch-stack/s0102.patch
@@ -601,7 +601,7 @@ index b7561e53b6..fe7eb57423 100644
import("../../webrtc.gni")
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
-index deb0435c15..44d226504f 100644
+index 23d10bbd83..0c5ec81d48 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -30,8 +30,8 @@
diff --git a/third_party/libwebrtc/pc/BUILD.gn b/third_party/libwebrtc/pc/BUILD.gn
@@ -377,6 +377,7 @@ rtc_library("media_session") {
"../rtc_base:checks",
"../rtc_base:logging",
"../rtc_base:unique_id_generator",
+ "../rtc_base/experiments:field_trial_parser",
"../rtc_base/memory:always_valid_pointer",
"//third_party/abseil-cpp/absl/algorithm:container",
"//third_party/abseil-cpp/absl/strings",
diff --git a/third_party/libwebrtc/pc/congestion_control_integrationtest.cc b/third_party/libwebrtc/pc/congestion_control_integrationtest.cc
@@ -44,18 +44,32 @@ class PeerConnectionCongestionControlTest
: PeerConnectionIntegrationBaseTest(SdpSemantics::kUnifiedPlan) {}
};
-TEST_F(PeerConnectionCongestionControlTest, OfferContainsCcfbIfEnabled) {
+TEST_F(PeerConnectionCongestionControlTest,
+ OfferDoesNotContainCcfbEvenIfEnabled) {
SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled/");
ASSERT_TRUE(CreatePeerConnectionWrappers());
caller()->AddAudioVideoTracks();
std::unique_ptr<SessionDescriptionInterface> offer =
caller()->CreateOfferAndWait();
std::string offer_str = absl::StrCat(*offer);
+ EXPECT_THAT(offer_str, Not(HasSubstr("a=rtcp-fb:* ack ccfb\r\n")));
+}
+
+TEST_F(PeerConnectionCongestionControlTest, OfferContainsCcfbIfFieldTrial) {
+ SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ caller()->AddAudioVideoTracks();
+ std::unique_ptr<SessionDescriptionInterface> offer =
+ caller()->CreateOfferAndWait();
+ std::string offer_str = absl::StrCat(*offer);
EXPECT_THAT(offer_str, HasSubstr("a=rtcp-fb:* ack ccfb\r\n"));
}
TEST_F(PeerConnectionCongestionControlTest, ReceiveOfferSetsCcfbFlag) {
- SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled/");
+ SetFieldTrials(kCallerName,
+ "WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
+ SetFieldTrials(kCalleeName,
+ "WebRTC-RFC8888CongestionControlFeedback/Enabled/");
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignalingForSdpOnly();
caller()->AddAudioVideoTracks();
@@ -89,7 +103,7 @@ TEST_F(PeerConnectionCongestionControlTest, ReceiveOfferSetsCcfbFlag) {
TEST_F(PeerConnectionCongestionControlTest, SendOnlySupportDoesNotEnableCcFb) {
// Enable CCFB for sender, do not enable it for receiver
SetFieldTrials(kCallerName,
- "WebRTC-RFC8888CongestionControlFeedback/Enabled/");
+ "WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
SetFieldTrials(kCalleeName,
"WebRTC-RFC8888CongestionControlFeedback/Disabled/");
ASSERT_TRUE(CreatePeerConnectionWrappers());
@@ -126,7 +140,7 @@ TEST_F(PeerConnectionCongestionControlTest,
ReNegotiationCalleeDoesNotSupportCcfb) {
// Enable CCFB for sender, do not enable it for receiver
SetFieldTrials(kCallerName,
- "WebRTC-RFC8888CongestionControlFeedback/Enabled/");
+ "WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
SetFieldTrials(kCalleeName,
"WebRTC-RFC8888CongestionControlFeedback/Disabled/");
ASSERT_TRUE(CreatePeerConnectionWrappers());
@@ -152,10 +166,10 @@ TEST_F(PeerConnectionCongestionControlTest,
TEST_F(PeerConnectionCongestionControlTest, ReNegotiationBothSupportCcfb) {
SetFieldTrials(kCallerName,
- "WebRTC-RFC8888CongestionControlFeedback/Enabled/"
+ "WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/"
"WebRTC-HeaderExtensionNegotiateMemory/Enabled/");
SetFieldTrials(kCalleeName,
- "WebRTC-RFC8888CongestionControlFeedback/Enabled/"
+ "WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/"
"WebRTC-HeaderExtensionNegotiateMemory/Enabled/");
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignalingForSdpOnly();
@@ -191,7 +205,7 @@ TEST_F(PeerConnectionCongestionControlTest, ReNegotiationBothSupportCcfb) {
#ifdef WEBRTC_HAVE_SCTP
TEST_F(PeerConnectionCongestionControlTest,
ReceiveOfferWithDataChannelsSetsCcfbFlag) {
- SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled/");
+ SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignalingForSdpOnly();
caller()->AddAudioVideoTracks();
@@ -240,7 +254,7 @@ TEST_F(PeerConnectionCongestionControlTest,
#endif
TEST_F(PeerConnectionCongestionControlTest, NegotiatingCcfbRemovesTsn) {
- SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled/");
+ SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignalingForSdpOnly();
callee()->AddVideoTrack();
@@ -320,7 +334,7 @@ TEST_F(PeerConnectionCongestionControlTest, NegotiatingCcfbRemovesTsn) {
}
TEST_F(PeerConnectionCongestionControlTest, CcfbGetsUsed) {
- SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled/");
+ SetFieldTrials("WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignaling();
caller()->AddAudioVideoTracks();
@@ -368,4 +382,32 @@ TEST_F(PeerConnectionCongestionControlTest, TransportCcGetsUsed) {
EXPECT_THAT(pc_internal->FeedbackAccordingToRfc8888CountForTesting(), Eq(0));
}
+TEST_F(PeerConnectionCongestionControlTest,
+ TransportCcGetsUsedIfCalleeNotEnabledRfc8888) {
+ SetFieldTrials(kCallerName,
+ "WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
+ SetFieldTrials(kCalleeName,
+ "WebRTC-RFC8888CongestionControlFeedback/Disabled/");
+ ASSERT_TRUE(CreatePeerConnectionWrappers());
+ ConnectFakeSignaling();
+ caller()->AddAudioVideoTracks();
+ caller()->CreateAndSetAndSignalOffer();
+ ASSERT_THAT(WaitUntil([&] { return SignalingStateStable(); }, IsTrue()),
+ IsRtcOk());
+ MediaExpectations media_expectations;
+ media_expectations.CalleeExpectsSomeAudio();
+ media_expectations.CalleeExpectsSomeVideo();
+ ASSERT_TRUE(ExpectNewFrames(media_expectations));
+ auto pc_internal = caller()->pc_internal();
+ EXPECT_THAT(
+ WaitUntil(
+ [&] {
+ return pc_internal->FeedbackAccordingToTransportCcCountForTesting();
+ },
+ Gt(0)),
+ IsRtcOk());
+ // Test that RFC 8888 feedback is NOT generated when field trial disabled.
+ EXPECT_THAT(pc_internal->FeedbackAccordingToRfc8888CountForTesting(), Eq(0));
+}
+
} // namespace webrtc
diff --git a/third_party/libwebrtc/pc/media_session.cc b/third_party/libwebrtc/pc/media_session.cc
@@ -662,6 +662,21 @@ const TransportDescription* GetTransportDescription(
return desc;
}
+bool OfferRfc8888(const FieldTrialsView& field_trials) {
+ if (field_trials.IsEnabled("WebRTC-RFC8888CongestionControlFeedback")) {
+ FieldTrialParameter<bool> offer_rfc_8888("offer", false);
+ ParseFieldTrial(
+ {&offer_rfc_8888},
+ field_trials.Lookup("WebRTC-RFC8888CongestionControlFeedback"));
+ return offer_rfc_8888;
+ }
+ return false;
+}
+
+bool AcceptOfferWithRfc8888(const FieldTrialsView& field_trials) {
+ return field_trials.IsEnabled("WebRTC-RFC8888CongestionControlFeedback");
+}
+
} // namespace
MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
@@ -670,7 +685,10 @@ MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
UniqueRandomIdGenerator* ssrc_generator,
const TransportDescriptionFactory* transport_desc_factory,
CodecLookupHelper* codec_lookup_helper)
- : ssrc_generator_(ssrc_generator),
+ : offer_rfc_8888_(OfferRfc8888(transport_desc_factory->trials())),
+ accept_offer_with_rfc_8888_(
+ AcceptOfferWithRfc8888(transport_desc_factory->trials())),
+ ssrc_generator_(ssrc_generator),
transport_desc_factory_(transport_desc_factory),
codec_lookup_helper_(codec_lookup_helper),
payload_types_in_transport_trial_enabled_(
@@ -838,8 +856,7 @@ MediaSessionDescriptionFactory::CreateAnswerOrError(
// Decide what congestion control feedback format we're using.
bool has_ack_ccfb = false;
- if (transport_desc_factory_->trials().IsEnabled(
- "WebRTC-RFC8888CongestionControlFeedback")) {
+ if (accept_offer_with_rfc_8888_) {
for (const auto& content : offer->contents()) {
if (content.type != MediaProtocolType::kRtp) {
continue;
@@ -1169,9 +1186,7 @@ RTCError MediaSessionDescriptionFactory::AddRtpContentForOffer(
content_description = std::make_unique<VideoContentDescription>();
}
// RFC 8888 support.
- content_description->set_rtcp_fb_ack_ccfb(
- transport_desc_factory_->trials().IsEnabled(
- "WebRTC-RFC8888CongestionControlFeedback"));
+ content_description->set_rtcp_fb_ack_ccfb(offer_rfc_8888_);
auto error = CreateMediaContentOffer(
media_description_options, session_options, codecs_to_include,
header_extensions, ssrc_generator(), current_streams,
@@ -1338,10 +1353,8 @@ RTCError MediaSessionDescriptionFactory::AddRtpContentForAnswer(
// RFC 8888 support. Only answer with "ack ccfb" if offer has it and
// experiment is enabled.
if (offer_content_description->rtcp_fb_ack_ccfb()) {
- bool use_ccfb = transport_desc_factory_->trials().IsEnabled(
- "WebRTC-RFC8888CongestionControlFeedback");
- if (use_ccfb) {
- answer_content->set_rtcp_fb_ack_ccfb(use_ccfb);
+ if (accept_offer_with_rfc_8888_) {
+ answer_content->set_rtcp_fb_ack_ccfb(true);
for (auto& codec : codecs_to_include) {
codec.feedback_params.Remove(FeedbackParam(kRtcpFbParamTransportCc));
}
diff --git a/third_party/libwebrtc/pc/media_session.h b/third_party/libwebrtc/pc/media_session.h
@@ -28,6 +28,7 @@
#include "pc/codec_vendor.h"
#include "pc/media_options.h"
#include "pc/session_description.h"
+#include "rtc_base/experiments/field_trial_parser.h"
#include "rtc_base/memory/always_valid_pointer.h"
#include "rtc_base/unique_id_generator.h"
@@ -173,6 +174,10 @@ class MediaSessionDescriptionFactory {
return ssrc_generator_.get();
}
+ // Feedback format according to RFC-8888 will be offered if true.
+ const bool offer_rfc_8888_;
+ // Feedback format according to RFC-8888 will be accepted if offered.
+ const bool accept_offer_with_rfc_8888_;
bool is_unified_plan_ = false;
// This object may or may not be owned by this class.
AlwaysValidPointer<UniqueRandomIdGenerator> const ssrc_generator_;
diff --git a/third_party/libwebrtc/pc/rtc_stats_integrationtest.cc b/third_party/libwebrtc/pc/rtc_stats_integrationtest.cc
@@ -1245,7 +1245,7 @@ TEST_F(RTCStatsIntegrationTest, ExperimentalPsnrStats) {
}
TEST_F(RTCStatsIntegrationTest, ExperimentalTransportCcfbStats) {
- StartCall("WebRTC-RFC8888CongestionControlFeedback/Enabled/");
+ StartCall("WebRTC-RFC8888CongestionControlFeedback/Enabled,offer:true/");
// This assumes all other stats are ok and tests the stats which should be
// different under the field trial.
diff --git a/third_party/libwebrtc/test/peer_scenario/tests/l4s_test.cc b/third_party/libwebrtc/test/peer_scenario/tests/l4s_test.cc
@@ -168,7 +168,8 @@ TEST(L4STest, NegotiateAndUseCcfbIfEnabled) {
PeerScenario s(*test_info_);
PeerScenarioClient::Config config;
- config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback", "Enabled");
+ config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback",
+ "Enabled,offer:true");
config.disable_encryption = true;
PeerScenarioClient* caller = s.CreateClient(config);
PeerScenarioClient* callee = s.CreateClient(config);
@@ -253,7 +254,7 @@ TEST_P(FeedbackFormatTest, AdaptToLinkCapacityWithoutEcn) {
caller_config.disable_encryption = true;
caller_config.field_trials.Set(
"WebRTC-RFC8888CongestionControlFeedback",
- params.caller_supports_rfc8888 ? "Enabled" : "Disabled");
+ params.caller_supports_rfc8888 ? "Enabled,offer:true" : "Disabled");
PeerScenarioClient* caller = s.CreateClient(caller_config);
PeerScenarioClient::Config callee_config;
@@ -356,7 +357,7 @@ TEST(L4STest, NoCcfbSentAfterRenegotiationAndCallerCachLocalDescription) {
PeerScenarioClient::Config caller_config;
caller_config.disable_encryption = true;
caller_config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback",
- "Enabled");
+ "Enabled,offer:true");
PeerScenarioClient* caller = s.CreateClient(caller_config);
PeerScenarioClient::Config callee_config;
@@ -463,7 +464,8 @@ TEST(L4STest, NoCcfbSentAfterRenegotiationAndCallerCachLocalDescription) {
TEST(L4STest, CallerAdaptToLinkCapacityOnNetworkWithEcn) {
PeerScenario s(*test_info_);
PeerScenarioClient::Config config;
- config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback", "Enabled");
+ config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback",
+ "Enabled,offer:true");
PeerScenarioClient* caller = s.CreateClient(config);
PeerScenarioClient* callee = s.CreateClient(config);
@@ -506,7 +508,8 @@ TEST(L4STest, SendsEct1UntilFirstFeedback) {
PeerScenario s(*test_info_);
PeerScenarioClient::Config config;
- config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback", "Enabled");
+ config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback",
+ "Enabled,offer:true");
config.disable_encryption = true;
PeerScenarioClient* caller = s.CreateClient(config);
PeerScenarioClient* callee = s.CreateClient(config);
@@ -563,7 +566,8 @@ TEST(L4STest, SendsEct1AfterRouteChange) {
PeerScenario s(*test_info_);
PeerScenarioClient::Config config;
- config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback", "Enabled");
+ config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback",
+ "Enabled,offer:true");
config.disable_encryption = true;
config.endpoints = {{0, {.type = AdapterType::ADAPTER_TYPE_WIFI}}};
PeerScenarioClient* caller = s.CreateClient(config);