data: Add media roles configuration

This ensures we properly duck any "multimedia" streams when playing
event sounds. We also introduce an alert group for e.g. cell broadcasts.

For testing copy to

  ~/.config/wireplumber/wireplumber.conf.d/media-role-nodes.conf

and

  systemctl --user restart wireplumber

Signed-off-by: Guido Günther <agx@sigxcpu.org>
This commit is contained in:
Guido Günther
2025-10-24 13:43:39 +02:00
parent 5de4519710
commit d58b7cf517
2 changed files with 276 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
# Based on https://gitlab.freedesktop.org/pipewire/wireplumber/-/blob/master/src/config/wireplumber.conf.d.examples/media-role-nodes.conf
wireplumber.profiles = {
main = {
policy.linking.role-based.loopbacks = required
}
}
wireplumber.settings = {
# Default role
node.stream.default-media-role = "Multimedia"
linking.role-based.duck-level = 0.5
}
wireplumber.components.rules = [
{
matches = [
{
provides = "~loopback.sink.*"
}
]
actions = {
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
}
playback.props = {
# This must be set to ensure that the real audio sink is suspended
# when there is no active client stream linked
node.passive = true
# Set this to an unused role to make sure that loopbacks don't
# accidentally chain-link on to one another, especially when
# node.stream.default-media-role is configured in the settings
media.role = "Loopback"
}
}
requires = [ support.export-core, pw.node-factory.adapter ]
}
}
}
]
wireplumber.components = [
{
type = virtual, provides = policy.linking.role-based.loopbacks
requires = [ loopback.sink.role.multimedia
loopback.sink.role.notification
loopback.sink.role.alarm
loopback.sink.role.ringtone
loopback.sink.role.alert ]
}
{
name = libpipewire-module-loopback, type = pw-module
arguments = {
node.name = "loopback.sink.role.multimedia"
node.description = "Multimedia"
capture.props = {
device.intended-roles = [ "Music", "Movie", "Game", "Multimedia" ]
device.icon-name = "applications-multimedia"
policy.role-based.priority = 10
policy.role-based.action.same-priority = "mix"
policy.role-based.action.lower-priority = "mix"
}
}
provides = loopback.sink.role.multimedia
}
{
name = libpipewire-module-loopback, type = pw-module
arguments = {
# System events from e.g. notifications
node.name = "loopback.sink.role.notification"
node.description = "System Events and Notifications"
capture.props = {
device.intended-roles = [ "Notification" ]
device.icon-name = "preferences-system-notifications"
policy.role-based.priority = 20
policy.role-based.action.same-priority = "mix"
policy.role-based.action.lower-priority = "duck"
}
}
provides = loopback.sink.role.notification
}
{
name = libpipewire-module-loopback, type = pw-module
arguments = {
# Alarm clocks
node.name = "loopback.sink.role.alarm"
node.description = "Alarm Clocks"
capture.props = {
device.intended-roles = [ "Alarm" ]
device.icon-name = "alarm"
policy.role-based.priority = 30
policy.role-based.action.same-priority = "mix"
policy.role-based.action.lower-priority = "duck"
}
}
provides = loopback.sink.role.alarm
}
{
name = libpipewire-module-loopback, type = pw-module
arguments = {
# Phone call ring tones
node.name = "loopback.sink.role.ringtone"
node.description = "Ringtones"
capture.props = {
device.intended-roles = [ "Ringtone" ]
device.icon-name = "call-ring"
policy.role-based.priority = 40
policy.role-based.action.same-priority = "mix"
policy.role-based.action.lower-priority = "cork"
}
}
provides = loopback.sink.role.ringtone
}
{
name = libpipewire-module-loopback, type = pw-module
arguments = {
# Cell Broadcasts, etc
node.name = "loopback.sink.role.alert"
node.description = "Alerts"
capture.props = {
device.intended-roles = [ "Alert", "Emergency" ]
device.icon-name = "network-cellular"
policy.role-based.priority = 100
policy.role-based.action.same-priority = "mix"
policy.role-based.action.lower-priority = "cork"
}
}
provides = loopback.sink.role.alert
}
]