Merge branch 'profile-preferred-priority-setting' into 'master'

find-preferred-profile: Add setting to prioritize quality/latency profiles

See merge request pipewire/wireplumber!789
This commit is contained in:
Julian Bouzas 2026-03-19 16:13:50 +00:00
commit 7788f3f346
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

@ -892,6 +892,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 ()