From 7fa44ef8d0b2f603bd826d399718cef8cf6a800a Mon Sep 17 00:00:00 2001 From: Julian Bouzas Date: Tue, 21 Apr 2026 13:54:11 -0400 Subject: [PATCH] find-preferred-profile: Add new 'bluetooth.profile-preference' setting This setting will use the best quality or latency profiles for BT devices if available. HSP/HFP profiles will always be ignored. The setting is a string that only accepts 'quality' and 'latency' strings. Any other value will be treated the same way as the 'quality' value. --- po/conf.pot | 10 ++++ src/config/wireplumber.conf | 6 ++ src/scripts/device/find-preferred-profile.lua | 60 +++++++++++++++---- src/scripts/device/select-profile.lua | 8 +++ 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/po/conf.pot b/po/conf.pot index 13641209..32948bcf 100644 --- a/po/conf.pot +++ b/po/conf.pot @@ -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" diff --git a/src/config/wireplumber.conf b/src/config/wireplumber.conf index 63a4046b..cfdf0577 100644 --- a/src/config/wireplumber.conf +++ b/src/config/wireplumber.conf @@ -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 = { diff --git a/src/scripts/device/find-preferred-profile.lua b/src/scripts/device/find-preferred-profile.lua index 852032ab..6ec0dd93 100644 --- a/src/scripts/device/find-preferred-profile.lua +++ b/src/scripts/device/find-preferred-profile.lua @@ -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 diff --git a/src/scripts/device/select-profile.lua b/src/scripts/device/select-profile.lua index da870aeb..25046517 100644 --- a/src/scripts/device/select-profile.lua +++ b/src/scripts/device/select-profile.lua @@ -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)