mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2026-03-11 05:33:43 -04: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;
|
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)
|
static int verb_device_management(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb)
|
||||||
{
|
{
|
||||||
struct list_head *pos;
|
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->rename_list);
|
||||||
uc_mgr_free_dev_name_list(&verb->remove_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 */
|
/* normalize device names to remove spaces per use-case.h specification */
|
||||||
err = verb_normalize_device_names(uc_mgr, verb);
|
err = verb_normalize_device_names(uc_mgr, verb);
|
||||||
if (err < 0)
|
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);
|
err = verb_strip_single_device_index(verb);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle conflicting/supported lists */
|
/* 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).
|
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.
|
See the SND_USE_CASE_MOD constants like #SND_USE_CASE_MOD_ECHO_REF for the full list of known modifiers.
|
||||||
|
|
||||||
### Boot (alsactl)
|
### Boot (alsactl)
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,9 @@ struct use_case_device {
|
||||||
|
|
||||||
/* value list */
|
/* value list */
|
||||||
struct list_head 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