scripts: add libcamera monitor
This commit is contained in:
10
src/config/main.lua.d/30-libcamera-monitor.lua
Normal file
10
src/config/main.lua.d/30-libcamera-monitor.lua
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
libcamera_monitor = {}
|
||||||
|
libcamera_monitor.properties = {}
|
||||||
|
libcamera_monitor.rules = {}
|
||||||
|
|
||||||
|
function libcamera_monitor.enable()
|
||||||
|
load_monitor("libcamera", {
|
||||||
|
properties = libcamera_monitor.properties,
|
||||||
|
rules = libcamera_monitor.rules,
|
||||||
|
})
|
||||||
|
end
|
37
src/config/main.lua.d/50-libcamera-config.lua
Normal file
37
src/config/main.lua.d/50-libcamera-config.lua
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
libcamera_monitor.rules = {
|
||||||
|
-- An array of matches/actions to evaluate.
|
||||||
|
{
|
||||||
|
-- Rules for matching a device or node. It is an array of
|
||||||
|
-- properties that all need to match the regexp. If any of the
|
||||||
|
-- matches work, the actions are executed for the object.
|
||||||
|
matches = {
|
||||||
|
{
|
||||||
|
-- This matches all cards.
|
||||||
|
{ "device.name", "matches", "libcamera_device.*" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
-- Apply properties on the matched object.
|
||||||
|
apply_properties = {
|
||||||
|
-- ["device.nick"] = "My Device",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
matches = {
|
||||||
|
{
|
||||||
|
-- Matches all sources.
|
||||||
|
{ "node.name", "matches", "libcamera_input.*" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
-- Matches all sinks.
|
||||||
|
{ "node.name", "matches", "libcamera_output.*" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
apply_properties = {
|
||||||
|
--["node.nick"] = "My Node",
|
||||||
|
--["priority.driver"] = 100,
|
||||||
|
--["priority.session"] = 100,
|
||||||
|
--["node.pause-on-idle"] = false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
139
src/scripts/monitors/libcamera.lua
Normal file
139
src/scripts/monitors/libcamera.lua
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
-- WirePlumber
|
||||||
|
--
|
||||||
|
-- Copyright © 2021 Collabora Ltd.
|
||||||
|
-- @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||||
|
--
|
||||||
|
-- SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
local config = ... or {}
|
||||||
|
|
||||||
|
-- preprocess rules and create Interest objects
|
||||||
|
for _, r in ipairs(config.rules or {}) do
|
||||||
|
r.interests = {}
|
||||||
|
for _, i in ipairs(r.matches) do
|
||||||
|
local interest_desc = { type = "properties" }
|
||||||
|
for _, c in ipairs(i) do
|
||||||
|
c.type = "pw"
|
||||||
|
table.insert(interest_desc, Constraint(c))
|
||||||
|
end
|
||||||
|
local interest = Interest(interest_desc)
|
||||||
|
table.insert(r.interests, interest)
|
||||||
|
end
|
||||||
|
r.matches = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- applies properties from config.rules when asked to
|
||||||
|
function rulesApplyProperties(properties)
|
||||||
|
for _, r in ipairs(config.rules or {}) do
|
||||||
|
if r.apply_properties then
|
||||||
|
for _, interest in ipairs(r.interests) do
|
||||||
|
if interest:matches(properties) then
|
||||||
|
for k, v in pairs(r.apply_properties) do
|
||||||
|
properties[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function findDuplicate(parent, id, property, value)
|
||||||
|
for i = 0, id - 1, 1 do
|
||||||
|
local obj = parent:get_managed_object(i)
|
||||||
|
if obj and obj.properties[property] == value then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function createNode(parent, id, type, factory, properties)
|
||||||
|
local dev_props = parent.properties
|
||||||
|
|
||||||
|
-- set the device id and spa factory name; REQUIRED, do not change
|
||||||
|
properties["device.id"] = parent["bound-id"]
|
||||||
|
properties["factory.name"] = factory
|
||||||
|
|
||||||
|
-- set the default pause-on-idle setting
|
||||||
|
properties["node.pause-on-idle"] = false
|
||||||
|
|
||||||
|
-- set the node name
|
||||||
|
local name =
|
||||||
|
(factory:find("sink") and "libcamera_output") or
|
||||||
|
(factory:find("source") and "libcamera_input" or factory)
|
||||||
|
.. "." ..
|
||||||
|
(dev_props["device.name"]:gsub("^libcamera_device%.(.+)", "%1") or
|
||||||
|
dev_props["device.name"] or
|
||||||
|
dev_props["device.nick"] or
|
||||||
|
dev_props["device.alias"] or
|
||||||
|
"libcamera-device")
|
||||||
|
-- sanitize name
|
||||||
|
name = name:gsub("([^%w_%-%.])", "_")
|
||||||
|
|
||||||
|
properties["node.name"] = name
|
||||||
|
|
||||||
|
-- deduplicate nodes with the same name
|
||||||
|
for counter = 2, 99, 1 do
|
||||||
|
if findDuplicate(parent, id, "node.name", properties["node.name"]) then
|
||||||
|
properties["node.name"] = name .. "." .. counter
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set the node description
|
||||||
|
local desc = dev_props["device.description"] or "libcamera-device"
|
||||||
|
-- sanitize description, replace ':' with ' '
|
||||||
|
properties["node.description"] = desc:gsub("(:)", " ")
|
||||||
|
|
||||||
|
-- apply properties from config.rules
|
||||||
|
rulesApplyProperties(properties)
|
||||||
|
|
||||||
|
-- create the node
|
||||||
|
local node = Node("spa-node-factory", properties)
|
||||||
|
node:activate(Feature.Proxy.BOUND)
|
||||||
|
parent:store_managed_object(id, node)
|
||||||
|
end
|
||||||
|
|
||||||
|
function createDevice(parent, id, type, factory, properties)
|
||||||
|
-- ensure the device has an appropriate name
|
||||||
|
local name = "libcamera_device." ..
|
||||||
|
(properties["device.name"] or
|
||||||
|
properties["device.bus-id"] or
|
||||||
|
properties["device.bus-path"] or
|
||||||
|
tostring(id)):gsub("([^%w_%-%.])", "_")
|
||||||
|
|
||||||
|
properties["device.name"] = name
|
||||||
|
|
||||||
|
-- deduplicate devices with the same name
|
||||||
|
for counter = 2, 99, 1 do
|
||||||
|
if findDuplicate(parent, id, "device.name", properties["device.name"]) then
|
||||||
|
properties["device.name"] = name .. "." .. counter
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ensure the device has a description
|
||||||
|
properties["device.description"] =
|
||||||
|
properties["device.description"]
|
||||||
|
or properties["device.product.name"]
|
||||||
|
or "Unknown device"
|
||||||
|
|
||||||
|
-- apply properties from config.rules
|
||||||
|
rulesApplyProperties(properties)
|
||||||
|
|
||||||
|
-- create the device
|
||||||
|
local device = SpaDevice(factory, properties)
|
||||||
|
device:connect("create-object", createNode)
|
||||||
|
device:activate(Feature.SpaDevice.ENABLED | Feature.Proxy.BOUND)
|
||||||
|
parent:store_managed_object(id, device)
|
||||||
|
end
|
||||||
|
|
||||||
|
monitor = SpaDevice("api.libcamera.enum.client", config.properties or {})
|
||||||
|
if monitor then
|
||||||
|
monitor:connect("create-object", createDevice)
|
||||||
|
monitor:activate(Feature.SpaDevice.ENABLED)
|
||||||
|
else
|
||||||
|
Log.message("PipeWire's libcamera SPA missing or broken. libcamera not supported.")
|
||||||
|
end
|
Reference in New Issue
Block a user