tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit a6f9a7b5fa184566d0d143bfdd2fa3902e960d71
parent 8b0d58626af667585a13eae56e98206c642ac321
Author: Dan Baker <dbaker@mozilla.com>
Date:   Thu, 23 Oct 2025 15:36:18 -0600

Bug 1995393 - Vendor libwebrtc from fd3849b8af

Upstream commit: https://webrtc.googlesource.com/src/+/fd3849b8afd181aa6302c83ec43f90ce89fb1f8d
    Refine RFC8888 CCFB enablement logic and add test.

    The `SdpOfferAnswerHandler::PushdownMediaDescription` now checks if the remote description supports RFC8888 Congestion Control Feedback when processing an answer. This ensures that RFC8888 feedback is only enabled if both sides signal support.

    Bug: webrtc:438613826
    Change-Id: Iecf2050cb5f2110e010ce056af6b58077a60891e
    Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/404482
    Commit-Queue: Harald Alvestrand <hta@webrtc.org>
    Reviewed-by: Harald Alvestrand <hta@webrtc.org>
    Auto-Submit: Per Kjellander <perkj@webrtc.org>
    Cr-Commit-Position: refs/heads/main@{#45346}

Diffstat:
Mthird_party/libwebrtc/README.mozilla.last-vendor | 4++--
Mthird_party/libwebrtc/pc/sdp_offer_answer.cc | 30++++++++++++++++++++++++------
Mthird_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc | 22++++++++++++++++++++++
Mthird_party/libwebrtc/test/peer_scenario/peer_scenario_client.h | 8++++++++
Mthird_party/libwebrtc/test/peer_scenario/tests/BUILD.gn | 1+
Mthird_party/libwebrtc/test/peer_scenario/tests/l4s_test.cc | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 166 insertions(+), 8 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-10-23T21:34:04.946928+00:00. +libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2025-10-23T21:36:06.675378+00:00. # base of lastest vendoring -dead53b925 +fd3849b8af diff --git a/third_party/libwebrtc/pc/sdp_offer_answer.cc b/third_party/libwebrtc/pc/sdp_offer_answer.cc @@ -5040,9 +5040,9 @@ RTCError SdpOfferAnswerHandler::PushdownMediaDescription( ContentSource source, const std::map<std::string, const ContentGroup*>& bundle_groups_by_mid) { TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::PushdownMediaDescription"); + RTC_DCHECK_RUN_ON(signaling_thread()); const SessionDescriptionInterface* sdesc = (source == CS_LOCAL ? local_description() : remote_description()); - RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK(sdesc); if (ConfiguredForMedia()) { @@ -5114,11 +5114,29 @@ RTCError SdpOfferAnswerHandler::PushdownMediaDescription( // If local and remote are both set, we assume that it's safe to trigger // CCFB. if (pc_->trials().IsEnabled("WebRTC-RFC8888CongestionControlFeedback")) { - if (use_ccfb && local_description() && remote_description()) { - // The call and the congestion controller live on the worker thread. - context_->worker_thread()->PostTask([call = pc_->call_ptr()] { - call->EnableSendCongestionControlFeedbackAccordingToRfc8888(); - }); + if (type == SdpType::kAnswer && use_ccfb && local_description() && + remote_description()) { + bool remote_supports_ccfb = true; + // Verify that the remote supports CCFB before enabling. + for (const auto& content : + remote_description()->description()->contents()) { + if (content.type != MediaProtocolType::kRtp || content.rejected || + content.media_description() == nullptr) { + continue; + } + if (!content.media_description()->rtcp_fb_ack_ccfb()) { + remote_supports_ccfb = false; + break; + } + } + if (remote_supports_ccfb) { + // The call and the congestion controller live on the worker thread. + context_->worker_thread()->PostTask([call = pc_->call_ptr()] { + call->EnableSendCongestionControlFeedbackAccordingToRfc8888(); + }); + } else { + RTC_LOG(LS_WARNING) << "Local but not Remote supports CCFB."; + } } } } diff --git a/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc b/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.cc @@ -465,6 +465,28 @@ void PeerScenarioClient::SetSdpAnswer( })); } +void PeerScenarioClient::SetLocalDescription( + std::string sdp, + SdpType type, + std::function<void(RTCError)> on_complete) { + RTC_DCHECK_RUN_ON(signaling_thread_); + peer_connection_->SetLocalDescription( + CreateSessionDescription(type, sdp), + make_ref_counted<LambdaSetLocalDescriptionObserver>( + std::move(on_complete))); +} + +void PeerScenarioClient::SetRemoteDescription( + std::string sdp, + SdpType type, + std::function<void(RTCError)> on_complete) { + RTC_DCHECK_RUN_ON(signaling_thread_); + peer_connection_->SetRemoteDescription( + CreateSessionDescription(type, sdp), + make_ref_counted<LambdaSetRemoteDescriptionObserver>( + std::move(on_complete))); +} + void PeerScenarioClient::AddIceCandidate( std::unique_ptr<IceCandidate> candidate) { RTC_DCHECK_RUN_ON(signaling_thread_); diff --git a/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.h b/third_party/libwebrtc/test/peer_scenario/peer_scenario_client.h @@ -26,6 +26,7 @@ #include "api/jsep.h" #include "api/media_stream_interface.h" #include "api/peer_connection_interface.h" +#include "api/rtc_error.h" #include "api/rtp_receiver_interface.h" #include "api/rtp_sender_interface.h" #include "api/rtp_transceiver_interface.h" @@ -174,6 +175,13 @@ class PeerScenarioClient { std::function<void(const SessionDescriptionInterface& answer)> done_handler); + void SetLocalDescription(std::string sdp, + SdpType type, + std::function<void(RTCError)> on_complete); + void SetRemoteDescription(std::string sdp, + SdpType type, + std::function<void(RTCError)> on_complete); + // Adds the given ice candidate when the peer connection is ready. void AddIceCandidate(std::unique_ptr<IceCandidate> candidate); diff --git a/third_party/libwebrtc/test/peer_scenario/tests/BUILD.gn b/third_party/libwebrtc/test/peer_scenario/tests/BUILD.gn @@ -25,6 +25,7 @@ if (rtc_include_tests) { "../../../api:audio_options_api", "../../../api:libjingle_peerconnection_api", "../../../api:make_ref_counted", + "../../../api:rtc_error", "../../../api:rtc_stats_api", "../../../api:rtp_parameters", "../../../api:rtp_transceiver_direction", diff --git a/third_party/libwebrtc/test/peer_scenario/tests/l4s_test.cc b/third_party/libwebrtc/test/peer_scenario/tests/l4s_test.cc @@ -16,6 +16,7 @@ #include "absl/strings/str_cat.h" #include "api/jsep.h" #include "api/make_ref_counted.h" +#include "api/rtc_error.h" #include "api/scoped_refptr.h" #include "api/stats/rtc_stats_report.h" #include "api/stats/rtcstats_objects.h" @@ -327,6 +328,114 @@ INSTANTIATE_TEST_SUITE_P( return info.param.test_suffix; }); +TEST(L4STest, NoCcfbSentAfterRenegotiationAndCallerCachLocalDescription) { + // The caller supports CCFB, but the callee does not. + // This test that the caller does not start sending CCFB after renegotiation + // even if the local description is cached. The callers local description + // will contain CCFB since it was used in the initial offer. + PeerScenario s(*test_info_); + PeerScenarioClient::Config caller_config; + caller_config.disable_encryption = true; + caller_config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback", + "Enabled"); + PeerScenarioClient* caller = s.CreateClient(caller_config); + + PeerScenarioClient::Config callee_config; + callee_config.disable_encryption = true; + callee_config.field_trials.Set("WebRTC-RFC8888CongestionControlFeedback", + "Disabled"); + PeerScenarioClient* callee = s.CreateClient(callee_config); + + auto caller_to_callee = s.net() + ->NodeBuilder() + .capacity(DataRate::KilobitsPerSec(600)) + .Build() + .node; + auto callee_to_caller = s.net() + ->NodeBuilder() + .capacity(DataRate::KilobitsPerSec(600)) + .Build() + .node; + RtcpFeedbackCounter callee_feedback_counter; + caller_to_callee->router()->SetWatcher([&](const EmulatedIpPacket& packet) { + callee_feedback_counter.Count(packet); + }); + RtcpFeedbackCounter caller_feedback_counter; + callee_to_caller->router()->SetWatcher([&](const EmulatedIpPacket& packet) { + caller_feedback_counter.Count(packet); + }); + + s.net()->CreateRoute(caller->endpoint(), {caller_to_callee}, + callee->endpoint()); + s.net()->CreateRoute(callee->endpoint(), {callee_to_caller}, + caller->endpoint()); + + auto signaling = s.ConnectSignaling(caller, callee, {caller_to_callee}, + {callee_to_caller}); + PeerScenarioClient::VideoSendTrackConfig video_conf; + video_conf.generator.squares_video->framerate = 30; + video_conf.generator.squares_video->width = 640; + video_conf.generator.squares_video->height = 360; + caller->CreateVideo("FROM_CALLER", video_conf); + callee->CreateVideo("FROM_CALLEE", video_conf); + + signaling.StartIceSignaling(); + std::atomic<bool> offer_exchange_done(false); + signaling.NegotiateSdp([&](const SessionDescriptionInterface& answer) { + offer_exchange_done = true; + }); + ASSERT_TRUE(s.WaitAndProcess(&offer_exchange_done)); + s.ProcessMessages(TimeDelta::Seconds(2)); + + EXPECT_EQ(caller_feedback_counter.FeedbackAccordingToRfc8888(), 0); + EXPECT_EQ(callee_feedback_counter.FeedbackAccordingToRfc8888(), 0); + int transport_cc_caller = + caller_feedback_counter.FeedbackAccordingToTransportCc(); + int transport_cc_callee = + callee_feedback_counter.FeedbackAccordingToTransportCc(); + EXPECT_GT(transport_cc_caller, 0); + EXPECT_GT(transport_cc_callee, 0); + + offer_exchange_done = false; + // Save the caller's local description and use it as answer to the next offer + // from callee. + std::string answer_str; + caller->pc()->local_description()->ToString(&answer_str); + ASSERT_FALSE(answer_str.empty()); + ASSERT_THAT(answer_str, HasSubstr("a=rtcp-fb:* ack ccfb\r\n")); + + callee->CreateAndSetSdp( + [&](SessionDescriptionInterface* /*munge_offer*/) { + // Do not munge the offer. + }, + [&](std::string offer) { + // Callee does not support ccfb and does not have it in the offer. + ASSERT_THAT(offer, Not(HasSubstr("a=rtcp-fb:* ack ccfb\r\n"))); + caller->SetRemoteDescription( + offer, SdpType::kOffer, [&](RTCError error) { + ASSERT_TRUE(error.ok()); + caller->SetLocalDescription( + answer_str, SdpType::kAnswer, [&](RTCError error) { + ASSERT_TRUE(error.ok()); + callee->SetRemoteDescription(answer_str, SdpType::kAnswer, + [&](RTCError error) { + ASSERT_TRUE(error.ok()); + offer_exchange_done = true; + }); + }); + }); + }); + ASSERT_TRUE(s.WaitAndProcess(&offer_exchange_done)); + s.ProcessMessages(TimeDelta::Seconds(4)); + + EXPECT_EQ(caller_feedback_counter.FeedbackAccordingToRfc8888(), 0); + EXPECT_EQ(callee_feedback_counter.FeedbackAccordingToRfc8888(), 0); + EXPECT_GT(caller_feedback_counter.FeedbackAccordingToTransportCc(), + transport_cc_caller); + EXPECT_GT(callee_feedback_counter.FeedbackAccordingToTransportCc(), + transport_cc_callee); +} + // Note - this test only test that the // caller adapt to the link capacity. It does not test that the caller uses ECN // to adapt even though the network can mark packets with CE.