firefox/003-libwebrtc-pipewire-camera-filter-out-devices-without-capabilities.patch
Jan Grulich 85157a42c7 Enable PipeWire camera support for RHEL 10
Also backport upstream fixes for PipeWire camera support.

Resolves: RHEL-64749
2024-11-28 12:50:27 +01:00

232 lines
9.6 KiB
Diff

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_;
};