filter-utils: handle new 'filter.smart.targetable' property
This property indicates whether the filter can be directly linked with clients that have a defined target (Eg: pw-play --target <filter-name>) or not. This can be useful when a client wants to be linked with a filter that is in the middle of the chain in order to bypass the filters that are placed before the selected one. If the property is not set, wireplumber will consider the filter not targetable by default, meaning filters will never by bypassed by clients, and clients will always be linked with the first filter in the chain. Fixes #554
This commit is contained in:
@@ -134,6 +134,15 @@ optional node properties on the main node:
|
||||
disabled filter will never be used in any circumstances. If the property is
|
||||
not set, wireplumber will consider the filter not disabled by default.
|
||||
|
||||
- filter.smart.targetable:
|
||||
Boolean indicating whether the filter can be directly linked with clients that
|
||||
have a defined target (Eg: pw-play --target <filter-name>) or not. This can be
|
||||
useful when a client wants to be linked with a filter that is in the middle of
|
||||
the chain in order to bypass the filters that are placed before the selected
|
||||
one. If the property is not set, wireplumber will consider the filter not
|
||||
targetable by default, meaning filters will never by bypassed by clients, and
|
||||
clients will always be linked with the first filter in the chain.
|
||||
|
||||
- filter.smart.target:
|
||||
A JSON object that defines the matching properties of the filter's target node.
|
||||
A filter target can never be another filter node (wireplumber will ignore it),
|
||||
@@ -173,6 +182,7 @@ The PipeWire configuration files for the 2 filters should be like this:
|
||||
filter.smart = true
|
||||
filter.smart.name = loopback-1
|
||||
filter.smart.disabled = false
|
||||
filter.smart.targetable = false
|
||||
filter.smart.before = [ loopback-2 ]
|
||||
}
|
||||
playback.props = {
|
||||
@@ -199,6 +209,7 @@ The PipeWire configuration files for the 2 filters should be like this:
|
||||
filter.smart = true
|
||||
filter.smart.name = loopback-2
|
||||
filter.smart.disabled = false
|
||||
filter.smart.targetable = false
|
||||
}
|
||||
playback.props = {
|
||||
audio.position = [ FL FR ]
|
||||
@@ -268,6 +279,7 @@ define the filters like this:
|
||||
filter.smart = true
|
||||
filter.smart.name = loopback-1
|
||||
filter.smart.disabled = false
|
||||
filter.smart.targetable = false
|
||||
filter.smart.before = [ loopback-2 ]
|
||||
filter.smart.target = { node.name = "not-default-audio-device-name" }
|
||||
}
|
||||
@@ -295,6 +307,7 @@ define the filters like this:
|
||||
filter.smart = true
|
||||
filter.smart.name = loopback-2
|
||||
filter.smart.disabled = false
|
||||
filter.smart.targetable = false
|
||||
}
|
||||
playback.props = {
|
||||
audio.position = [ FL FR ]
|
||||
|
@@ -83,6 +83,29 @@ local function getFilterSmartDisabled (metadata, node)
|
||||
return false
|
||||
end
|
||||
|
||||
local function getFilterSmartTargetable (metadata, node)
|
||||
-- Check metadata
|
||||
if metadata ~= nil then
|
||||
local id = node["bound-id"]
|
||||
local value_str = metadata:find (id, "filter.smart.targetable")
|
||||
if value_str ~= nil then
|
||||
local json = Json.Raw (value_str)
|
||||
if json:is_boolean() then
|
||||
return json:parse()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check node properties
|
||||
local prop_str = node.properties ["filter.smart.targetable"]
|
||||
if prop_str ~= nil then
|
||||
return cutils.parseBool (prop_str)
|
||||
end
|
||||
|
||||
-- Otherwise consider the filter not targetable by default
|
||||
return false
|
||||
end
|
||||
|
||||
local function getFilterSmartTarget (metadata, node, om, dont_move)
|
||||
-- Check metadata and fallback to properties
|
||||
local id = node["bound-id"]
|
||||
@@ -287,6 +310,7 @@ local function rescanFilters (om, metadata_om)
|
||||
filter.smart = getFilterSmart (metadata, n)
|
||||
filter.name = getFilterSmartName (metadata, n)
|
||||
filter.disabled = getFilterSmartDisabled (metadata, n)
|
||||
filter.targetable = getFilterSmartTargetable (metadata, n)
|
||||
filter.target = getFilterSmartTarget (metadata, n, om)
|
||||
filter.before = getFilterSmartBefore (metadata, n)
|
||||
filter.after = getFilterSmartAfter (metadata, n)
|
||||
@@ -354,6 +378,21 @@ function module.is_filter_disabled (direction, link_group)
|
||||
return false
|
||||
end
|
||||
|
||||
function module.is_filter_targetable (direction, link_group)
|
||||
-- Make sure direction and link_group is valid
|
||||
if direction == nil or link_group == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
for i, v in ipairs(module.filters) do
|
||||
if v.direction == direction and v.link_group == link_group then
|
||||
return v.targetable
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function module.get_filter_target (direction, link_group)
|
||||
-- Make sure direction and link_group are valid
|
||||
if direction == nil or link_group == nil then
|
||||
|
@@ -35,6 +35,18 @@ SimpleEventHook {
|
||||
return
|
||||
end
|
||||
|
||||
-- bypass the hook if target is defined, is a filter and is targetable
|
||||
local target_node = target:get_associated_proxy ("node")
|
||||
local target_link_group = target_node.properties ["node.link-group"]
|
||||
local target_direction = cutils.getTargetDirection (si.properties)
|
||||
if target_link_group ~= nil and si_flags.has_defined_target then
|
||||
if futils.is_filter_smart (target_direction, target_link_group) and
|
||||
not futils.is_filter_disabled (target_direction, target_link_group) and
|
||||
futils.is_filter_targetable (target_direction, target_link_group) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Get the filter from the given target if it exists, otherwise get the
|
||||
-- default filter, but only if target was not defined
|
||||
local target_direction = cutils.getTargetDirection (si.properties)
|
||||
|
Reference in New Issue
Block a user