File 0004.patch of Package wireplumber
From 72b680fc4c15826e46d8090540321953ff16667e Mon Sep 17 00:00:00 2001
From: Julian Bouzas <julian.bouzas@collabora.com>
Date: Tue, 3 Feb 2026 12:49:57 -0500
Subject: [PATCH] bluez: Use 'target.object' instead of smart filters for BT
loopback nodes
This allows treating BT loopback nodes as regular nodes.
See #898
---
src/scripts/monitors/bluez.lua | 33 ++++++++++++++-------------------
1 file changed, 14 insertions(+), 19 deletions(-)
diff --git a/src/scripts/monitors/bluez.lua b/src/scripts/monitors/bluez.lua
index 0e5ba572..7d97a0ae 100644
--- a/src/scripts/monitors/bluez.lua
+++ b/src/scripts/monitors/bluez.lua
@@ -231,6 +231,12 @@ function createSetNode(parent, id, type, factory, properties)
return LocalModule("libpipewire-module-combine-stream", args_string, combine_properties)
end
+function getNodeName (prefix, bt_address, dev_name, node_id)
+ local name = prefix .. "." .. (bt_address or dev_name) .. "." .. tostring(node_id)
+ -- sanitize name
+ return name:gsub("([^%w_%-%.])", "_")
+end
+
function createNode(parent, id, type, factory, properties)
local dev_props = parent.properties
local parent_id = parent["bound-id"]
@@ -262,11 +268,8 @@ function createNode(parent, id, type, factory, properties)
-- set the node name
local name_prefix = ((factory:find("sink") and "bluez_output") or
(factory:find("source") and "bluez_input" or factory))
- local name = name_prefix .. "." ..
- (properties["api.bluez5.address"] or dev_props["device.name"]) .. "." ..
- tostring(id)
- -- sanitize name
- properties["node.name"] = name:gsub("([^%w_%-%.])", "_")
+ properties["node.name"] = getNodeName (name_prefix,
+ properties["api.bluez5.address"], dev_props["device.name"], id)
-- set priority
if not properties["priority.driver"] then
@@ -299,11 +302,9 @@ function createNode(parent, id, type, factory, properties)
if factory == "api.bluez5.sco.source" or
(factory == "api.bluez5.a2dp.source" and cutils.parseBool (properties["api.bluez5.a2dp-duplex"])) then
properties["bluez5.loopback"] = false
- properties["bluez5.loopback-target"] = true
properties["api.bluez5.internal"] = true
elseif factory == "api.bluez5.sco.sink" or factory == "api.bluez5.a2dp.sink" then
properties["bluez5.sink-loopback"] = false
- properties["bluez5.sink-loopback-target"] = true
properties["api.bluez5.internal"] = true
end
@@ -414,6 +415,8 @@ function CreateDeviceLoopbackSource (dev_props, dev_id)
local dev_name = dev_props["api.bluez5.address"] or dev_props["device.name"]
local dec_desc = dev_props["device.description"] or dev_props["device.name"]
or dev_props["device.nick"] or dev_props["device.alias"] or "bluetooth-device"
+ local target_object = getNodeName ("bluez_input",
+ dev_props["api.bluez5.address"], dev_props["device.name"], DEVICE_SOURCE_ID)
-- sanitize description, replace ':' with ' '
dec_desc = dec_desc:gsub("(:)", " ")
@@ -434,6 +437,7 @@ function CreateDeviceLoopbackSource (dev_props, dev_id)
["node.dont-fallback"] = true,
["node.linger"] = true,
["state.restore-props"] = false,
+ ["target.object"] = target_object,
},
["playback.props"] = Json.Object {
["node.name"] = string.format ("bluez_input.%s", dev_name),
@@ -446,12 +450,6 @@ function CreateDeviceLoopbackSource (dev_props, dev_id)
["device.routes"] = "1",
["priority.session"] = 2010,
["bluez5.loopback"] = true,
- ["filter.smart"] = true,
- ["filter.smart.target"] = Json.Object {
- ["bluez5.loopback-target"] = true,
- ["bluez5.loopback"] = false,
- ["device.id"] = dev_id
- }
}
}
return LocalModule("libpipewire-module-loopback", args:get_data(), {})
@@ -461,6 +459,8 @@ function CreateDeviceLoopbackSink (dev_props, dev_id)
local dev_name = dev_props["api.bluez5.address"] or dev_props["device.name"]
local dec_desc = dev_props["device.description"] or dev_props["device.name"]
or dev_props["device.nick"] or dev_props["device.alias"] or "bluetooth-device"
+ local target_object = getNodeName ("bluez_output",
+ dev_props["api.bluez5.address"], dev_props["device.name"], DEVICE_SINK_ID)
-- sanitize description, replace ':' with ' '
dec_desc = dec_desc:gsub("(:)", " ")
@@ -479,12 +479,6 @@ function CreateDeviceLoopbackSink (dev_props, dev_id)
["device.routes"] = "1",
["priority.session"] = 2010,
["bluez5.sink-loopback"] = true,
- ["filter.smart"] = true,
- ["filter.smart.target"] = Json.Object {
- ["bluez5.sink-loopback-target"] = true,
- ["bluez5.sink-loopback"] = false,
- ["device.id"] = dev_id
- }
},
["playback.props"] = Json.Object {
["node.name"] = string.format ("bluez_playback_internal.%s", dev_name),
@@ -496,6 +490,7 @@ function CreateDeviceLoopbackSink (dev_props, dev_id)
["node.dont-fallback"] = true,
["node.linger"] = true,
["state.restore-props"] = false,
+ ["target.object"] = target_object,
}
}
return LocalModule("libpipewire-module-loopback", args:get_data(), {})
--
GitLab