diff --git a/docs/rst/daemon/configuration/policy.rst b/docs/rst/daemon/configuration/policy.rst index b94bf80e..55f9571c 100644 --- a/docs/rst/daemon/configuration/policy.rst +++ b/docs/rst/daemon/configuration/policy.rst @@ -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 ) 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 ] diff --git a/src/scripts/lib/filter-utils.lua b/src/scripts/lib/filter-utils.lua index 0ae514c9..18878f8d 100644 --- a/src/scripts/lib/filter-utils.lua +++ b/src/scripts/lib/filter-utils.lua @@ -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 diff --git a/src/scripts/linking/get-filter-from-target.lua b/src/scripts/linking/get-filter-from-target.lua index e17de37a..e9cd77e0 100644 --- a/src/scripts/linking/get-filter-from-target.lua +++ b/src/scripts/linking/get-filter-from-target.lua @@ -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)