Итак, делюсь опытом.

Первым делом нужно узнать, по какому пути регистируются звуковушки. Для этого надо дать команду
udevadm monitor --kernel --property --subsystem-match=sound
и каким-то образом сделать так, чтобы карты переопределились. Для USB - легко. Просто переткнуть. Для PCI - нужно выгрузить и загрузить модуль ядра.
Модуль ядра можно узнать командой
lsmod | grep snd
У меня это snd_oxygen (для карточек Xonar DG).
Дальше выгружаю модуль:
sudo rmmod snd_oxygen
и получаю сообщение о том, что модуль занят и выгрузить его невозможно. Что может его занимать? Правильно, pulseaudio. Задача - убить pulseaudio и быстро дать команду rmmod. Быстро потому, что pulseaudio тут же перезагрузится заново.

sudo killall pulseaudio
sudo rmmod snd_oxygen
Модуль выгрузился.
Ну и заново его загружаем:
sudo modprobe snd_oxygen

В это время в отдельной вкладке терминала работает программка udevadm и она показала следующее:

monitor will print the received events for:
KERNEL - the kernel uevent

KERNEL[8590.844301] add     [b] /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0[/b] (sound)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0
SEQNUM=2827
SUBSYSTEM=sound

KERNEL[8590.844393] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/controlC0 (sound)
ACTION=add
DEVNAME=/dev/snd/controlC0
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/controlC0
MAJOR=116
MINOR=14
SEQNUM=2828
SUBSYSTEM=sound

