From d93b89fc95e95528d9fbaea62e20145c7b23f19b Mon Sep 17 00:00:00 2001 From: Julian Bouzas Date: Tue, 27 Jan 2026 14:12:45 -0500 Subject: [PATCH] find-preferred-profile: Add setting to prioritize quality/latency profiles This new 'device.profile.preferred-priority' setting allows prioritizing high quality known profiles or low latency known profiles by setting it to 'quality' or 'latency' respectively. If set to 'default', it will use the priorities defined in the 'device.profile.priority.rules' configuration section. --- po/conf.pot | 10 +++ src/config/wireplumber.conf | 6 ++ src/scripts/device/find-preferred-profile.lua | 64 +++++++++++++++---- src/scripts/device/state-profile.lua | 33 ++++++++++ 4 files changed, 102 insertions(+), 11 deletions(-) diff --git a/po/conf.pot b/po/conf.pot index 13641209..53240f9d 100644 --- a/po/conf.pot +++ b/po/conf.pot @@ -23,6 +23,16 @@ msgstr "" msgid "Persistent storage" msgstr "" +#. /wireplumber.settings.schema/device.profile.preferred-priority/description +#: wireplumber.conf +msgid "The preferred priority for audio device profiles. Possible values are: 'default', 'latency' or 'quality'" +msgstr "" + +#. /wireplumber.settings.schema/device.profile.preferred-priority/name +#: wireplumber.conf +msgid "Device profile preferred priority" +msgstr "" + #. /wireplumber.settings.schema/device.restore-profile/description #: wireplumber.conf msgid "Remember and restore device profiles" diff --git a/src/config/wireplumber.conf b/src/config/wireplumber.conf index ee1aa1d6..2a57d51c 100644 --- a/src/config/wireplumber.conf +++ b/src/config/wireplumber.conf @@ -889,6 +889,12 @@ wireplumber.settings.schema = { type = "bool" default = false } + device.profile.preferred-priority = { + name = "Device profile preferred priority" + description = "The preferred priority for audio device profiles. Possible values are: 'default', 'latency' or 'quality'" + type = "string" + default = "default" + } ## Linking diff --git a/src/scripts/device/find-preferred-profile.lua b/src/scripts/device/find-preferred-profile.lua index 852032ab..aeccd412 100644 --- a/src/scripts/device/find-preferred-profile.lua +++ b/src/scripts/device/find-preferred-profile.lua @@ -13,6 +13,54 @@ log = Log.open_topic ("s-device") config = {} config.rules = Conf.get_section_as_json ("device.profile.priority.rules", Json.Array {}) +local LATENCY_PROFILE_PRIORITIES = { + "a2dp-sink-aptx_ll", + "a2dp-sink-sbc_xq", + "a2dp-sink-aptx", + "a2dp-sink-sbc", + "a2dp-sink-ldac", + "a2dp-sink-aptx_hd", + "a2dp-sink-aac", +} + +local QUALITY_PROFILE_PRIORITIES = { + "a2dp-sink-ldac", + "a2dp-sink-aptx_hd", + "a2dp-sink-aac", + "a2dp-sink-sbc_xq", + "a2dp-sink-aptx", + "a2dp-sink-sbc", + "a2dp-sink-aptx_ll" +} + +local ProfilePriorityType = { + DEFAULT = "default", + LATENCY = "latency", + QUALITY = "quality", +} + +function getPreferredProfilePriorities (device) + local priority_type = Settings.get_string ("device.profile.preferred-priority") + if priority_type == ProfilePriorityType.DEFAULT then + -- Check priority defined rules if any + local props = JsonUtils.match_rules_update_properties ( + config.rules, device.properties) + local p_array = props["priorities"] + if not p_array then + return nil + end + return Json.Raw(p_array):parse() + elseif priority_type == ProfilePriorityType.LATENCY then + return LATENCY_PROFILE_PRIORITIES + elseif priority_type == ProfilePriorityType.QUALITY then + return QUALITY_PROFILE_PRIORITIES + end + + log:warning (device, "Profile priority type '" .. tostring (priority_type) .. + "' no valid, using default profile priority") + return nil +end + SimpleEventHook { name = "device/find-preferred-profile", after = "device/find-stored-profile", @@ -30,20 +78,13 @@ SimpleEventHook { return end + -- Get the preferred profile priorities 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 + local priorities = getPreferredProfilePriorities (device) + if priorities == nil then + return end - local p_json = Json.Raw(p_array) - local priorities = p_json:parse() - local device_name = device.properties["device.name"] or "" - for _, priority_profile in ipairs(priorities) do for p in device:iterate_params("EnumProfile") do local device_profile = cutils.parseParam(p, "EnumProfile") @@ -55,6 +96,7 @@ SimpleEventHook { end ::profile_set:: + local device_name = device.properties["device.name"] or "" if selected_profile then log:info (device, string.format ( "Found preferred profile '%s' (%d) for device '%s'", diff --git a/src/scripts/device/state-profile.lua b/src/scripts/device/state-profile.lua index 8d42ef8d..af865a8b 100644 --- a/src/scripts/device/state-profile.lua +++ b/src/scripts/device/state-profile.lua @@ -147,3 +147,36 @@ Settings.subscribe ("device.restore-profile", function () toggleState (Settings.get_boolean ("device.restore-profile")) end) toggleState (Settings.get_boolean ("device.restore-profile")) + +device_om = ObjectManager { + Interest { + type = "device", + Constraint { "device.api", "c", "alsa", "bluez5" }, + } +} + +function clearStoredProfile (device) + if state_table ~= nil then + local dev_name = device.properties["device.name"] + state_table[dev_name] = nil + state:save_after_timeout (state_table) + log:info (device, string.format ("cleared stored profile for device '%s'", + dev_name)) + end +end + +function evaluateProfiles () + source = source or Plugin.find ("standard-event-source") + if source ~= nil then + for device in device_om:iterate () do + clearStoredProfile (device) + source:call ("push-event", "select-profile", device, nil) + end + end +end + +Settings.subscribe ("device.profile.preferred-priority", function () + evaluateProfiles () +end) + +device_om:activate ()