monitors/camera: fix camera device deduplication not working for certain devices.
Enhance the parsing logic to consider more than one device number. libcamera devices some times use up multiple V4L2 devices, in this case libcamera should be given a chance to enumerate the device. Fixes #623
This commit is contained in:

committed by
George Kiagiadakis

parent
ae983e6fd7
commit
06e11dc4be
@@ -25,36 +25,92 @@ function mutils.find_duplicate (parent, id, property, value)
|
||||
return false
|
||||
end
|
||||
|
||||
function mutils.get_cam_data (self, dev_string)
|
||||
local dev_num = tonumber (dev_string)
|
||||
if not dev_num then
|
||||
return
|
||||
function get_cam_data(self, dev_id)
|
||||
if not self.cam_data[dev_id] then
|
||||
self.cam_data[dev_id] = {}
|
||||
self.cam_data[dev_id]["libcamera"] = {}
|
||||
self.cam_data[dev_id]["v4l2"] = {}
|
||||
end
|
||||
|
||||
if not self.cam_data[dev_num] then
|
||||
self.cam_data[dev_num] = {}
|
||||
self.cam_data[dev_num]["libcamera"] = {}
|
||||
self.cam_data[dev_num]["v4l2"] = {}
|
||||
end
|
||||
|
||||
return self.cam_data[dev_num], dev_num
|
||||
return self.cam_data[dev_id]
|
||||
end
|
||||
|
||||
function mutils.clear_cam_data (self, dev_string)
|
||||
local dev_num = tonumber (dev_string)
|
||||
function parse_devids_get_cam_data(self, devids)
|
||||
local dev_ids_json = Json.Raw(devids)
|
||||
local dev_ids_table = {}
|
||||
|
||||
if dev_ids_json:is_array() then
|
||||
dev_ids_table = dev_ids_json:parse()
|
||||
else
|
||||
-- to maintain the backward compatibility with earlier pipewire versions.
|
||||
for dev_id_str in devids:gmatch("%S+") do
|
||||
local dev_id = tonumber(dev_id_str)
|
||||
if dev_id then
|
||||
table.insert(dev_ids_table, dev_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local dev_num = nil
|
||||
-- `device.devids` is a json array of device numbers
|
||||
for _, dev_id_str in ipairs(dev_ids_table) do
|
||||
local dev_id = tonumber(dev_id_str)
|
||||
if not dev_id then
|
||||
log:notice ("invalid device number")
|
||||
return
|
||||
end
|
||||
|
||||
log:debug ("Working on device " .. dev_id)
|
||||
local dev_cam_data = get_cam_data (self, dev_id)
|
||||
if not dev_num then
|
||||
dev_num = dev_id
|
||||
if #dev_ids_table > 1 then
|
||||
-- libcam node can some times use more tha one V4L2 devices, in this
|
||||
-- case, return the first device id and mark rest of the them as peers
|
||||
-- to the first one.
|
||||
log:debug ("Device " .. dev_id .. " uses multi V4L2 devices")
|
||||
dev_cam_data.uses_multi_v4l2_devices = true
|
||||
end
|
||||
else
|
||||
log:debug ("Device " .. dev_id .. " is peer to " .. dev_num)
|
||||
dev_cam_data.peer_id = dev_num
|
||||
end
|
||||
end
|
||||
|
||||
if dev_num then
|
||||
return self.cam_data[dev_num], dev_num
|
||||
end
|
||||
end
|
||||
|
||||
function mutils.clear_cam_data (self, dev_num)
|
||||
local dev_cam_data = self.cam_data[dev_num]
|
||||
if not dev_num then
|
||||
return
|
||||
end
|
||||
|
||||
if dev_cam_data.uses_multi_v4l2_devices then
|
||||
for dev_id, cam_data_ in pairs(self.cam_data) do
|
||||
if cam_data_.peer_id == dev_num then
|
||||
log:debug("clear " .. dev_id .. " it is peer to " .. dev_num)
|
||||
self.cam_data[dev_id] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.cam_data[dev_num] = nil
|
||||
end
|
||||
|
||||
function mutils.create_cam_node (self, dev_num)
|
||||
function mutils.create_cam_node(self, dev_num)
|
||||
local api = nil
|
||||
local cam_data = self:get_cam_data (dev_num)
|
||||
local cam_data = get_cam_data (self, dev_num)
|
||||
|
||||
if cam_data["v4l2"].enum_status and cam_data["libcamera"].enum_status then
|
||||
if cam_data.is_device_uvc then
|
||||
if cam_data.uses_multi_v4l2_devices then
|
||||
api = "libcamera"
|
||||
elseif cam_data.peer_id ~= nil then
|
||||
-- no need to create node for peer
|
||||
log:notice ("timer expired for peer device " .. dev_num)
|
||||
return
|
||||
elseif cam_data.is_device_uvc then
|
||||
api = "v4l2"
|
||||
else
|
||||
api = "libcamera"
|
||||
@@ -63,8 +119,8 @@ function mutils.create_cam_node (self, dev_num)
|
||||
api = cam_data["v4l2"].enum_status and "v4l2" or "libcamera"
|
||||
end
|
||||
|
||||
log:info (string.format ("create \"%s\" node for device:%s%s", api,
|
||||
cam_data.dev_path, (cam_data.is_device_uvc and "(uvc)" or "")))
|
||||
log:info (string.format ("create \"%s\" node for device:%s", api,
|
||||
cam_data.dev_path))
|
||||
|
||||
source = source or Plugin.find ("standard-event-source")
|
||||
local e = source:call ("create-event", "create-" .. api .. "-device-node",
|
||||
@@ -82,17 +138,21 @@ end
|
||||
-- for a device, logic is based on the device number of the device given by both
|
||||
-- the parties.
|
||||
function mutils.register_cam_node (self, parent, id, factory, properties)
|
||||
local cam_data, dev_num = self:get_cam_data (properties["device.devids"])
|
||||
local api = properties["device.api"]
|
||||
local dev_ids = properties["device.devids"]
|
||||
log:debug(api .. " reported " .. dev_ids)
|
||||
|
||||
local cam_data, dev_num = parse_devids_get_cam_data(self, dev_ids)
|
||||
|
||||
if not cam_data then
|
||||
log:notice (string.format ("device number invalid for %s device:%s",
|
||||
log:notice (string.format ("device numbers invalid for %s device:%s",
|
||||
api, properties["device.name"]))
|
||||
return false
|
||||
end
|
||||
|
||||
-- only v4l2 can give this info
|
||||
if properties["api.v4l2.cap.driver"] == "uvcvideo" then
|
||||
log:debug ("Device " .. dev_num .. " is a UVC device")
|
||||
cam_data.is_device_uvc = true
|
||||
end
|
||||
|
||||
@@ -107,6 +167,7 @@ function mutils.register_cam_node (self, parent, id, factory, properties)
|
||||
-- cache info, it comes handy when creating node
|
||||
cam_api_data.parent = parent
|
||||
cam_api_data.id = id
|
||||
cam_api_data.name = properties["device.name"]
|
||||
cam_api_data.factory = factory
|
||||
cam_api_data.properties = properties
|
||||
|
||||
@@ -114,11 +175,11 @@ function mutils.register_cam_node (self, parent, id, factory, properties)
|
||||
if cam_api_data.enum_status and not cam_data[other_api].enum_status then
|
||||
log:trace (string.format ("\"%s\" armed a timer for %d", api, dev_num))
|
||||
cam_data.source = Core.timeout_add (
|
||||
Settings.get_int ("monitor.camera-discovery-timeout"), function()
|
||||
log:trace (string.format ("\"%s\" armed timer expired for %d", api, dev_num))
|
||||
self:create_cam_node (dev_num)
|
||||
cam_data.source = nil
|
||||
end)
|
||||
Settings.get_int ("monitor.camera-discovery-timeout"), function()
|
||||
log:trace (string.format ("\"%s\" armed timer expired for %d", api, dev_num))
|
||||
self:create_cam_node (dev_num)
|
||||
cam_data.source = nil
|
||||
end)
|
||||
elseif cam_data.source then
|
||||
log:trace (string.format ("\"%s\" disarmed timer for %d", api, dev_num))
|
||||
cam_data.source:destroy ()
|
||||
|
Reference in New Issue
Block a user