From 286575b387cff9b3ec318d3cf90cf20d2f3c2ce4 Mon Sep 17 00:00:00 2001 From: Jan Grulich 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( 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(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(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; + 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 { void Init(VideoCaptureOptions::Callback* callback, int fd = kInvalidPipeWireFd); - - const std::deque& nodes() const { return nodes_; } + const std::deque& nodes() const { + return nodes_; + } friend class CameraPortalNotifier; friend class PipeWireNode; @@ -134,7 +145,7 @@ class PipeWireSession : public rtc::RefCountedNonVirtual { int sync_seq_ = 0; - std::deque nodes_; + std::deque nodes_; std::unique_ptr portal_; std::unique_ptr portal_notifier_; };