scripts: use filter-utils to implement smart filter policy

This commit is contained in:
Julian Bouzas 2023-08-07 10:01:37 -04:00 committed by George Kiagiadakis
parent 1ba3844f2c
commit 56017fdbe6
8 changed files with 283 additions and 52 deletions

View file

@ -503,6 +503,11 @@ wireplumber.components = [
provides = hooks.linking.target.find-defined
requires = [ support.lua-scripting ]
}
{
name = linking/find-filter-target.lua, type = script/lua
provides = hooks.linking.target.find-filter
requires = [ support.lua-scripting, metadata.filters ]
}
{
name = linking/find-default-target.lua, type = script/lua
provides = hooks.linking.target.find-default
@ -513,6 +518,11 @@ wireplumber.components = [
provides = hooks.linking.target.find-best
requires = [ support.lua-scripting ]
}
{
name = linking/get-filter-from-target.lua, type = script/lua
provides = hooks.linking.target.get-filter-from
requires = [ support.lua-scripting, metadata.filters ]
}
{
name = linking/prepare-link.lua, type = script/lua
provides = hooks.linking.target.prepare-link
@ -530,8 +540,10 @@ wireplumber.components = [
hooks.linking.target.link ]
wants = [ hooks.linking.move-follow,
hooks.linking.target.find-defined,
hooks.linking.target.find-filter,
hooks.linking.target.find-default,
hooks.linking.target.find-best ]
hooks.linking.target.find-best,
hooks.linking.target.get-filter-from ]
}
## Linking: Role-based priority system

View file

@ -44,12 +44,19 @@ SimpleEventHook {
} do
local target_props = target.properties
local target_node_id = target_props ["node.id"]
local si_target_node = si:get_associated_proxy ("node")
local si_target_link_group = si_target_node.properties ["node.link-group"]
local priority = tonumber (target_props ["priority.session"]) or 0
log:debug (string.format ("Looking at: %s (%s)",
tostring (target_props ["node.name"]),
tostring (target_node_id)))
if si_target_link_group ~= nil then
Log.debug ("... ignoring filter as best target")
goto skip_linkable
end
if not putils.canLink (si_props, target) then
log:debug ("... cannot link, skip linkable")
goto skip_linkable

View file

