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.
This commit is contained in:
Julian Bouzas 2026-01-27 14:12:45 -05:00 committed by Arun Raghavan
parent 11af177902
commit d93b89fc95
4 changed files with 102 additions and 11 deletions

View file

@ -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"

View file

@ -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

View file

@ -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'",

View file

@ -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 ()