linking: explicitly mark targets that should be managed by the role-based policy

The previous assumption that any target with "device.intended-roles"
should be managed by the role-based policy is wrong, as for example
Bluetooth SCO nodes always have "device.intended-roles = Communication"
and some ALSA devices managed by ACP also do. This is meant to be used
as a hint for the desktop policy (it's been there in PulseAudio as well)
and does not necessarily mean that a role-priority-based policy should
be applied on all links to those devices.

Instead, use a new property to explicitly mark all the targets that
are meant to be managed by the role-based policy and respect that in
all places where we check for a potential role-based policy link.

Fixes: #682
This commit is contained in:
George Kiagiadakis 2024-06-28 10:06:58 +03:00
parent abc299c1d3
commit 01a7339625
6 changed files with 27 additions and 17 deletions

View file

@ -36,6 +36,11 @@ wireplumber.components.rules = [
merge = {
arguments = {
capture.props = {
# Explicitly mark all these sinks as valid role-based policy
# targets, meaning that any links between streams and these sinks
# will be managed by the role-based policy
policy.role-based.target = true
audio.position = [ FL, FR ]
media.class = Audio/Sink
}

View file

@ -63,7 +63,7 @@ function lutils.clearPriorityMediaRoleLink (link)
for l in cutils.get_object_manager ("session-item"):iterate {
type = "SiLink",
Constraint { "item.factory.name", "=", "si-standard-link", type = "pw-global" },
Constraint { "is.media.role.link", "=", true },
Constraint { "is.role.policy.link", "=", true },
Constraint { "target.media.class", "=", lmc },
} do
local props = l.properties
@ -122,6 +122,17 @@ function setPriorityMediaRoleLink (lmc, link)
end
end
function lutils.is_role_policy_target (si_props, target_props)
-- role-based policy links are those that link to targets with
-- policy.role-based.target = true, unless the stream is a monitor
-- (usually pavucontrol) or the stream is linking to the monitor ports
-- of a sink (both are "input")
return Core.test_feature ("hooks.linking.role-based.rescan")
and cutils.parseBool (target_props["policy.role-based.target"])
and not cutils.parseBool (si_props ["stream.monitor"])
and si_props["item.node.direction"] ~= target_props["item.node.direction"]
end
function lutils.unwrap_select_target_event (self, event)
local source = event:get_source ()
local si = event:get_subject ()

View file

@ -28,8 +28,8 @@ SimpleEventHook {
local source, om, si, si_props, si_flags, target =
lutils:unwrap_select_target_event (event)
-- bypass the hook if the target was not found or if the target is media role node
if target == nil or target.properties["device.intended-roles"] then
-- bypass the hook if the target was not found or if it is a role-based policy target
if target == nil or lutils.is_role_policy_target (si_props, target.properties) then
return
end

View file

@ -63,13 +63,7 @@ AsyncEventHook {
out_item = target
end
-- role links are those that link to targets with intended-roles
-- unless the stream is a monitor (usually pavucontrol) or the stream
-- is linking to the monitor ports of a sink (both are "input")
local is_media_role_link = Core.test_feature ("hooks.linking.role-based.rescan")
and target_props["device.intended-roles"] ~= nil
and not cutils.parseBool (si_props ["stream.monitor"])
and si_props["item.node.direction"] ~= target_props["item.node.direction"]
local is_role_policy_link = lutils.is_role_policy_target (si_props, target_props)
log:info (si,
string.format ("link %s <-> %s passthrough:%s, exclusive:%s, media role link:%s",
@ -77,7 +71,7 @@ AsyncEventHook {
tostring (target_props ["node.name"]),
tostring (passthrough),
tostring (exclusive),
tostring (is_media_role_link)))
tostring (is_role_policy_link)))
-- create and configure link
si_link = SessionItem ("si-standard-link")
@ -93,7 +87,7 @@ AsyncEventHook {
["policy.role-based.priority"] = target_props["policy.role-based.priority"],
["policy.role-based.action.same-priority"] = target_props["policy.role-based.action.same-priority"],
["policy.role-based.action.lower-priority"] = target_props["policy.role-based.action.lower-priority"],
["is.media.role.link"] = is_media_role_link,
["is.role.policy.link"] = is_role_policy_link,
["main.item.id"] = si.id,
["target.item.id"] = target.id,
} then
@ -129,9 +123,9 @@ AsyncEventHook {
log:debug (si_link, "registered link between "
.. tostring (si) .. " and " .. tostring (target))
-- only activate non media role links because their activation is
-- only activate non role-based policy links because their activation is
-- handled by rescan-media-role-links.lua
if not is_media_role_link then
if not is_role_policy_link then
si_link:activate (Feature.SessionItem.ACTIVE, function (l, e)
if e then
transition:return_error (tostring (l) .. " link failed: "

View file

@ -85,7 +85,7 @@ AsyncEventHook {
-- on media client link added and removed
Constraint { "event.type", "c", "session-item-added", "session-item-removed" },
Constraint { "event.session-item.interface", "=", "link" },
Constraint { "is.media.role.link", "=", true },
Constraint { "is.role.policy.link", "=", true },
},
EventInterest {
-- on default metadata suspend.playback changed
@ -140,7 +140,7 @@ AsyncEventHook {
for link in om:iterate {
type = "SiLink",
Constraint { "is.media.role.link", "=", true },
Constraint { "is.role.policy.link", "=", true },
Constraint { "target.media.class", "=", mc },
} do
-- deactivate all links if suspend playback metadata is present

View file

@ -82,7 +82,7 @@ function unhandleLinkable (si, om)
out_flags.peer_id = nil
end
if cutils.parseBool (silink.properties["is.media.role.link"]) then
if cutils.parseBool (silink.properties["is.role.policy.link"]) then
lutils.clearPriorityMediaRoleLink(silink)
end