@ -11,7 +11,7 @@ log = Log.open_topic ("s-linking")
SimpleEventHook {
name = "linking/find-default-target",
after = "linking/find-defined-target",
after = "linking/find-filter-target",
interests = {
EventInterest {
Constraint { "event.type", "=", "select-target" },

View file

@ -0,0 +1,72 @@
-- WirePlumber
--
-- Copyright © 2023 Collabora Ltd.
--
-- SPDX-License-Identifier: MIT
--
-- Check if the target node is a filter target.
local putils = require ("policy-utils")
local cutils = require ("common-utils")
local futils = require ("filter-utils")
log = Log.open_topic ("s-linking")
function findFilterTarget (si, om)
local node = si:get_associated_proxy ("node")
local direction = cutils.getTargetDirection (si.properties)
local link_group = node.properties ["node.link-group"]
local target_id = -1
-- return nil if si is not a filter node
if link_group == nil then
return nil
end
-- get the filter target
return futils.get_filter_target (direction, link_group)
end
SimpleEventHook {
name = "linking/find-filter-target",
after = "linking/find-defined-target",
interests = {
EventInterest {
Constraint { "event.type", "=", "select-target" },
},
},
execute = function (event)
local source, om, si, si_props, si_flags, target =
putils:unwrap_find_target_event (event)
-- bypass the hook if the target is already picked up
if target then
return
end
local target_picked = false
log:info (si, string.format ("handling item: %s (%s)",
tostring (si_props ["node.name"]), tostring (si_props ["node.id"])))
target = findFilterTarget (si, om)
local can_passthrough, passthrough_compatible
if target then
passthrough_compatible, can_passthrough =
putils.checkPassthroughCompatibility (si, target)
if putils.canLink (si_props, target) and passthrough_compatible then
target_picked = true;
end
end
if target_picked then
log:info (si,
string.format ("... filter target picked: %s (%s), can_passthrough:%s",
tostring (target.properties ["node.name"]),
tostring (target.properties ["node.id"]),
tostring (can_passthrough)))
si_flags.can_passthrough = can_passthrough
event:set_data ("target", target)
end
end
}:register ()

View file

@ -0,0 +1,64 @@
-- WirePlumber
--
-- Copyright © 2023 Collabora Ltd.
--
-- SPDX-License-Identifier: MIT
--
-- Check if the target node is a filter target.
local putils = require ("policy-utils")
local cutils = require ("common-utils")
local futils = require ("filter-utils")
log = Log.open_topic ("s-linking")
SimpleEventHook {
name = "linking/get-filter-from-target",
after = "linking/find-best-target",
interests = {
EventInterest {
Constraint { "event.type", "=", "select-target" },
},
},
execute = function (event)
local source, om, si, si_props, si_flags, target =
putils:unwrap_find_target_event (event)
-- bypass the hook if the target was not found
if target == nil then
return
end
-- bypass the hook if the session item is a filter
local node = si:get_associated_proxy ("node")
local link_group = node.properties ["node.link-group"]
if link_group ~= nil then
return
end
-- Get the filter from the given target, if any
local target_direction = cutils.getTargetDirection (si.properties)
local filter_target = futils.get_filter_from_target (target_direction, target)
if filter_target ~= nil then
target = filter_target
end
local can_passthrough, passthrough_compatible
if target ~= nil then
passthrough_compatible, can_passthrough =
putils.checkPassthroughCompatibility (si, target)
if putils.canLink (si_props, target) and passthrough_compatible then
target_picked = true;
end
end
if target_picked then
log:info (si,
string.format ("... filter target picked: %s (%s), can_passthrough:%s",
tostring (target.properties ["node.name"]),
tostring (target.properties ["node.id"]),
tostring (can_passthrough)))
si_flags.can_passthrough = can_passthrough
event:set_data ("target", target)
end
end
}:register ()

View file

@ -14,7 +14,7 @@ log = Log.open_topic ("s-linking")
SimpleEventHook {
name = "linking/prepare-link",
after = "linking/find-best-target",
after = "linking/get-filter-from-target",
interests = {
EventInterest {
Constraint { "event.type", "=", "select-target" },

View file

@ -12,8 +12,26 @@
local putils = require ("policy-utils")
local cutils = require ("common-utils")
local futils = require ("filter-utils")
log = Log.open_topic ("s-linking")
function checkFilter (si, om, handle_nonstreams)
-- always handle filters if handle_nonstreams is true, even if it is disabled
if handle_nonstreams then
return true
end
-- always return true if this is not a filter
local node = si:get_associated_proxy ("node")
local link_group = node.properties["node.link-group"]
if link_group == nil then
return true
end
local direction = cutils.getTargetDirection (si.properties)
return futils.is_filter_enabled (direction, link_group)
end
function checkLinkable (si, om, handle_nonstreams)
local si_props = si.properties
@ -28,9 +46,48 @@ function checkLinkable (si, om, handle_nonstreams)
return false, si_props
end
-- check filters
if not checkFilter (si, om, handle_nonstreams) then
return false, si_props
end
return true, si_props
end
function unhandleLinkable (si, om)
local si_id = si.id
local valid, si_props = checkLinkable (si, om, true)
if not valid then
return
end
log.info (si, string.format ("unhandling item: %s (%s)",
tostring (si_props ["node.name"]), tostring (si_props ["node.id"])))
-- iterate over all the links in the graph and
-- remove any links associated with this item
for silink in om:iterate { type = "SiLink" } do
local out_id = tonumber (silink.properties ["out.item.id"])
local in_id = tonumber (silink.properties ["in.item.id"])
if out_id == si_id or in_id == si_id then
local in_flags = putils:get_flags (in_id)
local out_flags = putils:get_flags (out_id)
if out_id == si_id and in_flags.peer_id == out_id then
in_flags.peer_id = nil
elseif in_id == si_id and out_flags.peer_id == in_id then
out_flags.peer_id = nil
end
silink:remove ()
log.info (silink, "... link removed")
end
end
putils:clear_flags (si_id)
end
SimpleEventHook {
name = "linking/linkable-removed",
interests = {
@ -43,40 +100,34 @@ SimpleEventHook {
local si = event:get_subject ()
local source = event:get_source ()
local om = source:call ("get-object-manager", "session-item")
local si_id = si.id
local valid, si_props = checkLinkable (si, om, true)
if not valid then
return
end
log:info (si, string.format ("unhandling item: %s (%s)",
tostring (si_props ["node.name"]), tostring (si_props ["node.id"])))
-- iterate over all the links in the graph and
-- remove any links associated with this item
for silink in om:iterate { type = "SiLink" } do
local out_id = tonumber (silink.properties ["out.item.id"])
local in_id = tonumber (silink.properties ["in.item.id"])
if out_id == si_id or in_id == si_id then
local in_flags = putils:get_flags (in_id)
local out_flags = putils:get_flags (out_id)
if out_id == si_id and in_flags.peer_id == out_id then
in_flags.peer_id = nil
elseif in_id == si_id and out_flags.peer_id == in_id then
out_flags.peer_id = nil
end
silink:remove ()
log:info (silink, "... link removed")
end
end
putils:clear_flags (si_id)
unhandleLinkable (si, om)
end
}:register ()
function handleLinkables (source)
local om = source:call ("get-object-manager", "session-item")
for si in om:iterate { type = "SiLinkable" } do
local valid, si_props = checkLinkable (si, om)
if not valid then
goto skip_linkable
end
-- check if we need to link this node at all
local autoconnect = cutils.parseBool (si_props ["node.autoconnect"])
if not autoconnect then
log.debug (si, tostring (si_props ["node.name"]) .. " does not need to be autoconnected")
goto skip_linkable
end
-- push event to find target and link
source:call ("push-event", "select-target", si, nil)
::skip_linkable::
end
end
SimpleEventHook {
name = "linking/rescan",
interests = {
@ -86,28 +137,10 @@ SimpleEventHook {
},
execute = function (event)
local source = event:get_source ()
local om = source:call ("get-object-manager", "session-item")
log:info ("rescanning...")
for si in om:iterate { type = "SiLinkable" } do
local valid, si_props = checkLinkable (si, om)
if not valid then
goto skip_linkable
end
-- check if we need to link this node at all
local autoconnect = cutils.parseBool (si_props ["node.autoconnect"])
if not autoconnect then
log:debug (si, tostring (si_props ["node.name"]) .. " does not need to be autoconnected")
goto skip_linkable
end
-- push event to find target and link
source:call ("push-event", "select-target", si, nil)
::skip_linkable::
end
handleLinkables (source)
end
}:register ()
@ -131,3 +164,44 @@ SimpleEventHook {
source:call ("schedule-rescan", "linking")
end
}:register ()
SimpleEventHook {
name = "linking/rescan-trigger-before-filters-metadata-changed",
before = "lib/filter-utils/rescan-metadata-changed",
interests = {
EventInterest {
Constraint { "event.type", "=", "metadata-changed" },
Constraint { "metadata.name", "=", "filters" },
},
},
execute = function (event)
local source = event:get_source ()
local om = source:call ("get-object-manager", "session-item")
-- unlink all filters
for si in om:iterate {
type = "SiLinkable",
Constraint { "node.link-group", "+" },
} do
unhandleLinkable (si, om)
end
end
}:register ()
SimpleEventHook {
name = "linking/rescan-trigger-after-filters-metadata-changed",
after = "lib/filter-utils/rescan-metadata-changed",
interests = {
EventInterest {
Constraint { "event.type", "=", "metadata-changed" },
Constraint { "metadata.name", "=", "filters" },
},
},
execute = function (event)
local source = event:get_source ()
local om = source:call ("get-object-manager", "session-item")
source:call ("schedule-rescan", "linking")
end
}:register ()

View file

@ -255,6 +255,8 @@ load_components (ScriptRunnerFixture *f, gconstpointer argv)
load_component (f, "linking/find-best-target.lua", "script/lua");
load_component (f, "linking/find-default-target.lua", "script/lua");
load_component (f, "linking/find-defined-target.lua", "script/lua");
load_component (f, "linking/find-filter-target.lua", "script/lua");
load_component (f, "linking/get-filter-from-target.lua", "script/lua");
load_component (f, "linking/link-target.lua", "script/lua");
load_component (f, "linking/prepare-link.lua", "script/lua");
load_component (f, "linking/rescan.lua", "script/lua");