# This example configuration file specifies loopback nodes that can be used # to apply a role-based linking policy. # # The loopbacks are simply created by loading the libpipewire-module-loopback # pipewire module with the appropriate options. You may also create these # loopbacks in the pipewire daemon process by configuring them in pipewire.conf # (using pipewire's syntax) instead of here. wireplumber.profiles = { main = { policy.linking.role-based.loopbacks = required } } wireplumber.settings = { # This sets a default media role to be applied to streams that don't have # a role already set. This allows you to force all streams to go through # the role loopbacks. If not set, then streams without a role will follow # the standard desktop policy and will link to the default sink node.stream.default-media-role = "Multimedia" ## This allows you to tweak the volume level that is applied when ducking #linking.role-based.duck-level = 0.3 } wireplumber.components.rules = [ # This encodes common arguments and dependencies of the role loopbacks so that # we don't have to repeateadly write them on all instances below { 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.navigation loopback.sink.role.assistant loopback.sink.role.communication 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" ] 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 = { node.name = "loopback.sink.role.notification" node.description = "System Notifications" capture.props = { device.intended-roles = [ "Notification" ] policy.role-based.priority = 20 policy.role-based.action.same-priority = "mix" policy.role-based.action.lower-priority = "mix" } } provides = loopback.sink.role.notification } { name = libpipewire-module-loopback, type = pw-module arguments = { node.name = "loopback.sink.role.navigation" node.description = "Navigation" capture.props = { device.intended-roles = [ "Navigation", "GPS" ] policy.role-based.priority = 30 policy.role-based.action.same-priority = "mix" policy.role-based.action.lower-priority = "duck" } } provides = loopback.sink.role.navigation } { name = libpipewire-module-loopback, type = pw-module arguments = { node.name = "loopback.sink.role.assistant" node.description = "Voice Assistant" capture.props = { device.intended-roles = [ "Assistant" ] policy.role-based.priority = 40 policy.role-based.action.same-priority = "mix" policy.role-based.action.lower-priority = "cork" } } provides = loopback.sink.role.assistant } { name = libpipewire-module-loopback, type = pw-module arguments = { node.name = "loopback.sink.role.communication" node.description = "Communication" capture.props = { device.intended-roles = [ "Communication", "Phone" ] policy.role-based.priority = 50 policy.role-based.action.same-priority = "mix" policy.role-based.action.lower-priority = "cork" } } provides = loopback.sink.role.communication } { name = libpipewire-module-loopback, type = pw-module arguments = { node.name = "loopback.sink.role.alert" node.description = "Alert" capture.props = { device.intended-roles = [ "Alert", "Emergency" ] policy.role-based.priority = 100 policy.role-based.action.same-priority = "mix" policy.role-based.action.lower-priority = "cork" policy.role-based.preferred-target = "Speaker" } } provides = loopback.sink.role.alert } ]