PipeWire camera: filter out devices with no capabilities
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. Bug: webrtc:42225999 Change-Id: Ic2905bc66b55c3f48b49ff4097167f10d17ad656 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/358864 Commit-Queue: Jan Grulich <grulja@gmail.com> Reviewed-by: Andreas Pehrson <apehrson@mozilla.com> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42785}
This commit is contained in:
parent
db561d4174
commit
b4aba7834e
@ -55,31 +55,31 @@ int32_t DeviceInfoPipeWire::GetDeviceName(uint32_t deviceNumber,
|
|||||||
if (deviceNumber >= NumberOfDevices())
|
if (deviceNumber >= NumberOfDevices())
|
||||||
return -1;
|
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";
|
RTC_LOG(LS_INFO) << "deviceNameUTF8 buffer passed is too small";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (deviceUniqueIdUTF8Length <= node.unique_id().length()) {
|
if (deviceUniqueIdUTF8Length <= node->unique_id().length()) {
|
||||||
RTC_LOG(LS_INFO) << "deviceUniqueIdUTF8 buffer passed is too small";
|
RTC_LOG(LS_INFO) << "deviceUniqueIdUTF8 buffer passed is too small";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (productUniqueIdUTF8 &&
|
if (productUniqueIdUTF8 &&
|
||||||
productUniqueIdUTF8Length <= node.model_id().length()) {
|
productUniqueIdUTF8Length <= node->model_id().length()) {
|
||||||
RTC_LOG(LS_INFO) << "productUniqueIdUTF8 buffer passed is too small";
|
RTC_LOG(LS_INFO) << "productUniqueIdUTF8 buffer passed is too small";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(deviceNameUTF8, 0, deviceNameLength);
|
memset(deviceNameUTF8, 0, deviceNameLength);
|
||||||
node.display_name().copy(deviceNameUTF8, deviceNameLength);
|
node->display_name().copy(deviceNameUTF8, deviceNameLength);
|
||||||
|
|
||||||
memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
|
memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
|
||||||
node.unique_id().copy(deviceUniqueIdUTF8, deviceUniqueIdUTF8Length);
|
node->unique_id().copy(deviceUniqueIdUTF8, deviceUniqueIdUTF8Length);
|
||||||
|
|
||||||
if (productUniqueIdUTF8) {
|
if (productUniqueIdUTF8) {
|
||||||
memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
|
memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
|
||||||
node.model_id().copy(productUniqueIdUTF8, productUniqueIdUTF8Length);
|
node->model_id().copy(productUniqueIdUTF8, productUniqueIdUTF8Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -90,11 +90,11 @@ int32_t DeviceInfoPipeWire::CreateCapabilityMap(
|
|||||||
RTC_CHECK(pipewire_session_);
|
RTC_CHECK(pipewire_session_);
|
||||||
|
|
||||||
for (auto& node : pipewire_session_->nodes()) {
|
for (auto& node : pipewire_session_->nodes()) {
|
||||||
if (node.unique_id().compare(deviceUniqueIdUTF8) != 0)
|
if (node->unique_id().compare(deviceUniqueIdUTF8) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_captureCapabilities = node.capabilities();
|
_captureCapabilities = node->capabilities();
|
||||||
_lastUsedDeviceNameLength = node.unique_id().length();
|
_lastUsedDeviceNameLength = node->unique_id().length();
|
||||||
_lastUsedDeviceName = static_cast<char*>(
|
_lastUsedDeviceName = static_cast<char*>(
|
||||||
realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
|
realloc(_lastUsedDeviceName, _lastUsedDeviceNameLength + 1));
|
||||||
memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8,
|
memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8,
|
||||||
|
|||||||
@ -53,6 +53,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));
|
||||||
|
}
|
||||||
|
|
||||||
RTC_NO_SANITIZE("cfi-icall")
|
RTC_NO_SANITIZE("cfi-icall")
|
||||||
PipeWireNode::PipeWireNode(PipeWireSession* session,
|
PipeWireNode::PipeWireNode(PipeWireSession* session,
|
||||||
uint32_t id,
|
uint32_t id,
|
||||||
@ -75,11 +88,6 @@ PipeWireNode::PipeWireNode(PipeWireSession* session,
|
|||||||
pw_node_add_listener(proxy_, &node_listener_, &node_events, this);
|
pw_node_add_listener(proxy_, &node_listener_, &node_events, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PipeWireNode::~PipeWireNode() {
|
|
||||||
pw_proxy_destroy(proxy_);
|
|
||||||
spa_hook_remove(&node_listener_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
RTC_NO_SANITIZE("cfi-icall")
|
RTC_NO_SANITIZE("cfi-icall")
|
||||||
void PipeWireNode::OnNodeInfo(void* data, const pw_node_info* info) {
|
void PipeWireNode::OnNodeInfo(void* data, const pw_node_info* info) {
|
||||||
@ -102,7 +110,9 @@ void PipeWireNode::OnNodeInfo(void* data, const pw_node_info* info) {
|
|||||||
pid.value());
|
pid.value());
|
||||||
that->model_id_ = model_str;
|
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++) {
|
for (uint32_t i = 0; i < info->n_params; i++) {
|
||||||
uint32_t id = info->params[i].id;
|
uint32_t id = info->params[i].id;
|
||||||
if (id == SPA_PARAM_EnumFormat &&
|
if (id == SPA_PARAM_EnumFormat &&
|
||||||
@ -356,6 +366,14 @@ void PipeWireSession::OnCoreDone(void* data, uint32_t id, int seq) {
|
|||||||
if (id == PW_ID_CORE) {
|
if (id == PW_ID_CORE) {
|
||||||
if (seq == that->sync_seq_) {
|
if (seq == that->sync_seq_) {
|
||||||
RTC_LOG(LS_VERBOSE) << "Enumerating PipeWire camera devices complete.";
|
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);
|
that->Finish(VideoCaptureOptions::Status::SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,8 +391,8 @@ void PipeWireSession::OnRegistryGlobal(void* data,
|
|||||||
|
|
||||||
// Skip already added nodes to avoid duplicate camera entries
|
// Skip already added nodes to avoid duplicate camera entries
|
||||||
if (std::find_if(that->nodes_.begin(), that->nodes_.end(),
|
if (std::find_if(that->nodes_.begin(), that->nodes_.end(),
|
||||||
[id](const PipeWireNode& node) {
|
[id](const PipeWireNode::PipeWireNodePtr& node) {
|
||||||
return node.id() == id;
|
return node->id() == id;
|
||||||
}) != that->nodes_.end())
|
}) != that->nodes_.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -388,7 +406,7 @@ void PipeWireSession::OnRegistryGlobal(void* data,
|
|||||||
if (!node_role || strcmp(node_role, "Camera"))
|
if (!node_role || strcmp(node_role, "Camera"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
that->nodes_.emplace_back(that, id, props);
|
that->nodes_.push_back(PipeWireNode::Create(that, id, props));
|
||||||
that->PipeWireSync();
|
that->PipeWireSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,9 +414,10 @@ void PipeWireSession::OnRegistryGlobal(void* data,
|
|||||||
void PipeWireSession::OnRegistryGlobalRemove(void* data, uint32_t id) {
|
void PipeWireSession::OnRegistryGlobalRemove(void* data, uint32_t id) {
|
||||||
PipeWireSession* that = static_cast<PipeWireSession*>(data);
|
PipeWireSession* that = static_cast<PipeWireSession*>(data);
|
||||||
|
|
||||||
auto it = std::remove_if(
|
auto it = std::remove_if(that->nodes_.begin(), that->nodes_.end(),
|
||||||
that->nodes_.begin(), that->nodes_.end(),
|
[id](const PipeWireNode::PipeWireNodePtr& node) {
|
||||||
[id](const PipeWireNode& node) { return node.id() == id; });
|
return node->id() == id;
|
||||||
|
});
|
||||||
that->nodes_.erase(it, that->nodes_.end());
|
that->nodes_.erase(it, that->nodes_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,8 +37,15 @@ class VideoCaptureModulePipeWire;
|
|||||||
// So they all represent one camera that is available via PipeWire.
|
// So they all represent one camera that is available via PipeWire.
|
||||||
class PipeWireNode {
|
class PipeWireNode {
|
||||||
public:
|
public:
|
||||||
PipeWireNode(PipeWireSession* session, uint32_t id, const spa_dict* props);
|
struct PipeWireNodeDeleter {
|
||||||
~PipeWireNode();
|
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_; }
|
uint32_t id() const { return id_; }
|
||||||
std::string display_name() const { return display_name_; }
|
std::string display_name() const { return display_name_; }
|
||||||
@ -48,6 +55,9 @@ class PipeWireNode {
|
|||||||
return capabilities_;
|
return capabilities_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PipeWireNode(PipeWireSession* session, uint32_t id, const spa_dict* props);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void OnNodeInfo(void* data, const pw_node_info* info);
|
static void OnNodeInfo(void* data, const pw_node_info* info);
|
||||||
static void OnNodeParam(void* data,
|
static void OnNodeParam(void* data,
|
||||||
@ -87,8 +97,9 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
|
|||||||
|
|
||||||
void Init(VideoCaptureOptions::Callback* callback,
|
void Init(VideoCaptureOptions::Callback* callback,
|
||||||
int fd = kInvalidPipeWireFd);
|
int fd = kInvalidPipeWireFd);
|
||||||
|
const std::deque<PipeWireNode::PipeWireNodePtr>& nodes() const {
|
||||||
const std::deque<PipeWireNode>& nodes() const { return nodes_; }
|
return nodes_;
|
||||||
|
}
|
||||||
|
|
||||||
friend class CameraPortalNotifier;
|
friend class CameraPortalNotifier;
|
||||||
friend class PipeWireNode;
|
friend class PipeWireNode;
|
||||||
@ -134,7 +145,7 @@ class PipeWireSession : public rtc::RefCountedNonVirtual<PipeWireSession> {
|
|||||||
|
|
||||||
int sync_seq_ = 0;
|
int sync_seq_ = 0;
|
||||||
|
|
||||||
std::deque<PipeWireNode> nodes_;
|
std::deque<PipeWireNode::PipeWireNodePtr> nodes_;
|
||||||
std::unique_ptr<CameraPortal> portal_;
|
std::unique_ptr<CameraPortal> portal_;
|
||||||
std::unique_ptr<CameraPortalNotifier> portal_notifier_;
|
std::unique_ptr<CameraPortalNotifier> portal_notifier_;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user