commit 142a49eca33a5b2a77315e4ed65b428ed204b416
parent 4e54bfb07729ccb6a65cd72a3e0e99b6e7f67cd3
Author: Dan Baker <dbaker@mozilla.com>
Date: Mon, 1 Dec 2025 20:58:48 -0700
Bug 2000941 - Vendor libwebrtc from 85c183fd32
Upstream commit: https://webrtc.googlesource.com/src/+/85c183fd32c2a2372322c57eae31601949847ffd
Move some of JsepSessionDescription impl to SessionDescriptionInternal
This change begins transforming `SessionDescriptionInterface` from a
pure interface into a class with a concrete base implementation. This
is the first step toward making the class thread-aware.
A new `SessionDescriptionInternal` class is introduced to house the
common data members (SDP type, session ID, version, and the internal
`description_` pointer). `SessionDescriptionInterface` is updated to
inherit from this new base. To start with, all members in this class
are const, initialized at construction time.
Consequently:
- Pure virtual getters in `SessionDescriptionInterface` (like
`GetType`, `session_id`, etc.) are now implemented in the header by
forwarding to the `SessionDescriptionInternal` base.
- `JsepSessionDescription` is simplified, removing its duplicate data
members and relying on the inherited implementation.
- A `SequenceChecker` is added to the internal base to begin
enforcing thread constraints. For now, checks are not enforced
but a method is added that allows for resetting the thread checker.
This method will be needed in corner cases, mostly internally at api/
ownership transition points.
Bug: webrtc:442220720
Change-Id: Ibe65d9045313723913f306c4ebc97500e516a1c7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/409380
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#45658}
Diffstat:
10 files changed, 145 insertions(+), 60 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-02T03:55:23.939638+00:00.
+libwebrtc updated from /Users/danielbaker/elm/.moz-fast-forward/moz-libwebrtc commit mozpatches on 2025-12-02T03:58:33.271617+00:00.
# base of lastest vendoring
-9c45144f9b
+85c183fd32
diff --git a/third_party/libwebrtc/api/BUILD.gn b/third_party/libwebrtc/api/BUILD.gn
@@ -402,6 +402,7 @@ if (!build_with_mozilla) {
"../rtc_base:ssl",
"../rtc_base:ssl_adapter",
"../rtc_base:stringutils",
+ "../rtc_base/system:no_unique_address",
"adaptation:resource_adaptation_api",
"audio:audio_device",
"audio:audio_frame_processor",
@@ -1424,6 +1425,7 @@ if (rtc_include_tests) {
deps = [
":candidate",
":libjingle_peerconnection_api",
+ "../pc:session_description",
"../test:test_support",
"//third_party/abseil-cpp/absl/strings:string_view",
]
diff --git a/third_party/libwebrtc/api/DEPS b/third_party/libwebrtc/api/DEPS
@@ -106,6 +106,7 @@ specific_include_rules = {
"jsep\.h": [
"+absl/strings/has_absl_stringify.h",
"+absl/strings/str_format.h",
+ "+rtc_base/system/no_unique_address.h",
],
"local_network_access_permission\.h": [
diff --git a/third_party/libwebrtc/api/jsep.h b/third_party/libwebrtc/api/jsep.h
@@ -34,6 +34,8 @@
#include "api/candidate.h"
#include "api/ref_count.h"
#include "api/rtc_error.h"
+#include "api/sequence_checker.h"
+#include "rtc_base/system/no_unique_address.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
@@ -206,13 +208,67 @@ void AbslStringify(Sink& sink, SdpType sdp_type) {
RTC_EXPORT std::optional<SdpType> SdpTypeFromString(
const std::string& type_str);
+// TODO: bugs.webrtc.org/442220720 - This class is temporarily here while
+// SessionDescriptionInterface transforms from a pure interface into a simple
+// non-virtual class. The purpose of `SessionDescriptionInternal` is to provide
+// protected methods to classes currently inheriting from
+// SessionDescriptionInterface, the basic implementation that satisified the
+// interface. Once the migration of the implementation is complete, the
+// SessionDescriptionInterface class can be made non-virtual, final and
+// SessionDescriptionInternal can effectively be renamed to
+// SessionDescriptionInterface. The reason for all of this is that access to and
+// modification of the internal state needs to be made thread aware so that
+// concurrent operations aren't executed on different threads or that the
+// state can be declared const when no known modifications are pending.
+class SessionDescriptionInternal {
+ public:
+ explicit SessionDescriptionInternal(
+ SdpType type,
+ absl_nullable std::unique_ptr<SessionDescription> description,
+ absl::string_view id,
+ absl::string_view version);
+
+ ~SessionDescriptionInternal();
+
+ // Resets the internal sequence_checker_ to not be attached to a particular
+ // thread. Used when transfering object ownership between threads. Must be
+ // called by the thread that currently owns the object before transferring the
+ // ownership.
+ void RelinquishThreadOwnership();
+
+ protected:
+ // Only meant for the SessionDescriptionInterface implementation.
+ SdpType sdp_type() const { return sdp_type_; }
+ absl::string_view id() const { return id_; }
+ absl::string_view version() const { return version_; }
+ const SessionDescription* description() const { return description_.get(); }
+ SessionDescription* description() { return description_.get(); }
+ size_t mediasection_count() const;
+
+ protected:
+ // This method is necessarily `protected`, and not private, while
+ // the SessionDescriptionInterface implementation is being consolidated
+ // into a single class.
+ SequenceChecker& sequence_checker() { return sequence_checker_; }
+
+ private:
+ RTC_NO_UNIQUE_ADDRESS SequenceChecker sequence_checker_{
+ SequenceChecker::kDetached};
+
+ const SdpType sdp_type_;
+ const std::string id_;
+ const std::string version_;
+ absl_nullable const std::unique_ptr<SessionDescription> description_;
+};
+
// Class representation of an SDP session description.
//
// An instance of this interface is supposed to be owned by one class at a time
// and is therefore not expected to be thread safe.
//
// An instance can be created by CreateSessionDescription.
-class RTC_EXPORT SessionDescriptionInterface {
+class RTC_EXPORT SessionDescriptionInterface
+ : public SessionDescriptionInternal {
public:
// String representations of the supported SDP types.
static const char kOffer[];
@@ -227,21 +283,24 @@ class RTC_EXPORT SessionDescriptionInterface {
virtual std::unique_ptr<SessionDescriptionInterface> Clone() const = 0;
// Only for use internally.
- virtual SessionDescription* description() = 0;
- virtual const SessionDescription* description() const = 0;
+ virtual SessionDescription* description() {
+ return SessionDescriptionInternal::description();
+ }
+ virtual const SessionDescription* description() const {
+ return SessionDescriptionInternal::description();
+ }
// Get the session id and session version, which are defined based on
// RFC 4566 for the SDP o= line.
- virtual std::string session_id() const = 0;
- virtual std::string session_version() const = 0;
+ virtual std::string session_id() const { return std::string(id()); }
+ virtual std::string session_version() const { return std::string(version()); }
// Returns the type of this session description as an SdpType. Descriptions of
// the various types are found in the SdpType documentation.
- virtual SdpType GetType() const = 0;
+ virtual SdpType GetType() const { return sdp_type(); }
- // kOffer/kPrAnswer/kAnswer
// TODO(steveanton): Remove this in favor of `GetType` that returns SdpType.
- virtual std::string type() const = 0;
+ virtual std::string type() const { return SdpTypeToString(sdp_type()); }
// Adds the specified candidate to the description.
//
@@ -261,7 +320,9 @@ class RTC_EXPORT SessionDescriptionInterface {
virtual bool RemoveCandidate(const IceCandidate* candidate) = 0;
// Returns the number of m= sections in the session description.
- virtual size_t number_of_mediasections() const = 0;
+ virtual size_t number_of_mediasections() const {
+ return mediasection_count();
+ }
// Returns a collection of all candidates that belong to a certain m=
// section.
@@ -283,6 +344,13 @@ class RTC_EXPORT SessionDescriptionInterface {
}
sink.Append("--- END SDP ---\n");
}
+
+ protected:
+ explicit SessionDescriptionInterface(
+ SdpType type,
+ std::unique_ptr<SessionDescription> description,
+ absl::string_view id,
+ absl::string_view version);
};
// Creates a SessionDescriptionInterface based on the SDP string and the type.
diff --git a/third_party/libwebrtc/api/jsep_session_description.h b/third_party/libwebrtc/api/jsep_session_description.h
@@ -47,27 +47,13 @@ class JsepSessionDescription final : public SessionDescriptionInterface {
JsepSessionDescription& operator=(const JsepSessionDescription&) = delete;
std::unique_ptr<SessionDescriptionInterface> Clone() const override;
-
- SessionDescription* description() override { return description_.get(); }
- const SessionDescription* description() const override {
- return description_.get();
- }
- std::string session_id() const override { return session_id_; }
- std::string session_version() const override { return session_version_; }
- SdpType GetType() const override { return type_; }
- std::string type() const override { return SdpTypeToString(type_); }
bool AddCandidate(const IceCandidate* candidate) override;
bool RemoveCandidate(const IceCandidate* candidate) override;
- size_t number_of_mediasections() const override;
const IceCandidateCollection* candidates(
size_t mediasection_index) const override;
bool ToString(std::string* out) const override;
private:
- const std::unique_ptr<SessionDescription> description_;
- const std::string session_id_;
- const std::string session_version_;
- const SdpType type_;
std::vector<IceCandidateCollection> candidate_collection_;
bool IsValidMLineIndex(int index) const;
diff --git a/third_party/libwebrtc/api/test/DEPS b/third_party/libwebrtc/api/test/DEPS
@@ -61,6 +61,9 @@ specific_include_rules = {
"mock_peerconnectioninterface\.h": [
"+rtc_base/thread.h",
],
+ "mock_session_description_interface\.h": [
+ "+pc/session_description.h",
+ ],
"videocodec_test_fixture\.h": [
"+modules/video_coding/codecs/h264/include/h264_globals.h",
],
diff --git a/third_party/libwebrtc/api/test/mock_session_description_interface.h b/third_party/libwebrtc/api/test/mock_session_description_interface.h
@@ -17,6 +17,7 @@
#include <type_traits>
#include "api/jsep.h"
+#include "pc/session_description.h"
#include "test/gmock.h"
namespace webrtc {
@@ -27,7 +28,8 @@ class [[deprecated(
"interface.")]] MockSessionDescriptionInterface
: public SessionDescriptionInterface {
public:
- MockSessionDescriptionInterface() = default;
+ MockSessionDescriptionInterface()
+ : SessionDescriptionInterface(SdpType::kRollback, nullptr, "", "") {}
MOCK_METHOD(std::unique_ptr<SessionDescriptionInterface>,
Clone,
(),
diff --git a/third_party/libwebrtc/moz-patch-stack/s0027.patch b/third_party/libwebrtc/moz-patch-stack/s0027.patch
@@ -203,7 +203,7 @@ index 3efce2dd19..cbfc05f243 100644
}
diff --git a/api/BUILD.gn b/api/BUILD.gn
-index 47f3e23450..462739dea8 100644
+index 1c02e38171..7758d17af0 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -44,6 +44,9 @@ rtc_library("enable_media") {
@@ -287,7 +287,7 @@ index 47f3e23450..462739dea8 100644
visibility = [ "*" ]
cflags = []
sources = [
-@@ -422,6 +450,7 @@ rtc_library("libjingle_peerconnection_api") {
+@@ -423,6 +451,7 @@ rtc_library("libjingle_peerconnection_api") {
"../rtc_base/system:rtc_export",
]
}
@@ -295,7 +295,7 @@ index 47f3e23450..462739dea8 100644
rtc_library("frame_transformer_interface") {
visibility = [ "*" ]
-@@ -644,6 +673,7 @@ rtc_source_set("peer_network_dependencies") {
+@@ -645,6 +674,7 @@ rtc_source_set("peer_network_dependencies") {
}
rtc_source_set("peer_connection_quality_test_fixture_api") {
@@ -303,7 +303,7 @@ index 47f3e23450..462739dea8 100644
visibility = [ "*" ]
testonly = true
sources = [ "test/peerconnection_quality_test_fixture.h" ]
-@@ -688,6 +718,7 @@ rtc_source_set("peer_connection_quality_test_fixture_api") {
+@@ -689,6 +719,7 @@ rtc_source_set("peer_connection_quality_test_fixture_api") {
"//third_party/abseil-cpp/absl/strings:string_view",
]
}
@@ -311,7 +311,7 @@ index 47f3e23450..462739dea8 100644
rtc_library("frame_generator_api") {
visibility = [ "*" ]
-@@ -793,6 +824,7 @@ rtc_library("create_frame_generator") {
+@@ -794,6 +825,7 @@ rtc_library("create_frame_generator") {
]
}
@@ -319,7 +319,7 @@ index 47f3e23450..462739dea8 100644
rtc_library("create_peer_connection_quality_test_frame_generator") {
visibility = [ "*" ]
testonly = true
-@@ -810,6 +842,7 @@ rtc_library("create_peer_connection_quality_test_frame_generator") {
+@@ -811,6 +843,7 @@ rtc_library("create_peer_connection_quality_test_frame_generator") {
"units:time_delta",
]
}
@@ -327,7 +327,7 @@ index 47f3e23450..462739dea8 100644
rtc_source_set("data_channel_event_observer_interface") {
visibility = [ "*" ]
-@@ -1002,6 +1035,7 @@ rtc_source_set("refcountedbase") {
+@@ -1003,6 +1036,7 @@ rtc_source_set("refcountedbase") {
}
rtc_library("ice_transport_factory") {
@@ -335,7 +335,7 @@ index 47f3e23450..462739dea8 100644
visibility = [ "*" ]
sources = [
"ice_transport_factory.cc",
-@@ -1025,6 +1059,7 @@ rtc_library("ice_transport_factory") {
+@@ -1026,6 +1060,7 @@ rtc_library("ice_transport_factory") {
"rtc_event_log",
]
}
diff --git a/third_party/libwebrtc/moz-patch-stack/s0102.patch b/third_party/libwebrtc/moz-patch-stack/s0102.patch
@@ -126,7 +126,7 @@ index 771e0b196a..7e1e8353ab 100644
"Generated during 'gn gen' by //BUILD.gn.",
"",
diff --git a/api/BUILD.gn b/api/BUILD.gn
-index 462739dea8..c6bf3e1bce 100644
+index 7758d17af0..129e246104 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -8,8 +8,8 @@
diff --git a/third_party/libwebrtc/pc/jsep_session_description.cc b/third_party/libwebrtc/pc/jsep_session_description.cc
@@ -150,20 +150,50 @@ std::unique_ptr<SessionDescriptionInterface> CreateRollbackSessionDescription(
SdpType::kRollback, /*description=*/nullptr, session_id, session_version);
}
-JsepSessionDescription::JsepSessionDescription(SdpType type) : type_(type) {}
+SessionDescriptionInternal::SessionDescriptionInternal(
+ SdpType type,
+ std::unique_ptr<SessionDescription> description,
+ absl::string_view id,
+ absl::string_view version)
+ : sdp_type_(type),
+ id_(id),
+ version_(version),
+ description_(std::move(description)) {
+ RTC_DCHECK(description_ || sdp_type_ == SdpType::kRollback);
+}
-JsepSessionDescription::JsepSessionDescription(
+SessionDescriptionInternal::~SessionDescriptionInternal() = default;
+
+size_t SessionDescriptionInternal::mediasection_count() const {
+ return description_ ? description_->contents().size() : 0u;
+}
+
+void SessionDescriptionInternal::RelinquishThreadOwnership() {
+ sequence_checker_.Detach();
+}
+
+SessionDescriptionInterface::SessionDescriptionInterface(
SdpType type,
std::unique_ptr<SessionDescription> description,
+ absl::string_view id,
+ absl::string_view version)
+ : SessionDescriptionInternal(type, std::move(description), id, version) {}
+
+JsepSessionDescription::JsepSessionDescription(SdpType type)
+ : SessionDescriptionInterface(type, nullptr, "", "") {}
+
+JsepSessionDescription::JsepSessionDescription(
+ SdpType type,
+ std::unique_ptr<SessionDescription> desc,
absl::string_view session_id,
absl::string_view session_version,
std::vector<IceCandidateCollection> candidates)
- : description_(std::move(description)),
- session_id_(session_id),
- session_version_(session_version),
- type_(type),
+ : SessionDescriptionInterface(type,
+ std::move(desc),
+ session_id,
+ session_version),
candidate_collection_(std::move(candidates)) {
- RTC_DCHECK(description_ || type == SdpType::kRollback);
+ RTC_DCHECK(description() || type == SdpType::kRollback);
RTC_DCHECK(candidate_collection_.empty() ||
candidate_collection_.size() == number_of_mediasections());
candidate_collection_.resize(number_of_mediasections());
@@ -174,9 +204,8 @@ JsepSessionDescription::~JsepSessionDescription() {}
std::unique_ptr<SessionDescriptionInterface> JsepSessionDescription::Clone()
const {
return std::make_unique<JsepSessionDescription>(
- GetType(), description_.get() ? description_->Clone() : nullptr,
- session_id_, session_version_,
- CloneCandidateCollection(candidate_collection_));
+ sdp_type(), description() ? description()->Clone() : nullptr, id(),
+ version(), CloneCandidateCollection(candidate_collection_));
}
bool JsepSessionDescription::AddCandidate(const IceCandidate* candidate) {
@@ -187,9 +216,9 @@ bool JsepSessionDescription::AddCandidate(const IceCandidate* candidate) {
return false;
}
const std::string& mediasection_mid =
- description_->contents()[mediasection_index].mid();
+ description()->contents()[mediasection_index].mid();
const TransportInfo* transport_info =
- description_->GetTransportInfoByName(mediasection_mid);
+ description()->GetTransportInfoByName(mediasection_mid);
if (!transport_info) {
return false;
}
@@ -219,7 +248,7 @@ bool JsepSessionDescription::AddCandidate(const IceCandidate* candidate) {
std::move(updated_candidate_wrapper));
UpdateConnectionAddress(
candidate_collection_[mediasection_index],
- description_->contents()[mediasection_index].media_description());
+ description()->contents()[mediasection_index].media_description());
}
return true;
@@ -235,16 +264,10 @@ bool JsepSessionDescription::RemoveCandidate(const IceCandidate* candidate) {
}
UpdateConnectionAddress(
candidate_collection_[mediasection_index],
- description_->contents()[mediasection_index].media_description());
+ description()->contents()[mediasection_index].media_description());
return true;
}
-size_t JsepSessionDescription::number_of_mediasections() const {
- if (!description_)
- return 0;
- return description_->contents().size();
-}
-
const IceCandidateCollection* JsepSessionDescription::candidates(
size_t mediasection_index) const {
if (mediasection_index >= candidate_collection_.size())
@@ -253,7 +276,7 @@ const IceCandidateCollection* JsepSessionDescription::candidates(
}
bool JsepSessionDescription::ToString(std::string* out) const {
- if (!description_ || !out) {
+ if (!description() || !out) {
return false;
}
*out = SdpSerialize(*this);
@@ -261,14 +284,14 @@ bool JsepSessionDescription::ToString(std::string* out) const {
}
bool JsepSessionDescription::IsValidMLineIndex(int index) const {
- RTC_DCHECK(description_);
+ RTC_DCHECK(description());
return index >= 0 &&
- index < static_cast<int>(description_->contents().size());
+ index < static_cast<int>(description()->contents().size());
}
bool JsepSessionDescription::GetMediasectionIndex(const IceCandidate* candidate,
size_t* index) const {
- if (!candidate || !index || !description_) {
+ if (!candidate || !index || !description()) {
return false;
}
@@ -283,7 +306,7 @@ bool JsepSessionDescription::GetMediasectionIndex(const IceCandidate* candidate,
}
int JsepSessionDescription::GetMediasectionIndex(absl::string_view mid) const {
- const auto& contents = description_->contents();
+ const auto& contents = description()->contents();
auto it =
std::find_if(contents.begin(), contents.end(),
[&](const auto& content) { return mid == content.mid(); });