mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2026-02-05 04:06:34 -05:00
ucm: sort devices by priority
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
a525015e3b
commit
b3e4b15583
3 changed files with 181 additions and 0 deletions
123
src/ucm/parser.c
123
src/ucm/parser.c
|
|
@ -2098,6 +2098,120 @@ static int verb_strip_single_device_index(struct use_case_verb *verb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine priority for a device.
|
||||
* Priority order:
|
||||
* 1. If 'Priority' value exists, use it as the sort key
|
||||
* 2. If 'PlaybackPriority' value exists, use it as the sort key
|
||||
* 3. If 'CapturePriority' value exists, use it as the sort key
|
||||
* 4. Fallback: LONG_MIN (no priority)
|
||||
*/
|
||||
static long verb_device_get_priority(struct use_case_device *device)
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct ucm_value *val;
|
||||
const char *priority_str = NULL;
|
||||
long priority = LONG_MIN;
|
||||
int err;
|
||||
|
||||
list_for_each(pos, &device->value_list) {
|
||||
val = list_entry(pos, struct ucm_value, list);
|
||||
if (strcmp(val->name, "Priority") == 0) {
|
||||
priority_str = val->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!priority_str) {
|
||||
list_for_each(pos, &device->value_list) {
|
||||
val = list_entry(pos, struct ucm_value, list);
|
||||
if (strcmp(val->name, "PlaybackPriority") == 0) {
|
||||
priority_str = val->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!priority_str) {
|
||||
list_for_each(pos, &device->value_list) {
|
||||
val = list_entry(pos, struct ucm_value, list);
|
||||
if (strcmp(val->name, "CapturePriority") == 0) {
|
||||
priority_str = val->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (priority_str) {
|
||||
err = safe_strtol(priority_str, &priority);
|
||||
if (err < 0)
|
||||
priority = LONG_MIN;
|
||||
}
|
||||
|
||||
return priority;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort devices based on priority values.
|
||||
* Priority order:
|
||||
* 1. If 'Priority' value exists, use it as the sort key
|
||||
* 2. If 'PlaybackPriority' value exists, use it as the sort key
|
||||
* 3. If 'CapturePriority' value exists, use it as the sort key
|
||||
* 4. Fallback: use device->name (original) as the sort key
|
||||
* Higher priority values are placed first in the list.
|
||||
*/
|
||||
static int verb_sort_devices(struct use_case_verb *verb)
|
||||
{
|
||||
struct list_head sorted_list;
|
||||
struct list_head *pos, *npos;
|
||||
struct use_case_device *device, *insert_dev;
|
||||
|
||||
INIT_LIST_HEAD(&sorted_list);
|
||||
|
||||
/* First pass: determine and cache priority for all devices */
|
||||
list_for_each(pos, &verb->device_list) {
|
||||
device = list_entry(pos, struct use_case_device, list);
|
||||
device->sort_priority = verb_device_get_priority(device);
|
||||
}
|
||||
|
||||
/* Move devices from verb->device_list to sorted_list in sorted order */
|
||||
list_for_each_safe(pos, npos, &verb->device_list) {
|
||||
device = list_entry(pos, struct use_case_device, list);
|
||||
|
||||
/* Remove device from original list */
|
||||
list_del(&device->list);
|
||||
|
||||
/* Find the insertion point in sorted_list */
|
||||
/* Devices are sorted in descending order of priority (higher priority first) */
|
||||
/* If priorities are equal or not defined, use device name as key */
|
||||
if (list_empty(&sorted_list)) {
|
||||
list_add_tail(&device->list, &sorted_list);
|
||||
} else {
|
||||
struct list_head *pos2, *insert_pos = &sorted_list;
|
||||
list_for_each(pos2, &sorted_list) {
|
||||
insert_dev = list_entry(pos2, struct use_case_device, list);
|
||||
|
||||
if (device->sort_priority > insert_dev->sort_priority) {
|
||||
insert_pos = pos2;
|
||||
break;
|
||||
} else if (device->sort_priority == insert_dev->sort_priority) {
|
||||
if (strcmp(device->name, insert_dev->name) < 0) {
|
||||
insert_pos = pos2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&device->list, insert_pos);
|
||||
}
|
||||
}
|
||||
|
||||
/* Move sorted list back to verb->device_list */
|
||||
list_splice_init(&sorted_list, &verb->device_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
|
||||
{
|
||||
struct list_head *pos;
|
||||
|
|
@ -2128,6 +2242,14 @@ static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_ve
|
|||
uc_mgr_free_dev_name_list(&verb->rename_list);
|
||||
uc_mgr_free_dev_name_list(&verb->remove_list);
|
||||
|
||||
/* strip index from single device names */
|
||||
if (uc_mgr->conf_format >= 8) {
|
||||
/* sort devices by priority */
|
||||
err = verb_sort_devices(verb);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* normalize device names to remove spaces per use-case.h specification */
|
||||
err = verb_normalize_device_names(uc_mgr, verb);
|
||||
if (err < 0)
|
||||
|
|
@ -2138,6 +2260,7 @@ static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_ve
|
|||
err = verb_strip_single_device_index(verb);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
/* handle conflicting/supported lists */
|
||||
|
|
|
|||
|
|
@ -395,6 +395,61 @@ in the laptop instead the microphone in headphones.
|
|||
|
||||
The preference of the devices is determined by the priority value (higher value = higher priority).
|
||||
|
||||
#### Device ordering (Syntax 8+)
|
||||
|
||||
Starting with **Syntax 8**, devices are automatically sorted based on their priority values.
|
||||
The sorting is performed at the end of device management processing, after device renaming
|
||||
and index assignment.
|
||||
|
||||
The priority key selection order is:
|
||||
1. **Priority** - If this value exists, use it as the sorting key
|
||||
2. **PlaybackPriority** - If Priority doesn't exist but PlaybackPriority exists, use it
|
||||
3. **CapturePriority** - If neither Priority nor PlaybackPriority exist, use CapturePriority
|
||||
4. **Fallback** - If no priority value is defined, use the device name for alphabetical sorting
|
||||
|
||||
Devices are sorted in **descending order** of priority (higher priority values appear first
|
||||
in the device list). When two devices have the same priority value, they are sorted
|
||||
alphabetically by device name.
|
||||
|
||||
Example - Device priority ordering:
|
||||
|
||||
~~~{.html}
|
||||
SectionDevice."Speaker" {
|
||||
Comment "Internal speaker"
|
||||
EnableSequence [
|
||||
cset "name='Speaker Switch' on"
|
||||
]
|
||||
Value {
|
||||
PlaybackPriority 100
|
||||
PlaybackPCM "hw:${CardId},0"
|
||||
}
|
||||
}
|
||||
|
||||
SectionDevice."Headphones" {
|
||||
Comment "Headphone jack"
|
||||
EnableSequence [
|
||||
cset "name='Headphone Switch' on"
|
||||
]
|
||||
Value {
|
||||
PlaybackPriority 200
|
||||
PlaybackPCM "hw:${CardId},1"
|
||||
}
|
||||
}
|
||||
|
||||
SectionDevice."HDMI" {
|
||||
Comment "HDMI output"
|
||||
EnableSequence [
|
||||
cset "name='HDMI Switch' on"
|
||||
]
|
||||
Value {
|
||||
PlaybackPriority 150
|
||||
PlaybackPCM "hw:${CardId},3"
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
In this example, the device list will be ordered as: Headphones (200), HDMI (150), Speaker (100).
|
||||
|
||||
See the SND_USE_CASE_MOD constants like #SND_USE_CASE_MOD_ECHO_REF for the full list of known modifiers.
|
||||
|
||||
### Boot (alsactl)
|
||||
|
|
|
|||
|
|
@ -179,6 +179,9 @@ struct use_case_device {
|
|||
|
||||
/* value list */
|
||||
struct list_head value_list;
|
||||
|
||||
/* cached priority for sorting (LONG_MIN if not determined) */
|
||||
long sort_priority;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue