从 ALSA USB 硬件设备获取 USB 设备文件路径

问题描述 投票:0回答:1

我目前正在开发一个 Rust 库/CLI/UI,用于管理 Focusrite Scarlett USB 音频设备特别是在 Linux 上。这些设备通常有许多不同的内部设置(我的 18i8 有近 300 个单独的控件),所以我试图在我的设计中考虑所有这些,以便用户可以轻松更改路由配置、输入/输出/混合增益、静音切换等

值得庆幸的是,Linux 已经通过一些 modprobe 配置和最新的内核支持这些设备:

/etc/modprobe.d/scarlett.conf

options snd_usb_audio vid=0x1235 pid=0x8214 device_setup=1

对于不同的型号和可能不同的主要硬件版本,需要将上述值设置为不同的 USB 产品 ID,以启用对这些设备的支持。

我现在已经学习 ALSA API 了几周了,我学到了很多东西:

  1. 有人用 C 语言编写了 a GTK4 UI 来管理 Scarlett 设备,我基本上已经阅读了整个代码库,尽管很痛苦,我还是能够弄清楚它到底在做什么/正在使用哪些 ALSA API .
  2. ALSA 文档充其量是糟糕的,所以在这个项目之后,我将撰写博客文章来描述我的困境并解释其中的微妙之处,并尝试回馈 ALSA 文档,以节省其他人几天/几周/几个月的时间。生活试图弄清楚这些事情。
  3. ALSA 用户空间库通常是简单的内核系统调用的类型定义,这意味着对于
    snd_ctl_t
    snd_hctl_t
    snd_mixer_t
    API 之类的东西,用户空间中基本上没有代码。所有结构都是不透明的,函数(系统调用)与这些结构引用一起使用来获取详细信息。内核对内存进行了一些魔法并将其提供给用户空间。
  4. 值得庆幸的是,勇敢而慷慨的灵魂已将大部分 ALSA API 移植到 Rust。我还将为此项目提供文档,以帮助其他人。

无论如何,这就是我的困境:我可以列出 ALSA 设备并迭代它们,通过

snd_ctl_card_info_t
我可以获得一些有用的属性,例如:

  • name
    :思嘉 18i8 USB
  • id
    :USB
  • longname
    :Focusrite Scarlett 18i8 USB,USB-0000:00:14.0-2.2,高速
  • mixername
    :USB 混音器
  • components
    :USB1235:8214
  • driver
    :USB 音频

但是,这似乎是我可以从可用 API 中获得的“最”的。我可以通过从 components 字段中的 USB 供应商/产品 ID 中提取模型类型来获取模型类型,并且我可以通过解析

longname
来找到实际的 USB 句柄,但是:
可能连接了多个具有相同 USB 供应商/产品 ID 的设备:这是将设备链接在一起以添加输入/输出的常用技术。

我担心提取
    usb-*
  1. slug 和 USB 供应商/产品 ID 的
  2. 稳定性
  3. ,也许这可能会随着内核版本的变化而变得无效。 我需要
    识别
    每个设备,希望有某种序列号,以便卡A(18i8)的配置永远不会无意中应用于卡B(18i8),并且我假设有某种USB设备包含每个设备的序列号的字段。
  4. 因此,是否有一个 Linux API 可以让我从某种 ALSA 句柄获取 USB 设备文件?
  5. 或者,我是否可能缺少某些东西可以从 ALSA API 中获取序列号?

编辑

:我可以通过
lsusb

找到序列号,字段名称是iSerial

$ sudo lsusb -d 1235:8214 -vv | grep iSerial
  iSerial          2 4K1A0P443EPEW7
似乎我需要 

root
 才能获取实际的字段值,但我可以通过在 
udev

规则中向我的用户授予设备权限来解决此问题。如果我只能从 ALSA API 获取稳定的 USB 设备路径,那么我可以使用

libusb
或其他 API 来提取
iSerial
字段。
    
使用卡片的索引,由 

snd_ctl_card_info_get_card
linux usb alsa
1个回答
0
投票
/dev/snd/controlC⟨idx⟩

设备节点(以及

/dev/snd/
中与该卡关联的其他设备节点)名称中的数字。由此,您可以获取sysfs树中的相应节点,并遍历父节点链以获取您想要的任何标识符;直接打开
/sys
下的文件或通过 udev 来打开文件。
下面是使用 PyALSA 和 GUdev 绑定到 Python 的演示,但您应该能够使用绑定到 ALSA (libasound) 和 udev (libudev 或 GUdev) 的任何语言编写类似的东西。
#!/usr/bin/env python3
import gi
gi.require_version('GUdev', '1.0')
from gi.repository import GUdev
from pyalsa import alsacard

client = GUdev.Client()

for index in alsacard.card_list():
    print(f'index={index!r} longname={alsacard.card_get_longname(index)!r}')

    device = client.query_by_subsystem_and_name('sound', 'controlC' + str(index))
    usb_device = device.get_parent_with_subsystem('usb', 'usb_device')
    if not usb_device:
        print('    seems not to be an USB device')
        continue

    vidpid = f'''{
        usb_device.get_sysfs_attr('idVendor')
    }:{
        usb_device.get_sysfs_attr('idProduct')
    }'''
    serial = usb_device.get_sysfs_attr('serial')

    print(f'    VID:PID={vidpid} serial={serial!r}')

© www.soinside.com 2019 - 2024. All rights reserved.