Enable PipeWire camera support for RHEL 10

Also backport upstream fixes for PipeWire camera support.

Resolves: RHEL-64749
This commit is contained in:
Jan Grulich 2024-11-26 09:16:27 +01:00
parent aa98dd5570
commit 85157a42c7
12 changed files with 1849 additions and 1 deletions

View File

@ -0,0 +1,116 @@
From 92643d686bed8f3e4f2c1aae194925b6dc9dea86 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Fri, 28 Jun 2024 18:13:15 +0000
Subject: [PATCH] Bug 1905335 - WebRTC backport: PipeWire capture: hide cursor
when it goes off screen or is not visible r=pehrsons,webrtc-reviewers
This is a simple backport of an WebRTC upstream change.
Upstream commit: e6ad337d633c145c48a5a4ae54968c14c16081c7
Differential Revision: https://phabricator.services.mozilla.com/D215197
---
.../wayland/mouse_cursor_monitor_pipewire.cc | 14 +++--
.../linux/wayland/shared_screencast_stream.cc | 52 +++++++++++--------
.../e6ad337d63.no-op-cherry-pick-msg | 1 +
3 files changed, 39 insertions(+), 28 deletions(-)
create mode 100644 third_party/libwebrtc/moz-patch-stack/e6ad337d63.no-op-cherry-pick-msg
diff --git a/third_party/libwebrtc/modules/desktop_capture/linux/wayland/mouse_cursor_monitor_pipewire.cc b/third_party/libwebrtc/modules/desktop_capture/linux/wayland/mouse_cursor_monitor_pipewire.cc
index 3d33b0fbb8e6e..00b07f341b16a 100644
--- a/third_party/libwebrtc/modules/desktop_capture/linux/wayland/mouse_cursor_monitor_pipewire.cc
+++ b/third_party/libwebrtc/modules/desktop_capture/linux/wayland/mouse_cursor_monitor_pipewire.cc
@@ -40,6 +40,14 @@ void MouseCursorMonitorPipeWire::Capture() {
RTC_DCHECK_RUN_ON(&sequence_checker_);
RTC_DCHECK(callback_);
+ absl::optional<DesktopVector> mouse_cursor_position =
+ options_.screencast_stream()->CaptureCursorPosition();
+ // Invalid cursor or position
+ if (!mouse_cursor_position) {
+ callback_->OnMouseCursor(nullptr);
+ return;
+ }
+
std::unique_ptr<MouseCursor> mouse_cursor =
options_.screencast_stream()->CaptureCursor();
@@ -48,11 +56,7 @@ void MouseCursorMonitorPipeWire::Capture() {
}
if (mode_ == SHAPE_AND_POSITION) {
- absl::optional<DesktopVector> mouse_cursor_position =
- options_.screencast_stream()->CaptureCursorPosition();
- if (mouse_cursor_position) {
- callback_->OnMouseCursorPosition(mouse_cursor_position.value());
- }
+ callback_->OnMouseCursorPosition(mouse_cursor_position.value());
}
}
diff --git a/third_party/libwebrtc/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/third_party/libwebrtc/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
index ab9054f1a1676..b8cac318ffeb9 100644
--- a/third_party/libwebrtc/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
+++ b/third_party/libwebrtc/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
@@ -690,32 +690,38 @@ void SharedScreenCastStreamPrivate::ProcessBuffer(pw_buffer* buffer) {
const struct spa_meta_cursor* cursor =
static_cast<struct spa_meta_cursor*>(spa_buffer_find_meta_data(
spa_buffer, SPA_META_Cursor, sizeof(*cursor)));
- if (cursor && spa_meta_cursor_is_valid(cursor)) {
- struct spa_meta_bitmap* bitmap = nullptr;
-
- if (cursor->bitmap_offset)
- bitmap =
- SPA_MEMBER(cursor, cursor->bitmap_offset, struct spa_meta_bitmap);
-
- if (bitmap && bitmap->size.width > 0 && bitmap->size.height > 0) {
- const uint8_t* bitmap_data =
- SPA_MEMBER(bitmap, bitmap->offset, uint8_t);
- BasicDesktopFrame* mouse_frame = new BasicDesktopFrame(
- DesktopSize(bitmap->size.width, bitmap->size.height));
- mouse_frame->CopyPixelsFrom(
- bitmap_data, bitmap->stride,
- DesktopRect::MakeWH(bitmap->size.width, bitmap->size.height));
- mouse_cursor_ = std::make_unique<MouseCursor>(
- mouse_frame, DesktopVector(cursor->hotspot.x, cursor->hotspot.y));
- if (observer_) {
- observer_->OnCursorShapeChanged();
+ if (cursor) {
+ if (spa_meta_cursor_is_valid(cursor)) {
+ struct spa_meta_bitmap* bitmap = nullptr;
+
+ if (cursor->bitmap_offset)
+ bitmap =
+ SPA_MEMBER(cursor, cursor->bitmap_offset, struct spa_meta_bitmap);
+
+ if (bitmap && bitmap->size.width > 0 && bitmap->size.height > 0) {
+ const uint8_t* bitmap_data =
+ SPA_MEMBER(bitmap, bitmap->offset, uint8_t);
+ BasicDesktopFrame* mouse_frame = new BasicDesktopFrame(
+ DesktopSize(bitmap->size.width, bitmap->size.height));
+ mouse_frame->CopyPixelsFrom(
+ bitmap_data, bitmap->stride,
+ DesktopRect::MakeWH(bitmap->size.width, bitmap->size.height));
+ mouse_cursor_ = std::make_unique<MouseCursor>(
+ mouse_frame, DesktopVector(cursor->hotspot.x, cursor->hotspot.y));
+
+ if (observer_) {
+ observer_->OnCursorShapeChanged();
+ }
}
- }
- mouse_cursor_position_.set(cursor->position.x, cursor->position.y);
+ mouse_cursor_position_.set(cursor->position.x, cursor->position.y);
- if (observer_) {
- observer_->OnCursorPositionChanged();
+ if (observer_) {
+ observer_->OnCursorPositionChanged();
+ }
+ } else {
+ // Indicate an invalid cursor
+ mouse_cursor_position_.set(-1, -1);
}
}
}

View File

@ -0,0 +1,87 @@
From fef1904f95dc592deef7044debe71a02c5d7046c Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Sat, 20 Jul 2024 07:04:27 +0000
Subject: [PATCH] Bug 1907013 - WebRTC backport: PipeWire camera: support
additional formats and fix RGB/BGR mapping r=jib,webrtc-reviewers
This is a simple backprot of an WebRTC upstream change.
Upstream commit: b1ebcfbfd6afb57f314b6689ca001aca1b13a5b4
Differential Revision: https://phabricator.services.mozilla.com/D216138
---
.../modules/video_capture/linux/pipewire_session.cc | 6 ++++++
.../video_capture/linux/video_capture_pipewire.cc | 12 ++++++++++--
.../moz-patch-stack/b1ebcfbfd6.no-op-cherry-pick-msg | 1 +
3 files changed, 17 insertions(+), 2 deletions(-)
create mode 100644 third_party/libwebrtc/moz-patch-stack/b1ebcfbfd6.no-op-cherry-pick-msg
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
index d52d6aacc8005..107ea3dfbd954 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
@@ -35,12 +35,18 @@ VideoType PipeWireRawFormatToVideoType(uint32_t id) {
return VideoType::kYUY2;
case SPA_VIDEO_FORMAT_UYVY:
return VideoType::kUYVY;
+ case SPA_VIDEO_FORMAT_RGB16:
+ return VideoType::kRGB565;
case SPA_VIDEO_FORMAT_RGB:
+ return VideoType::kBGR24;
+ case SPA_VIDEO_FORMAT_BGR:
return VideoType::kRGB24;
case SPA_VIDEO_FORMAT_BGRA:
return VideoType::kARGB;
case SPA_VIDEO_FORMAT_RGBA:
return VideoType::kABGR;
+ case SPA_VIDEO_FORMAT_ARGB:
+ return VideoType::kBGRA;
default:
return VideoType::kUnknown;
}
diff --git a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
index 9ff4fdb9b1c98..1672b7583f582 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
@@ -34,10 +34,15 @@ struct {
{SPA_VIDEO_FORMAT_YUY2, VideoType::kYUY2},
{SPA_VIDEO_FORMAT_UYVY, VideoType::kUYVY},
// PipeWire is big-endian for the formats, while libyuv is little-endian
- // This means that BGRA == ARGB and RGBA == ABGR
+ // This means that BGRA == ARGB, RGBA == ABGR and similar
+ // This follows mapping in libcamera PipeWire plugin:
+ // https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/spa/plugins/libcamera/libcamera-utils.cpp
{SPA_VIDEO_FORMAT_BGRA, VideoType::kARGB},
{SPA_VIDEO_FORMAT_RGBA, VideoType::kABGR},
- {SPA_VIDEO_FORMAT_RGB, VideoType::kRGB24},
+ {SPA_VIDEO_FORMAT_ARGB, VideoType::kBGRA},
+ {SPA_VIDEO_FORMAT_RGB, VideoType::kBGR24},
+ {SPA_VIDEO_FORMAT_BGR, VideoType::kRGB24},
+ {SPA_VIDEO_FORMAT_RGB16, VideoType::kRGB565},
};
VideoType VideoCaptureModulePipeWire::PipeWireRawFormatToVideoType(
@@ -302,13 +307,16 @@ void VideoCaptureModulePipeWire::OnFormatChanged(const struct spa_pod* format) {
break;
case VideoType::kYUY2:
case VideoType::kUYVY:
+ case VideoType::kRGB565:
stride = configured_capability_.width * 2;
break;
case VideoType::kRGB24:
+ case VideoType::kBGR24:
stride = configured_capability_.width * 3;
break;
case VideoType::kARGB:
case VideoType::kABGR:
+ case VideoType::kBGRA:
stride = configured_capability_.width * 4;
break;
default:
diff --git a/third_party/libwebrtc/moz-patch-stack/b1ebcfbfd6.no-op-cherry-pick-msg b/third_party/libwebrtc/moz-patch-stack/b1ebcfbfd6.no-op-cherry-pick-msg
new file mode 100644
index 0000000000000..e795b816b1382
--- /dev/null
+++ b/third_party/libwebrtc/moz-patch-stack/b1ebcfbfd6.no-op-cherry-pick-msg
@@ -0,0 +1 @@
+We cherry-picked this in bug 1907013.

View File

@ -0,0 +1,231 @@
From 286575b387cff9b3ec318d3cf90cf20d2f3c2ce4 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Mon, 2 Sep 2024 11:07:20 +0000
Subject: [PATCH] Bug 1913286 - WebRTC backport: PipeWire camera: filter out
devices with no capabilities r=pehrsons,webrtc-reviewers
Filter out devices that do not support any format supported by WebRTC.
This will for example be IR cameras that show as duplicated in the list
of cameras, but support only GRAY8 format and for that reason do not
work at all.
This is a simple backport of an WebRTC upstream change.
Upstream commit: b4aba7834e6c94adace1cb4c20e2e1ee70eb9cc5
Differential Revision: https://phabricator.services.mozilla.com/D219224
---
.../linux/device_info_pipewire.cc | 20 ++++-----
.../video_capture/linux/pipewire_session.cc | 43 +++++++++++++------
.../video_capture/linux/pipewire_session.h | 21 ++++++---
.../b4aba7834e.no-op-cherry-pick-msg | 1 +
4 files changed, 58 insertions(+), 27 deletions(-)
create mode 100644 third_party/libwebrtc/moz-patch-stack/b4aba7834e.no-op-cherry-pick-msg
diff --git a/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc b/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
index 31d922035b3f8..db2a3c7099169 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
@@ -57,31 +57,31 @@ int32_t DeviceInfoPipeWire::GetDeviceName(uint32_t deviceNumber,
if (deviceNumber >= NumberOfDevices())
return -1;
- const PipeWireNode& node = pipewire_session_->nodes().at(deviceNumber);
+ const auto& node = pipewire_session_->nodes().at(deviceNumber);
- if (deviceNameLength <= node.display_name().length()) {
+ if (deviceNameLength <= node->display_name().length()) {
RTC_LOG(LS_INFO) << "deviceNameUTF8 buffer passed is too small";
return -1;
}
- if (deviceUniqueIdUTF8Length <= node.unique_id().length()) {
+ if (deviceUniqueIdUTF8Length <= node->unique_id().length()) {
RTC_LOG(LS_INFO) << "deviceUniqueIdUTF8 buffer passed is too small";
return -1;
}
if (productUniqueIdUTF8 &&
- productUniqueIdUTF8Length <= node.model_id().length()) {
+ productUniqueIdUTF8Length <= node->model_id().length()) {
RTC_LOG(LS_INFO) << "productUniqueIdUTF8 buffer passed is too small";
return -1;
}
memset(deviceNameUTF8, 0, deviceNameLength);
- node.display_name().copy(deviceNameUTF8, deviceNameLength);
+ node->display_name().copy(deviceNameUTF8, deviceNameLength);
memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
- node.unique_id().copy(deviceUniqueIdUTF8, deviceUniqueIdUTF8Length);
+ node->unique_id().copy(deviceUniqueIdUTF8, deviceUniqueIdUTF8Length);
if (productUniqueIdUTF8) {
memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
- node.model_id().copy(productUniqueIdUTF8, productUniqueIdUTF8Length);
+ node->model_id().copy(productUniqueIdUTF8, productUniqueIdUTF8Length);
}
return 0;
@@ -92,11 +92,11 @@ int32_t DeviceInfoPipeWire::CreateCapabilityMap(
RTC_CHECK(pipewire_session_);
for (auto& node : pipewire_session_->nodes()) {
- if (node.unique_id().compare(deviceUniqueIdUTF8) != 0)
+ if (node->unique_id().compare(deviceUniqueIdUTF8) != 0)
continue;
- _captureCapabilities = node.capabilities();
- _lastUsedDeviceNameLength = node.unique_id().length();
+ _captureCapabilities = node->capabilities();
+ _lastUsedDeviceNameLength = node->unique_id().length();
_lastUsedDeviceName = static_cast<char*>(
realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8,
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
index 107ea3dfbd954..dbac09274bb31 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
@@ -52,6 +52,19 @@ VideoType PipeWireRawFormatToVideoType(uint32_t id) {
}
}
+void PipeWireNode::PipeWireNodeDeleter::operator()(
+ PipeWireNode* node) const noexcept {
+ pw_proxy_destroy(node->proxy_);
+ spa_hook_remove(&node->node_listener_);
+}
+
+// static
+PipeWireNode::PipeWireNodePtr PipeWireNode::Create(PipeWireSession* session,
+ uint32_t id,
+ const spa_dict* props) {
+ return PipeWireNodePtr(new PipeWireNode(session, id, props));
+}
+
PipeWireNode::PipeWireNode(PipeWireSession* session,
uint32_t id,
const spa_dict* props)
@@ -73,11 +86,6 @@ PipeWireNode::PipeWireNode(PipeWireSession* session,
pw_node_add_listener(proxy_, &node_listener_, &node_events, this);
}
-PipeWireNode::~PipeWireNode() {
- pw_proxy_destroy(proxy_);
- spa_hook_remove(&node_listener_);
-}
-
// static
void PipeWireNode::OnNodeInfo(void* data, const pw_node_info* info) {
PipeWireNode* that = static_cast<PipeWireNode*>(data);
@@ -99,7 +107,9 @@ void PipeWireNode::OnNodeInfo(void* data, const pw_node_info* info) {
pid.value());
that->model_id_ = model_str;
}
- } else if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
+ }
+
+ if (info->change_mask & PW_NODE_CHANGE_MASK_PARAMS) {
for (uint32_t i = 0; i < info->n_params; i++) {
uint32_t id = info->params[i].id;
if (id == SPA_PARAM_EnumFormat &&
@@ -350,6 +360,14 @@ void PipeWireSession::OnCoreDone(void* data, uint32_t id, int seq) {
if (id == PW_ID_CORE) {
if (seq == that->sync_seq_) {
RTC_LOG(LS_VERBOSE) << "Enumerating PipeWire camera devices complete.";
+
+ // Remove camera devices with no capabilities
+ auto it = std::remove_if(that->nodes_.begin(), that->nodes_.end(),
+ [](const PipeWireNode::PipeWireNodePtr& node) {
+ return node->capabilities().empty();
+ });
+ that->nodes_.erase(it, that->nodes_.end());
+
that->Finish(VideoCaptureOptions::Status::SUCCESS);
}
}
@@ -366,8 +384,8 @@ void PipeWireSession::OnRegistryGlobal(void* data,
// Skip already added nodes to avoid duplicate camera entries
if (std::find_if(that->nodes_.begin(), that->nodes_.end(),
- [id](const PipeWireNode& node) {
- return node.id() == id;
+ [id](const PipeWireNode::PipeWireNodePtr& node) {
+ return node->id() == id;
}) != that->nodes_.end())
return;
@@ -381,7 +399,7 @@ void PipeWireSession::OnRegistryGlobal(void* data,
if (!node_role || strcmp(node_role, "Camera"))
return;
- that->nodes_.emplace_back(that, id, props);
+ that->nodes_.push_back(PipeWireNode::Create(that, id, props));
that->PipeWireSync();
}
@@ -389,9 +407,10 @@ void PipeWireSession::OnRegistryGlobal(void* data,
void PipeWireSession::OnRegistryGlobalRemove(void* data, uint32_t id) {
PipeWireSession* that = static_cast<PipeWireSession*>(data);
- auto it = std::remove_if(
- that->nodes_.begin(), that->nodes_.end(),
- [id](const PipeWireNode& node) { return node.id() == id; });
+ auto it = std::remove_if(that->nodes_.begin(), that->nodes_.end(),
+ [id](const PipeWireNode::PipeWireNodePtr& node) {
+ return node->id() == id;
+ });
that->nodes_.erase(it, that->nodes_.end());
}
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
index fdc06a6b2a27a..84273ea695277 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
@@ -37,8 +37,15 @@ class VideoCaptureModulePipeWire;
// So they all represent one camera that is available via PipeWire.
class PipeWireNode {
public:
- PipeWireNode(PipeWireSession* session, uint32_t id, const spa_dict* props);
- ~PipeWireNode();
+ struct PipeWireNodeDeleter {
+ void operator()(PipeWireNode* node) const noexcept;
+ };
+
+ using PipeWireNodePtr =
+ std::unique_ptr<PipeWireNode, PipeWireNode::PipeWireNodeDeleter>;
+ static PipeWireNodePtr Create(PipeWireSession* session,
+ uint32_t id,
+ const spa_dict* props);
uint32_t id() const { return id_; }
std::string display_name() const { return display_name_; }
@@ -48,6 +55,9 @@ class PipeWireNode {
return capabilities_;
}
+ protected:
+ PipeWireNode(PipeWireSession* session, uint32_t id, const spa_dict* props);
+
private:
static void OnNodeInfo(void* data, const pw_node_info* info);
static void OnNodeParam(void* data,
@@ -87,8 +97,9 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
void Init(VideoCaptureOptions::Callback* callback,
int fd = kInvalidPipeWireFd);
-
- const std::deque<PipeWireNode>& nodes() const { return nodes_; }
+ const std::deque<PipeWireNode::PipeWireNodePtr>& nodes() const {
+ return nodes_;
+ }
friend class CameraPortalNotifier;
friend class PipeWireNode;
@@ -134,7 +145,7 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
int sync_seq_ = 0;
- std::deque<PipeWireNode> nodes_;
+ std::deque<PipeWireNode::PipeWireNodePtr> nodes_;
std::unique_ptr<CameraPortal> portal_;
std::unique_ptr<CameraPortalNotifier> portal_notifier_;
};

View File

@ -0,0 +1,52 @@
From b10c1d09729794c46f9c04d04c07c18d514d396e Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Wed, 4 Sep 2024 13:43:29 +0000
Subject: [PATCH] Bug 1912785 - Always query information about camera
availability r=pehrsons
We have to always update camera availability information, even when we
don't request cameras, because the WebRTC backend automatically creates
camera video engine and not having this information we might hitting an
assert later, where we assume the status of camera availability is not
unknown.
Differential Revision: https://phabricator.services.mozilla.com/D219062
---
dom/media/MediaManager.cpp | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp
index 2ade297d31e84..3cc716e6836ac 100644
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2153,9 +2153,15 @@ MediaManager::MaybeRequestPermissionAndEnumerateRawDevices(
}
if (!deviceAccessPromise) {
- // No device access request needed. Proceed directly.
- deviceAccessPromise =
- NativePromise::CreateAndResolve(CamerasAccessStatus::Granted, __func__);
+ // No device access request needed. We can proceed directly, but we still
+ // need to update camera availability, because the camera engine is always
+ // created together with the WebRTC backend, which is done because
+ // devicechange events must work before prompting in cases where persistent
+ // permission has already been given. Making a request to camera access not
+ // allowing a permission request does exactly what we need in this case.
+ ipc::PBackgroundChild* backgroundChild =
+ ipc::BackgroundChild::GetOrCreateForCurrentThread();
+ deviceAccessPromise = backgroundChild->SendRequestCameraAccess(false);
}
return deviceAccessPromise->Then(
@@ -2190,8 +2196,9 @@ MediaManager::MaybeRequestPermissionAndEnumerateRawDevices(
"rejected");
}
- if (aParams.mFlags.contains(EnumerationFlag::AllowPermissionRequest)) {
- MOZ_ASSERT(aValue.ResolveValue() == CamerasAccessStatus::Granted);
+ if (aParams.VideoInputType() == MediaSourceEnum::Camera &&
+ aParams.mFlags.contains(EnumerationFlag::AllowPermissionRequest) &&
+ aValue.ResolveValue() == CamerasAccessStatus::Granted) {
EnsureNoPlaceholdersInDeviceCache();
}

View File

@ -0,0 +1,293 @@
From df57b21200c7cde7ac34705e8fceab2fbe933bc5 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Tue, 3 Sep 2024 07:56:39 +0000
Subject: [PATCH] Bug 1912778 - Always register video input feedback for newly
created DeviceInfo r=pehrsons
Make sure to always register video input feedback when a new DeviceInfo
is created. We always destroy DeviceInfo once request to camera access
is resolved, making it to be created again, but this time skipping the
part where video input feedback is registered as we use already existing
VideoEngine. There is now just one place where DeviceInfo gets created
and the logic for video input feedback registration has been moved to
VideoEngine as it's the only place where we know when new DeviceInfo is
created.
Differential Revision: https://phabricator.services.mozilla.com/D219060
---
dom/media/systemservices/CamerasParent.cpp | 164 ++++++++++-----------
dom/media/systemservices/CamerasParent.h | 5 +
dom/media/systemservices/VideoEngine.cpp | 7 +-
dom/media/systemservices/VideoEngine.h | 2 +-
4 files changed, 91 insertions(+), 87 deletions(-)
diff --git a/dom/media/systemservices/CamerasParent.cpp b/dom/media/systemservices/CamerasParent.cpp
index 048d07b7fa..d6fe5986da 100644
--- a/dom/media/systemservices/CamerasParent.cpp
+++ b/dom/media/systemservices/CamerasParent.cpp
@@ -405,15 +405,25 @@ void CamerasParent::CloseEngines() {
Unused << ReleaseCapture(capEngine, streamNum);
}
- if (VideoEngine* engine = mEngines->ElementAt(CameraEngine); engine) {
- auto device_info = engine->GetOrCreateVideoCaptureDeviceInfo();
- MOZ_ASSERT(device_info);
- if (device_info) {
- device_info->DeRegisterVideoInputFeedBack(this);
- }
+ auto device_info = GetDeviceInfo(CameraEngine);
+ MOZ_ASSERT(device_info);
+ if (device_info) {
+ device_info->DeRegisterVideoInputFeedBack(this);
}
}
+std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo>
+CamerasParent::GetDeviceInfo(int aEngine) {
+ MOZ_ASSERT(mVideoCaptureThread->IsOnCurrentThread());
+ LOG_VERBOSE("CamerasParent(%p)::%s", this, __func__);
+
+ auto* engine = EnsureInitialized(aEngine);
+ if (!engine) {
+ return nullptr;
+ }
+ return engine->GetOrCreateVideoCaptureDeviceInfo(this);
+}
+
VideoEngine* CamerasParent::EnsureInitialized(int aEngine) {
MOZ_ASSERT(mVideoCaptureThread->IsOnCurrentThread());
LOG_VERBOSE("CamerasParent(%p)::%s", this, __func__);
@@ -449,14 +459,6 @@ VideoEngine* CamerasParent::EnsureInitialized(int aEngine) {
return nullptr;
}
- if (capEngine == CameraEngine) {
- auto device_info = engine->GetOrCreateVideoCaptureDeviceInfo();
- MOZ_ASSERT(device_info);
- if (device_info) {
- device_info->RegisterVideoInputFeedBack(this);
- }
- }
-
return mEngines->ElementAt(capEngine) = std::move(engine);
}
@@ -474,19 +476,16 @@ ipc::IPCResult CamerasParent::RecvNumberOfCaptureDevices(
LOG("CaptureEngine=%d", aCapEngine);
using Promise = MozPromise<int, bool, true>;
- InvokeAsync(
- mVideoCaptureThread, __func__,
- [this, self = RefPtr(this), aCapEngine] {
- int num = -1;
- if (auto* engine = EnsureInitialized(aCapEngine)) {
- if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
- num = static_cast<int>(devInfo->NumberOfDevices());
- }
- }
+ InvokeAsync(mVideoCaptureThread, __func__,
+ [this, self = RefPtr(this), aCapEngine] {
+ int num = -1;
+ if (auto devInfo = GetDeviceInfo(aCapEngine)) {
+ num = static_cast<int>(devInfo->NumberOfDevices());
+ }
- return Promise::CreateAndResolve(
- num, "CamerasParent::RecvNumberOfCaptureDevices");
- })
+ return Promise::CreateAndResolve(
+ num, "CamerasParent::RecvNumberOfCaptureDevices");
+ })
->Then(
mPBackgroundEventTarget, __func__,
[this, self = RefPtr(this)](Promise::ResolveOrRejectValue&& aValue) {
@@ -558,10 +557,8 @@ ipc::IPCResult CamerasParent::RecvNumberOfCapabilities(
mVideoCaptureThread, __func__,
[this, self = RefPtr(this), id = nsCString(aUniqueId), aCapEngine]() {
int num = -1;
- if (auto* engine = EnsureInitialized(aCapEngine)) {
- if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
- num = devInfo->NumberOfCapabilities(id.get());
- }
+ if (auto devInfo = GetDeviceInfo(aCapEngine)) {
+ num = devInfo->NumberOfCapabilities(id.get());
}
return Promise::CreateAndResolve(
num, "CamerasParent::RecvNumberOfCapabilities");
@@ -599,36 +596,34 @@ ipc::IPCResult CamerasParent::RecvGetCaptureCapability(
aIndex);
using Promise = MozPromise<webrtc::VideoCaptureCapability, int, true>;
- InvokeAsync(
- mVideoCaptureThread, __func__,
- [this, self = RefPtr(this), id = nsCString(aUniqueId), aCapEngine,
- aIndex] {
- webrtc::VideoCaptureCapability webrtcCaps;
- int error = -1;
- if (auto* engine = EnsureInitialized(aCapEngine)) {
- if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
- error = devInfo->GetCapability(id.get(), aIndex, webrtcCaps);
- }
- }
+ InvokeAsync(mVideoCaptureThread, __func__,
+ [this, self = RefPtr(this), id = nsCString(aUniqueId), aCapEngine,
+ aIndex] {
+ webrtc::VideoCaptureCapability webrtcCaps;
+ int error = -1;
+ if (auto devInfo = GetDeviceInfo(aCapEngine)) {
+ error = devInfo->GetCapability(id.get(), aIndex, webrtcCaps);
+ }
- if (!error && aCapEngine == CameraEngine) {
- auto iter = mAllCandidateCapabilities.find(id);
- if (iter == mAllCandidateCapabilities.end()) {
- std::map<uint32_t, webrtc::VideoCaptureCapability>
- candidateCapabilities;
- candidateCapabilities.emplace(aIndex, webrtcCaps);
- mAllCandidateCapabilities.emplace(id, candidateCapabilities);
- } else {
- (iter->second).emplace(aIndex, webrtcCaps);
- }
- }
- if (error) {
- return Promise::CreateAndReject(
- error, "CamerasParent::RecvGetCaptureCapability");
- }
- return Promise::CreateAndResolve(
- webrtcCaps, "CamerasParent::RecvGetCaptureCapability");
- })
+ if (!error && aCapEngine == CameraEngine) {
+ auto iter = mAllCandidateCapabilities.find(id);
+ if (iter == mAllCandidateCapabilities.end()) {
+ std::map<uint32_t, webrtc::VideoCaptureCapability>
+ candidateCapabilities;
+ candidateCapabilities.emplace(aIndex, webrtcCaps);
+ mAllCandidateCapabilities.emplace(id,
+ candidateCapabilities);
+ } else {
+ (iter->second).emplace(aIndex, webrtcCaps);
+ }
+ }
+ if (error) {
+ return Promise::CreateAndReject(
+ error, "CamerasParent::RecvGetCaptureCapability");
+ }
+ return Promise::CreateAndResolve(
+ webrtcCaps, "CamerasParent::RecvGetCaptureCapability");
+ })
->Then(
mPBackgroundEventTarget, __func__,
[this, self = RefPtr(this)](Promise::ResolveOrRejectValue&& aValue) {
@@ -664,33 +659,32 @@ ipc::IPCResult CamerasParent::RecvGetCaptureDevice(
using Data = std::tuple<nsCString, nsCString, pid_t, bool, int>;
using Promise = MozPromise<Data, bool, true>;
- InvokeAsync(
- mVideoCaptureThread, __func__,
- [this, self = RefPtr(this), aCapEngine, aDeviceIndex] {
- char deviceName[MediaEngineSource::kMaxDeviceNameLength];
- char deviceUniqueId[MediaEngineSource::kMaxUniqueIdLength];
- nsCString name;
- nsCString uniqueId;
- pid_t devicePid = 0;
- bool placeholder = false;
- int error = -1;
- if (auto* engine = EnsureInitialized(aCapEngine)) {
- if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
- error = devInfo->GetDeviceName(
- aDeviceIndex, deviceName, sizeof(deviceName), deviceUniqueId,
- sizeof(deviceUniqueId), nullptr, 0, &devicePid, &placeholder);
- }
- }
- if (error == 0) {
- name.Assign(deviceName);
- uniqueId.Assign(deviceUniqueId);
- }
+ InvokeAsync(mVideoCaptureThread, __func__,
+ [this, self = RefPtr(this), aCapEngine, aDeviceIndex] {
+ char deviceName[MediaEngineSource::kMaxDeviceNameLength];
+ char deviceUniqueId[MediaEngineSource::kMaxUniqueIdLength];
+ nsCString name;
+ nsCString uniqueId;
+ pid_t devicePid = 0;
+ bool placeholder = false;
+ int error = -1;
+ if (auto devInfo = GetDeviceInfo(aCapEngine)) {
+ error = devInfo->GetDeviceName(
+ aDeviceIndex, deviceName, sizeof(deviceName),
+ deviceUniqueId, sizeof(deviceUniqueId), nullptr, 0,
+ &devicePid, &placeholder);
+ }
- return Promise::CreateAndResolve(
- std::make_tuple(std::move(name), std::move(uniqueId), devicePid,
- placeholder, error),
- "CamerasParent::RecvGetCaptureDevice");
- })
+ if (error == 0) {
+ name.Assign(deviceName);
+ uniqueId.Assign(deviceUniqueId);
+ }
+
+ return Promise::CreateAndResolve(
+ std::make_tuple(std::move(name), std::move(uniqueId),
+ devicePid, placeholder, error),
+ "CamerasParent::RecvGetCaptureDevice");
+ })
->Then(
mPBackgroundEventTarget, __func__,
[this, self = RefPtr(this)](Promise::ResolveOrRejectValue&& aValue) {
diff --git a/dom/media/systemservices/CamerasParent.h b/dom/media/systemservices/CamerasParent.h
index 9d6a6f2f35..11a5229629 100644
--- a/dom/media/systemservices/CamerasParent.h
+++ b/dom/media/systemservices/CamerasParent.h
@@ -144,6 +144,11 @@ class CamerasParent final : public PCamerasParent,
// VideoInputFeedBack
void OnDeviceChange() override;
+ // Creates a new DeviceInfo or returns an existing DeviceInfo for given
+ // capture engine. Returns a nullptr in case capture engine failed to be
+ // initialized. Video capture thread only.
+ std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo> GetDeviceInfo(
+ int aEngine);
VideoEngine* EnsureInitialized(int aEngine);
// Stops any ongoing capturing and releases resources. Called on
diff --git a/dom/media/systemservices/VideoEngine.cpp b/dom/media/systemservices/VideoEngine.cpp
index d03149e3ac..ec4657d755 100644
--- a/dom/media/systemservices/VideoEngine.cpp
+++ b/dom/media/systemservices/VideoEngine.cpp
@@ -112,7 +112,8 @@ int VideoEngine::ReleaseVideoCapture(const int32_t aId) {
}
std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo>
-VideoEngine::GetOrCreateVideoCaptureDeviceInfo() {
+VideoEngine::GetOrCreateVideoCaptureDeviceInfo(
+ webrtc::VideoInputFeedBack* callBack) {
LOG(("%s", __PRETTY_FUNCTION__));
webrtc::Timestamp currentTime = webrtc::Timestamp::Micros(0);
@@ -157,6 +158,10 @@ VideoEngine::GetOrCreateVideoCaptureDeviceInfo() {
mDeviceInfo =
mVideoCaptureFactory->CreateDeviceInfo(mId, mCaptureDevInfo.type);
+ if (mDeviceInfo && mCaptureDevInfo.type == CaptureDeviceType::Camera) {
+ mDeviceInfo->RegisterVideoInputFeedBack(callBack);
+ }
+
LOG(("EXIT %s", __PRETTY_FUNCTION__));
return mDeviceInfo;
}
diff --git a/dom/media/systemservices/VideoEngine.h b/dom/media/systemservices/VideoEngine.h
index 588be92c27..289a1ab181 100644
--- a/dom/media/systemservices/VideoEngine.h
+++ b/dom/media/systemservices/VideoEngine.h
@@ -88,7 +88,7 @@ class VideoEngine {
* @see bug 1305212 https://bugzilla.mozilla.org/show_bug.cgi?id=1305212
*/
std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo>
- GetOrCreateVideoCaptureDeviceInfo();
+ GetOrCreateVideoCaptureDeviceInfo(webrtc::VideoInputFeedBack* callBack);
/**
* Destroys existing DeviceInfo.

View File

@ -0,0 +1,36 @@
From 7dd135852be020d5755af42fa45470df259ba945 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Wed, 4 Sep 2024 13:43:40 +0000
Subject: [PATCH] Bug 1830275 - WebRTC backport: PipeWire camera: make member
variable with the PipeWire status updated r=pehrsons,webrtc-reviewers
We keep information about the PipeWire camera status as a member of the
PipeWire session, but it's never updated and remains in uninitialized
state. Make sure it gets updated once PipeWire is initialized or when it
fails. There is currently no use for this member variable, but there is
a plan to use it so I'm rather keeping it instead of removing it.
This is a simple backport of an WebRTC upstream change.
Upstream commit: 3881cb65cfcec90b6f0a56ce7223a471aa0115f2
Differential Revision: https://phabricator.services.mozilla.com/D220895
---
.../libwebrtc/modules/video_capture/linux/pipewire_session.cc | 2 ++
.../libwebrtc/moz-patch-stack/3881cb65cf.no-op-cherry-pick-msg | 1 +
2 files changed, 3 insertions(+)
create mode 100644 third_party/libwebrtc/moz-patch-stack/3881cb65cf.no-op-cherry-pick-msg
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
index dbac09274bb31..ac12d0437290e 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
@@ -415,6 +415,8 @@ void PipeWireSession::OnRegistryGlobalRemove(void* data, uint32_t id) {
}
void PipeWireSession::Finish(VideoCaptureOptions::Status status) {
+ status_ = status;
+
webrtc::MutexLock lock(&callback_lock_);
if (callback_) {

View File

@ -0,0 +1,190 @@
From a4eb4517f2bdeb6591c05a09109b4b543b83fef1 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Thu, 5 Sep 2024 16:04:48 +0000
Subject: [PATCH] Bug 1830275 - Add missing support for device change
notifications r=pehrsons,webrtc-reviewers
Registers each DeviceInfoPipeWire in PipeWireSession we use and calls
DeviceChange() for each once there is a new camera added or removed to
invoke OnDeviceChange() for every registered VideoInputFeedback.
Differential Revision: https://phabricator.services.mozilla.com/D219218
---
.../linux/device_info_pipewire.cc | 10 +++-
.../video_capture/linux/pipewire_session.cc | 47 ++++++++++++++++++-
.../video_capture/linux/pipewire_session.h | 26 +++++++++-
3 files changed, 79 insertions(+), 4 deletions(-)
diff --git a/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc b/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
index db2a3c7099..a0607b4aba 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/device_info_pipewire.cc
@@ -29,13 +29,19 @@
namespace webrtc {
namespace videocapturemodule {
DeviceInfoPipeWire::DeviceInfoPipeWire(VideoCaptureOptions* options)
- : DeviceInfoImpl(), pipewire_session_(options->pipewire_session()) {}
+ : DeviceInfoImpl(), pipewire_session_(options->pipewire_session()) {
+ const bool ret = pipewire_session_->RegisterDeviceInfo(this);
+ RTC_CHECK(ret);
+}
int32_t DeviceInfoPipeWire::Init() {
return 0;
}
-DeviceInfoPipeWire::~DeviceInfoPipeWire() = default;
+DeviceInfoPipeWire::~DeviceInfoPipeWire() {
+ const bool ret = pipewire_session_->DeRegisterDeviceInfo(this);
+ RTC_CHECK(ret);
+}
uint32_t DeviceInfoPipeWire::NumberOfDevices() {
RTC_CHECK(pipewire_session_);
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
index ac12d04372..0b78c16df2 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
@@ -9,6 +9,7 @@
*/
#include "modules/video_capture/linux/pipewire_session.h"
+#include "modules/video_capture/linux/device_info_pipewire.h"
#include <spa/monitor/device.h>
#include <spa/param/format-utils.h>
@@ -274,6 +275,28 @@ void PipeWireSession::InitPipeWire(int fd) {
Finish(VideoCaptureOptions::Status::ERROR);
}
+bool PipeWireSession::RegisterDeviceInfo(DeviceInfoPipeWire* device_info) {
+ RTC_CHECK(device_info);
+ MutexLock lock(&device_info_lock_);
+ auto it = std::find(device_info_list_.begin(), device_info_list_.end(), device_info);
+ if (it == device_info_list_.end()) {
+ device_info_list_.push_back(device_info);
+ return true;
+ }
+ return false;
+}
+
+bool PipeWireSession::DeRegisterDeviceInfo(DeviceInfoPipeWire* device_info) {
+ RTC_CHECK(device_info);
+ MutexLock lock(&device_info_lock_);
+ auto it = std::find(device_info_list_.begin(), device_info_list_.end(), device_info);
+ if (it != device_info_list_.end()) {
+ device_info_list_.erase(it);
+ return true;
+ }
+ return false;
+}
+
bool PipeWireSession::StartPipeWire(int fd) {
pw_init(/*argc=*/nullptr, /*argv=*/nullptr);
@@ -344,6 +367,21 @@ void PipeWireSession::PipeWireSync() {
sync_seq_ = pw_core_sync(pw_core_, PW_ID_CORE, sync_seq_);
}
+void PipeWireSession::NotifyDeviceChange() {
+ RTC_LOG(LS_INFO) << "Notify about device list changes";
+ MutexLock lock(&device_info_lock_);
+
+ // It makes sense to notify about device changes only once we are
+ // properly initialized.
+ if (status_ != VideoCaptureOptions::Status::SUCCESS) {
+ return;
+ }
+
+ for (auto* deviceInfo : device_info_list_) {
+ deviceInfo->DeviceChange();
+ }
+}
+
// static
void PipeWireSession::OnCoreError(void* data,
uint32_t id,
@@ -401,6 +439,8 @@ void PipeWireSession::OnRegistryGlobal(void* data,
that->nodes_.push_back(PipeWireNode::Create(that, id, props));
that->PipeWireSync();
+
+ that->NotifyDeviceChange();
}
// static
@@ -412,10 +452,15 @@ void PipeWireSession::OnRegistryGlobalRemove(void* data, uint32_t id) {
return node->id() == id;
});
that->nodes_.erase(it, that->nodes_.end());
+
+ that->NotifyDeviceChange();
}
void PipeWireSession::Finish(VideoCaptureOptions::Status status) {
- status_ = status;
+ {
+ MutexLock lock(&device_info_lock_);
+ status_ = status;
+ }
webrtc::MutexLock lock(&callback_lock_);
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
index 84273ea695..1f3a00614f 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.h
@@ -29,6 +29,7 @@
namespace webrtc {
namespace videocapturemodule {
+class DeviceInfoPipeWire;
class PipeWireSession;
class VideoCaptureModulePipeWire;
@@ -97,6 +98,21 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
void Init(VideoCaptureOptions::Callback* callback,
int fd = kInvalidPipeWireFd);
+
+ // [De]Register DeviceInfo for device change updates
+ // These methods will add or remove references to DeviceInfo
+ // objects that we want to notify about device changes.
+ // NOTE: We do not take ownership of these objects and
+ // they should never be released by us. All the instances
+ // of DeviceInfoPipeWire must outlive their registration.
+
+ // Returns true when DeviceInfo was successfuly registered
+ // or false otherwise, when it was already registered before.
+ bool RegisterDeviceInfo(DeviceInfoPipeWire* device_info);
+ // Returns true when DeviceInfo was successfuly unregistered
+ // or false otherwise, when it was not previously registered.
+ bool DeRegisterDeviceInfo(DeviceInfoPipeWire* device_info);
+
const std::deque<PipeWireNode::PipeWireNodePtr>& nodes() const {
return nodes_;
}
@@ -111,6 +127,8 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
void StopPipeWire();
void PipeWireSync();
+ void NotifyDeviceChange();
+
static void OnCoreError(void* data,
uint32_t id,
int seq,
@@ -133,7 +151,13 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
VideoCaptureOptions::Callback* callback_ RTC_GUARDED_BY(&callback_lock_) =
nullptr;
- VideoCaptureOptions::Status status_;
+ webrtc::Mutex device_info_lock_;
+ std::vector<DeviceInfoPipeWire*> device_info_list_
+ RTC_GUARDED_BY(device_info_lock_);
+ // Guard with device_info_lock, because currently it's the only place where
+ // we use this status information.
+ VideoCaptureOptions::Status status_
+ RTC_GUARDED_BY(device_info_lock_);
struct pw_thread_loop* pw_main_loop_ = nullptr;
struct pw_context* pw_context_ = nullptr;

View File

@ -0,0 +1,52 @@
From 9d035f728745f13311ed13d057565ca3b45523aa Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Tue, 24 Sep 2024 11:20:02 +0000
Subject: [PATCH] Bug 1920460 - WebRTC backport: PipeWire camera: get max FPS
for each format when specified as list r=pehrsons,webrtc-reviewers
In many cases, the framerate can be specified as list of possible values
and in that case, we would end up with max FPS to be set to 0 as this
case was not handled.
This is a simple backport of an WebRTC upstream change.
Upstream commit: 3aa47cfd30dc965446cf1405bb062b756a62e6d1
Differential Revision: https://phabricator.services.mozilla.com/D223112
---
.../modules/video_capture/linux/pipewire_session.cc | 12 ++++++++++--
.../moz-patch-stack/3aa47cfd30.no-op-cherry-pick-msg | 1 +
2 files changed, 11 insertions(+), 2 deletions(-)
create mode 100644 third_party/libwebrtc/moz-patch-stack/3aa47cfd30.no-op-cherry-pick-msg
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
index d9bc49d521b03..e5db278ff6a99 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
@@ -17,6 +17,8 @@
#include <spa/param/video/raw.h>
#include <spa/pod/parser.h>
+#include <algorithm>
+
#include "common_video/libyuv/include/webrtc_libyuv.h"
#include "modules/video_capture/device_info_impl.h"
#include "rtc_base/logging.h"
@@ -152,9 +154,15 @@ void PipeWireNode::OnNodeParam(void* data,
fract = static_cast<spa_fraction*>(SPA_POD_BODY(val));
- if (choice == SPA_CHOICE_None)
+ if (choice == SPA_CHOICE_None) {
cap.maxFPS = 1.0 * fract[0].num / fract[0].denom;
- else if (choice == SPA_CHOICE_Range && fract[1].num > 0)
+ } else if (choice == SPA_CHOICE_Enum) {
+ for (uint32_t i = 1; i < n_items; i++) {
+ cap.maxFPS = std::max(
+ static_cast<int32_t>(1.0 * fract[i].num / fract[i].denom),
+ cap.maxFPS);
+ }
+ } else if (choice == SPA_CHOICE_Range && fract[1].num > 0)
cap.maxFPS = 1.0 * fract[1].num / fract[1].denom;
}
}

View File

@ -0,0 +1,172 @@
From ca88b4994e140370ca5795c60f46559301458a98 Mon Sep 17 00:00:00 2001
From: Jan Grulich <jgrulich@redhat.com>
Date: Wed, 25 Sep 2024 06:52:35 +0000
Subject: [PATCH] Bug 1920472 - WebRTC backport: PipeWire camera: use exact
stream parameters specified by capability r=pehrsons,webrtc-reviewers
We currently specify stream parameters to be a range for both framerate
and resolution, where preferred value is specified. The preferred value
doesn't seem to be taken into account and we end up accepting resolution
from 1x1 to MAX_INTxMAX_INT. In case the other side tries to first match
with lower resolution than requested, we will happily match it and start
streaming low quality video. We should instead request the exact stream
parameters as specified by requested capability. This capability always
come from what has been originally reported as supported so it shouldn't
happen we don't find a matching stream. This also applies to requested
video format. We previously requested mjpg for streams with resolution
higher than 640x480, but it doesn't necessarily mean the camera supports
mjpg for the requested resolution. Again, refer to requested capability
in this case as it should indicate what is supported and we know we can
request exactly the same video format. It can happen that framerate is
set to 0 as unspecified. In that case keep using a range as before, but
with more sane values.
This is a simple backport of an WebRTC upstream change.
Upstream commit: 9703f8474f156e08e4a96dc36253f1cdccd549e1
Differential Revision: https://phabricator.services.mozilla.com/D223119
---
.../linux/video_capture_pipewire.cc | 85 +++++++++++--------
.../linux/video_capture_pipewire.h | 1 +
.../9703f8474f.no-op-cherry-pick-msg | 1 +
3 files changed, 52 insertions(+), 35 deletions(-)
create mode 100644 third_party/libwebrtc/moz-patch-stack/9703f8474f.no-op-cherry-pick-msg
diff --git a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
index 1672b7583f..2338fa6d87 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
@@ -51,10 +51,20 @@ VideoType VideoCaptureModulePipeWire::PipeWireRawFormatToVideoType(
if (spa_and_pixel_format.spa_format == spa_format)
return spa_and_pixel_format.video_type;
}
- RTC_LOG(LS_INFO) << "Unsupported pixel format: " << spa_format;
+ RTC_LOG(LS_WARNING) << "Unsupported pixel format: " << spa_format;
return VideoType::kUnknown;
}
+uint32_t VideoCaptureModulePipeWire::VideoTypeToPipeWireRawFormat(
+ VideoType type) {
+ for (const auto& spa_and_pixel_format : kSupportedFormats) {
+ if (spa_and_pixel_format.video_type == type)
+ return spa_and_pixel_format.spa_format;
+ }
+ RTC_LOG(LS_WARNING) << "Unsupported video type: " << static_cast<int>(type);
+ return SPA_VIDEO_FORMAT_UNKNOWN;
+}
+
VideoCaptureModulePipeWire::VideoCaptureModulePipeWire(
VideoCaptureOptions* options)
: VideoCaptureImpl(),
@@ -87,45 +97,53 @@ int32_t VideoCaptureModulePipeWire::Init(const char* deviceUniqueId) {
}
static spa_pod* BuildFormat(spa_pod_builder* builder,
- uint32_t format,
+ VideoType video_type,
uint32_t width,
uint32_t height,
float frame_rate) {
- spa_pod_frame frames[2];
+ spa_pod_frame frame;
+
+ const uint32_t media_subtype = video_type == VideoType::kMJPEG
+ ? SPA_MEDIA_SUBTYPE_mjpg
+ : SPA_MEDIA_SUBTYPE_raw;
- spa_pod_builder_push_object(builder, &frames[0], SPA_TYPE_OBJECT_Format,
+ spa_pod_builder_push_object(builder, &frame, SPA_TYPE_OBJECT_Format,
SPA_PARAM_EnumFormat);
spa_pod_builder_add(builder, SPA_FORMAT_mediaType,
SPA_POD_Id(SPA_MEDIA_TYPE_video), SPA_FORMAT_mediaSubtype,
- SPA_POD_Id(format), 0);
-
- if (format == SPA_MEDIA_SUBTYPE_raw) {
- spa_pod_builder_prop(builder, SPA_FORMAT_VIDEO_format, 0);
- spa_pod_builder_push_choice(builder, &frames[1], SPA_CHOICE_Enum, 0);
- spa_pod_builder_id(builder, kSupportedFormats[0].spa_format);
- for (const auto& spa_and_pixel_format : kSupportedFormats)
- spa_pod_builder_id(builder, spa_and_pixel_format.spa_format);
- spa_pod_builder_pop(builder, &frames[1]);
- }
+ SPA_POD_Id(media_subtype), 0);
- spa_rectangle preferred_size = spa_rectangle{width, height};
- spa_rectangle min_size = spa_rectangle{1, 1};
- spa_rectangle max_size = spa_rectangle{4096, 4096};
- spa_pod_builder_add(
- builder, SPA_FORMAT_VIDEO_size,
- SPA_POD_CHOICE_RANGE_Rectangle(&preferred_size, &min_size, &max_size), 0);
+ if (media_subtype == SPA_MEDIA_SUBTYPE_raw) {
+ const uint32_t format =
+ VideoCaptureModulePipeWire::VideoTypeToPipeWireRawFormat(video_type);
+ RTC_CHECK(format != SPA_VIDEO_FORMAT_UNKNOWN);
+ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(format),
+ 0);
+ }
- spa_fraction preferred_frame_rate =
- spa_fraction{static_cast<uint32_t>(frame_rate), 1};
- spa_fraction min_frame_rate = spa_fraction{0, 1};
- spa_fraction max_frame_rate = spa_fraction{INT32_MAX, 1};
- spa_pod_builder_add(
- builder, SPA_FORMAT_VIDEO_framerate,
- SPA_POD_CHOICE_RANGE_Fraction(&preferred_frame_rate, &min_frame_rate,
- &max_frame_rate),
- 0);
+ spa_rectangle resolution = spa_rectangle{width, height};
+ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size,
+ SPA_POD_Rectangle(&resolution), 0);
+
+ // Framerate can be also set to 0 to be unspecified
+ if (frame_rate) {
+ spa_fraction framerate = spa_fraction{static_cast<uint32_t>(frame_rate), 1};
+ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_framerate,
+ SPA_POD_Fraction(&framerate), 0);
+ } else {
+ // Default to some reasonable values
+ spa_fraction preferred_frame_rate =
+ spa_fraction{static_cast<uint32_t>(30), 1};
+ spa_fraction min_frame_rate = spa_fraction{1, 1};
+ spa_fraction max_frame_rate = spa_fraction{30, 1};
+ spa_pod_builder_add(
+ builder, SPA_FORMAT_VIDEO_framerate,
+ SPA_POD_CHOICE_RANGE_Fraction(&preferred_frame_rate, &min_frame_rate,
+ &max_frame_rate),
+ 0);
+ }
- return static_cast<spa_pod*>(spa_pod_builder_pop(builder, &frames[0]));
+ return static_cast<spa_pod*>(spa_pod_builder_pop(builder, &frame));
}
int32_t VideoCaptureModulePipeWire::StartCapture(
@@ -176,13 +194,10 @@ int32_t VideoCaptureModulePipeWire::StartCapture(
uint32_t width = capability.width;
uint32_t height = capability.height;
uint32_t frame_rate = capability.maxFPS;
- bool prefer_jpeg = (width > 640) || (height > 480);
+ VideoType video_type = capability.videoType;
params.push_back(
- BuildFormat(&builder, SPA_MEDIA_SUBTYPE_raw, width, height, frame_rate));
- params.insert(
- prefer_jpeg ? params.begin() : params.end(),
- BuildFormat(&builder, SPA_MEDIA_SUBTYPE_mjpg, width, height, frame_rate));
+ BuildFormat(&builder, video_type, width, height, frame_rate));
int res = pw_stream_connect(
stream_, PW_DIRECTION_INPUT, node_id_,
diff --git a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.h b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.h
index eeb3b9497c..789f2034d3 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.h
+++ b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.h
@@ -28,6 +28,7 @@ class VideoCaptureModulePipeWire : public VideoCaptureImpl {
int32_t CaptureSettings(VideoCaptureCapability& settings) override;
static VideoType PipeWireRawFormatToVideoType(uint32_t format);
+ static uint32_t VideoTypeToPipeWireRawFormat(VideoType type);
private:
static void OnStreamParamChanged(void* data,

View File

@ -0,0 +1,61 @@
From 12b7d28d858fdcfa80795a2af49a71d3b5142733 Mon Sep 17 00:00:00 2001
From: Jan Grulich <grulja@gmail.com>
Date: Tue, 12 Nov 2024 12:28:19 +0000
Subject: [PATCH] Bug 1930598 - WebRTC backport: PipeWire camera: use better
unique device name for camera devices r=pehrsons,webrtc-reviewers
Originally we used node id from PipeWire as an unique device name and
while this works, it will change everytime PipeWire is restarted. This
has an impact on default camera selection, where for example Firefox can
automatically request a camera device that was used before, but this can
break with the next PipeWire restart.
This is a simple backport of an WebRTC upstream change.
Upstream commit: a5d71009ac1dce7da23813dc9413c03073cfa8ca
Differential Revision: https://phabricator.services.mozilla.com/D228635
---
.../modules/video_capture/linux/pipewire_session.cc | 2 +-
.../video_capture/linux/video_capture_pipewire.cc | 11 +++++++----
.../moz-patch-stack/a5d71009ac.no-op-cherry-pick-msg | 1 +
3 files changed, 9 insertions(+), 5 deletions(-)
create mode 100644 third_party/libwebrtc/moz-patch-stack/a5d71009ac.no-op-cherry-pick-msg
diff --git a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
index 641e5238ea..dd187c0358 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/pipewire_session.cc
@@ -74,7 +74,7 @@ PipeWireNode::PipeWireNode(PipeWireSession* session,
: session_(session),
id_(id),
display_name_(spa_dict_lookup(props, PW_KEY_NODE_DESCRIPTION)),
- unique_id_(rtc::ToString(id)) {
+ unique_id_(spa_dict_lookup(props, PW_KEY_NODE_NAME)) {
RTC_LOG(LS_VERBOSE) << "Found Camera: " << display_name_;
proxy_ = static_cast<pw_proxy*>(pw_registry_bind(
diff --git a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
index 2338fa6d87..888b8f386f 100644
--- a/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
+++ b/third_party/libwebrtc/modules/video_capture/linux/video_capture_pipewire.cc
@@ -82,12 +82,15 @@ int32_t VideoCaptureModulePipeWire::Init(const char* deviceUniqueId) {
RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
RTC_DCHECK_RUN_ON(&api_checker_);
- absl::optional<int> id;
- id = rtc::StringToNumber<int>(deviceUniqueId);
- if (id == absl::nullopt)
+ auto node =
+ std::find_if(session_->nodes_.begin(), session_->nodes_.end(),
+ [deviceUniqueId](const PipeWireNode::PipeWireNodePtr& node) {
+ return node->unique_id() == deviceUniqueId;
+ });
+ if (node == session_->nodes_.end())
return -1;
- node_id_ = id.value();
+ node_id_ = (*node)->id();
const int len = strlen(deviceUniqueId);
_deviceUniqueId = new (std::nothrow) char[len + 1];

File diff suppressed because one or more lines are too long

View File

@ -51,6 +51,12 @@ end}
%global rhel_minor_version %{lua:print(dist_to_rhel_minor(rpm.expand("%dist")))}
%if 0%{?rhel} == 10
%global use_pipewire_camera 1
%else
%global use_pipewire_camera 0
%endif
# System libraries options
%global system_nss 1
%global bundle_nss 0
@ -138,7 +144,7 @@ end}
Summary: Mozilla Firefox Web browser
Name: firefox
Version: 128.4.0
Release: 1%{?dist}
Release: 2%{?dist}
URL: https://www.mozilla.org/firefox/
License: MPLv1.1 or GPLv2+ or LGPLv2+
@ -209,6 +215,7 @@ Patch08: disable-pipewire.patch
Patch09: rhbz-2131158-webrtc-nss-fix.patch
Patch10: build-ffvpx.patch
Patch11: build-disable-gamepad.patch
Patch12: firefox-system-nss-replace-xyber-with-mlkem.patch
# -- Upstreamed patches --
Patch51: mozilla-bmo1170092.patch
@ -241,6 +248,28 @@ Patch200: webrtc-128.0.patch.patch
Patch201: D224587.1728128070.diff
Patch202: D224588.1728128098.diff
# --- Upstream PipeWire camera and screencast fixes ----
# https://phabricator.services.mozilla.com/D215197
Patch250: 001-libwebrtc-pipewire-screencast-hide-cursor-when-goes-off-screen-or-is-invisible.patch
# https://phabricator.services.mozilla.com/D216138
Patch251: 002-libwebrtc-pipewire-camera-support-additional-formats-and-fix-rgb-bgr-mapping.patch
# https://phabricator.services.mozilla.com/D219224
Patch252: 003-libwebrtc-pipewire-camera-filter-out-devices-without-capabilities.patch
# https://phabricator.services.mozilla.com/D219062
Patch253: 004-firefox-always-query-information-about-camera-availability.patch
# https://phabricator.services.mozilla.com/D219060
Patch254: 005-firefox-always-register-video-input-feedback-for-newly-created-deviceinfo.patch
# https://phabricator.services.mozilla.com/D220895
Patch255: 006-libwebrtc-pipewire-camera-make-member-variable-with-pipewire-status-updated.patch
# https://phabricator.services.mozilla.com/D219218
Patch256: 007-firefox-add-missing-support-for-device-change-notifications.patch
# https://phabricator.services.mozilla.com/D223112
Patch257: 008-libwebrtc-pipewire-camera-get-max-fps-for-each-format-when-specified-as-list.patch
# https://phabricator.services.mozilla.com/D223119
Patch258: 009-libwebrtc-pipewire-camera-use-exact-stream-parameters-specified-by-capability.patch
# https://phabricator.services.mozilla.com/D228635
Patch259: 010-libwebrtc-pipewire-camera-use-better-unique-device-name-for-camera-devices.patch
# ---- Test patches ----
# Generate without context by
@ -1151,6 +1180,7 @@ echo "--------------------------------------------"
%endif
%patch -P9 -p1 -b .rhbz-2131158-webrtc-nss-fix
%patch -P10 -p1 -b .build-ffvpx
%patch -P12 -p1 -b .system-nss-replace-xyber-with-mlkem
# -- Upstreamed patches --
%patch -P51 -p1 -b .mozilla-bmo1170092
@ -1183,6 +1213,17 @@ echo "--------------------------------------------"
%patch -P202 -p1 -b .D224588
%endif
# --- Upstream PipeWire camera and screencast fixes ----
%patch -P250 -p1 -b .pipewire-screencast-hide-cursor-when-goes-off-screen-or-is-invisible
%patch -P251 -p1 -b .pipewire-camera-support-additional-formats-and-fix-rgb-bgr-mapping
%patch -P252 -p1 -b .pipewire-camera-filter-out-devices-without-capabilities
%patch -P253 -p1 -b .always-query-information-about-camera-availability
%patch -P254 -p1 -b .always-register-video-input-feedback-for-newly-created-deviceinfo
%patch -P255 -p1 -b .pipewire-camera-make-member-variable-with-pipewire-status-updated
%patch -P256 -p1 -b .add-missing-support-for-device-change-notifications
%patch -P257 -p1 -b .pipewire-camera-get-max-fps-for-each-format-when-specified-as-list
%patch -P258 -p1 -b .pipewire-camera-use-exact-stream-parameters-specified-by-capability
%patch -P259 -p1 -b .pipewire-camera-use-better-unique-device-name-for-camera-devices
# ---- Security patches ----
@ -1730,6 +1771,11 @@ ln -s %{_datadir}/myspell %{buildroot}%{mozappdir}/dictionaries
%{__cp} failures-* %{buildroot}/%{version}-%{release}/ || true
%endif
%if %{?use_pipewire_camera}
echo 'pref("media.webrtc.camera.allow-pipewire", true);' >> %{buildroot}%{mozappdir}/defaults/preferences/all-redhat.js
%endif
# Add distribution.ini
%{__mkdir_p} %{buildroot}%{mozappdir}/distribution
%{__sed} -e "s/__NAME__/%(source /etc/os-release; echo ${NAME})/g" \
@ -1871,6 +1917,11 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
#---------------------------------------------------------------------
%changelog
* Mon Nov 25 2024 Jan Grulich <jgrulich@redhat.com - 128.4.0-2
- Enable PipeWire camera support for RHEL 10
+ backport upstream fixes for PipeWire camera support
Resolves: RHEL-64749
* Tue Oct 22 2024 Eike Rathke <erack@redhat.com> - 128.4.0-1
- Update to 128.4.0 build1