Merge branch 'setting-profile-preference' into 'master'

find-preferred-profile: Add new 'bluetooth.profile-preference' setting

See merge request pipewire/wireplumber!819
This commit is contained in:
Julian Bouzas 2026-04-30 11:37:01 +00:00
commit bd410f757a
4 changed files with 71 additions and 13 deletions

View file

@ -13,6 +13,16 @@ msgstr ""
msgid "Auto-switch to headset profile"
msgstr ""
#. /wireplumber.settings.schema/bluetooth.profile-preference/description
#: wireplumber.conf
msgid "Prefer better quality or better latency when auto-selecting profiles (only 'quality' or 'latency' values are accepted)"
msgstr ""
#. /wireplumber.settings.schema/bluetooth.profile-preference/name
#: wireplumber.conf
msgid "Bluetooth profile preference"
msgstr ""
#. /wireplumber.settings.schema/bluetooth.use-persistent-storage/description
#: wireplumber.conf
msgid "Remember and restore Bluetooth headset mode status"

View file

@ -876,6 +876,12 @@ wireplumber.settings.schema = {
type = "bool"
default = true
}
bluetooth.profile-preference = {
name = "Bluetooth profile preference"
description = "Prefer better quality or better latency when auto-selecting profiles (only 'quality' or 'latency' values are accepted)"
type = "string"
default = "quality"
}
## Device
device.restore-profile = {

View file

@ -13,6 +13,37 @@ log = Log.open_topic ("s-device")
config = {}
config.rules = Conf.get_section_as_json ("device.profile.priority.rules", Json.Array {})
function getRulesProfilePriorities (device)
local props = JsonUtils.match_rules_update_properties (config.rules,
device.properties)
local p_array = props["priorities"]
if not p_array then
return nil
end
local p_json = Json.Raw (p_array)
return p_json:parse ()
end
function getPreferredBluetoothProfilePriorities (device)
if device.properties["device.api"] ~= "bluez5" then
return nil
end
local preference = Settings.get_string ("bluetooth.profile-preference")
if preference == "latency" then
log:info (device, "using best latency profile")
return { "a2dp-auto-prefer-latency" }
elseif preference == "quality" then
log:info (device, "using best quality profile")
return { "a2dp-auto-prefer-quality" }
end
log:warning (device, "invalid preference value '" .. preference ..
"'. Defaulting to best quality profile")
return { "a2dp-auto-prefer-quality" }
end
SimpleEventHook {
name = "device/find-preferred-profile",
after = "device/find-stored-profile",
@ -31,19 +62,22 @@ SimpleEventHook {
end
local device = event:get_subject ()
local props = JsonUtils.match_rules_update_properties (
config.rules, device.properties)
local p_array = props["priorities"]
-- skip hook if the profile priorities are NOT defined for this device.
if not p_array then
return nil
end
local p_json = Json.Raw(p_array)
local priorities = p_json:parse()
local device_name = device.properties["device.name"] or ""
-- Use device priority rules if any. Otherwise, get the prefered quality or
-- latency priorities if BT device.
local priorities = getRulesProfilePriorities (device)
if priorities == nil then
priorities = getPreferredBluetoothProfilePriorities (device)
end
if priorities == nil then
log:info (device, string.format (
"Preferred profile priorities not available for device '%s'",
device_name))
return
end
-- Find the prefered profile
for _, priority_profile in ipairs(priorities) do
for p in device:iterate_params("EnumProfile") do
local device_profile = cutils.parseParam(p, "EnumProfile")
@ -61,8 +95,8 @@ SimpleEventHook {
selected_profile.name, selected_profile.index, device_name))
event:set_data ("selected-profile", selected_profile)
else
log:info (device, "Profiles listed in 'device.profile.priority.rules'"
.. " do not match the available ones of device: " .. device_name)
log:info (device, string.format (
"Could not find preferred profile for device '%s'", device_name))
end
end

View file

@ -26,3 +26,11 @@ SimpleEventHook {
source:call ("push-event", "select-profile", device, nil)
end
}:register()
Settings.subscribe ("bluetooth.profile-preference", function ()
source = source or Plugin.find ("standard-event-source")
local device_om = source:call ("get-object-manager", "device")
for device in device_om:iterate () do
source:call ("push-event", "select-profile", device, nil)
end
end)