KERNEL[8590.844418] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/pcmC0D0p (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC0D0p
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/pcmC0D0p
MAJOR=116
MINOR=15
SEQNUM=2829
SUBSYSTEM=sound

KERNEL[8590.844444] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/pcmC0D0c (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC0D0c
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/pcmC0D0c
MAJOR=116
MINOR=16
SEQNUM=2830
SUBSYSTEM=sound

KERNEL[8590.844513] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/pcmC0D1p (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC0D1p
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/pcmC0D1p
MAJOR=116
MINOR=17
SEQNUM=2831
SUBSYSTEM=sound

KERNEL[8590.845604] change   /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0 (sound)
ACTION=change
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0
SEQNUM=2832
SUBSYSTEM=sound

KERNEL[8590.847581] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/pcmC0D1c (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC0D1c
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card0/pcmC0D1c
MAJOR=116
MINOR=18
SEQNUM=2833
SUBSYSTEM=sound

KERNEL[8593.352313] add      [b]/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3[/b] (sound)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3
SEQNUM=2834
SUBSYSTEM=sound

KERNEL[8593.352423] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/controlC3 (sound)
ACTION=add
DEVNAME=/dev/snd/controlC3
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/controlC3
MAJOR=116
MINOR=19
SEQNUM=2835
SUBSYSTEM=sound

KERNEL[8593.352449] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/pcmC3D0p (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC3D0p
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/pcmC3D0p
MAJOR=116
MINOR=20
SEQNUM=2836
SUBSYSTEM=sound

KERNEL[8593.352496] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/pcmC3D0c (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC3D0c
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/pcmC3D0c
MAJOR=116
MINOR=21
SEQNUM=2837
SUBSYSTEM=sound

KERNEL[8593.352521] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/pcmC3D1p (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC3D1p
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/pcmC3D1p
MAJOR=116
MINOR=22
SEQNUM=2838
SUBSYSTEM=sound

KERNEL[8593.352568] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/pcmC3D1c (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC3D1c
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3/pcmC3D1c
MAJOR=116
MINOR=23
SEQNUM=2839
SUBSYSTEM=sound

KERNEL[8593.353777] change   /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3 (sound)
ACTION=change
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card3
SEQNUM=2840
SUBSYSTEM=sound

KERNEL[8595.856346] add     [b] /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4[/b] (sound)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4
SEQNUM=2841
SUBSYSTEM=sound

KERNEL[8595.856527] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/controlC4 (sound)
ACTION=add
DEVNAME=/dev/snd/controlC4
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/controlC4
MAJOR=116
MINOR=24
SEQNUM=2842
SUBSYSTEM=sound

KERNEL[8595.856550] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/pcmC4D0p (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC4D0p
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/pcmC4D0p
MAJOR=116
MINOR=25
SEQNUM=2843
SUBSYSTEM=sound

KERNEL[8595.856568] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/pcmC4D0c (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC4D0c
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/pcmC4D0c
MAJOR=116
MINOR=26
SEQNUM=2844
SUBSYSTEM=sound

KERNEL[8595.860227] change   /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4 (sound)
ACTION=change
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4
SEQNUM=2845
SUBSYSTEM=sound

KERNEL[8595.860262] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/pcmC4D1p (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC4D1p
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/pcmC4D1p
MAJOR=116
MINOR=27
SEQNUM=2846
SUBSYSTEM=sound

KERNEL[8595.860282] add      /devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/pcmC4D1c (sound)
ACTION=add
DEVNAME=/dev/snd/pcmC4D1c
DEVPATH=/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card4/pcmC4D1c
MAJOR=116
MINOR=28
SEQNUM=2847
SUBSYSTEM=sound

То, что нужно, я попытался выделить жирным, но, к сожалению, внутри кода это делать нельзя. Кому интересно - может запустить поиск по BB-code.

Следующий пункт - создаем файлик правил для udev:

sudo nano /etc/udev/rules.d/85-xonar-audio.rules
С содержимым:

SUBSYSTEM!="sound", GOTO="xonar_audio"
ACTION!="add", GOTO="xonar_audio"

DEVPATH=="/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:00.0/sound/card?", ATTR{id}="Xonar_DG_1"
DEVPATH=="/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:02.0/sound/card?", ATTR{id}="Xonar_DG_2"
DEVPATH=="/devices/pci0000:00/0000:00:1c.1/0000:04:00.0/0000:05:04.0/sound/card?", ATTR{id}="Xonar_DG_3"

LABEL="xonar_audio"
Скопированы пути и вместо card0, card1, card2... вставлено "card?". Потому как при загрузке драйвера карточке может присвоиться любой номер. В конце строки для карточки устанавливается айдишник. Использовать можно только буквы, цифры и знак подчеркивания.

Едем дальше.
Сохраняем файл и, для того, чтобы правила применились, опять же убиваем пульс, делаем rmmod и modprobe.
Теперь все выглядит вот так:

$ cat /proc/asound/cards

 0 [Xonar_DG_1     ]: CMI8786 - Xonar DG
                      C-Media Oxygen HD Audio at 0xc200, irq 17
 1 [NVidia_1       ]: HDA-Intel - HDA NVidia
                      HDA NVidia at 0xf7080000 irq 17
 2 [NVidia         ]: HDA-Intel - HDA NVidia
                      HDA NVidia at 0xf3080000 irq 17
 3 [Xonar_DG_2     ]: CMI8786 - Xonar DG
                      C-Media Oxygen HD Audio at 0xc100, irq 19
 4 [Xonar_DG_3     ]: CMI8786 - Xonar DG
                      C-Media Oxygen HD Audio at 0xc000, irq 17

Все. Каждой карте присвоен свой айдишник в зависимости от места на pci-шине.
Обращаться к каждой карточке можно с помощью hw:<ID>. Т.е. в моем случае:

aplay -D hw:Xonar_DG_1

Теперь совершенно без разницы, какой номер карте выдался. hw:0, hw:1, hw:2.... Можно обращаться по ID. А ID, в свою очередь привязан к PCI-шине.
Вот как-то так.

P.S.: Кстати, накатал в консоли сервера быстренько программку на Java, которая выдаст всю информацию по карточкам. И внутри самой Java в качестве name карты определяется как раз этот ID, который прописан в UDEV.
Выглядит примерно так: http://www.picshare.ru/uploads/170731/0V72ydusqP.jpg
Не красиво, конечно, но с этим по крайней мере уже можно поиграться. Поменять ID, сортировку в списке и т.д.
akorop
Э... а надо ли от пользователю требовать сделать выбор из неизвестно чего?
Ну а уж если предоставлять выбор, то надо предъявлять для выбора не динамически сложившиеся системные имена карт, а некие виртуальные имена, привязанные к PCI-адресам в порядке возрастания этих адресов (набор адресов можно получить, например, пропарсив вывод lspci).
Да, надо. Это не простые пользователи, а очень крупная российская компания. И им нужно иметь выбор, чтобы можно было поменять источник очень быстро.
Выглядит в веб-интерфейсе это примерно так:
http://www.picshare.ru/uploads/170720/bu0EeDF323.jpg
akorop
nafanja
карты то одинаковые
А дальше надо соорудить скрипт, который на основании этих данных будет запускать три программы захвата, указывая им alsa-адреса, сложившиеся при этой загрузке.
Не совсем так просто. На сервере стоит написанное мной ПО (демон), который занимается трансляциями.
Пользователь при настройке выбирает с какой звуковой карты какой канал транслировать. Т.е. можно, например, с третьей карты транслировать в сеть на IP первого канала. Штука в том, чтобы эта же конфигурация осталась после перезагрузки. Она и остается, только карты тусуются.
Поэтому скриптами не обойдешься.
ПО написано на Java. Там есть функция, которая возвращает Mixer.Info. Там никакой информации для жесткой привязки к карте нет. Из этой информации я выдираю только номер карты (hw:0, hw:1, hw:2) и с нее захватываю. Так как из программы не достучаться до жесткой привязки, приходится думать, как это сделать через драйвер.

Но за информацию спасибо. В UDEV вроде бы в правилах прописываются как раз числа из пути к файлу: /sys/bus/pci/devices/0000:00:14.2/sound/. Вроде бы это номер шины PCI. Попробую соорудить правила.
1. Это трансляционный сервер, который получает три радиотрансляции, захватывает их через звуковые карты, конвертит в mp3 и вещает в сеть. Задача состоит в том, чтобы сделать его фактически автономным. Поставить куда-нибудь и забыть. Если вдруг ему вздумается перезагрузиться, то он должен поднять вещание в том же порядке, что и было. Поэтому идеальный вариант, если он не будет перезагружаться. Но возможно все, в том числе и сбои питания.
2. Даже не представляю, какое и почему это вдруг оказалось неподходящим.
3. Да. Здесь видимо только UDEV. Только непонятно как.
Ребят, та же самая беда. Извините за некропостинг.
Три идентичных устройства. На всякий случай (на вопрос "зачем?") - идет захват, конвертирование и вещание мультикастом сразу трех каналов трансляции радиовещания.
Модуль ядра snd_ca0106.
При перезагрузке тусуются в произвольном порядке, естественно. Раздел "Ordering multiple cards of the same type" читал. Pid и Vid нет у карты. Советуют через правила udev, но я вообще не представляю, как это делается. Насколько я понял, там надо в рабочий комп втыкать устройство и смотреть по dmesg, какой ему id выдался. И к этому id привязываться. Но беда в том, что это не USB-устройства, а PCI. В рабочий комп не воткнешь. Да и нахожусь я от этого компьютера за тысячу километров.
Помогите, пожалуйста. Как решить эту проблему?