1. 枚举USB音频设备
任务目标
编写一个C语言程序,枚举系统中所有USB音频设备(具有音频接口的USB设备),并打印每个设备的厂商ID、产品ID、设备描述符中的关键字段,以及配置描述符中音频接口的接口编号、接口类别和端点信息。
环境与依赖
本案例基于Linux系统,使用libusb-1.0库访问USB设备。安装依赖:
sudo apt-get install libusb-1.0-0-dev
核心实现
程序通过libusb遍历USB总线上的设备,对每个设备获取设备描述符和配置描述符,遍历配置描述符中的所有接口,筛选出bInterfaceClass == 0x01(音频类)的接口并打印相关信息。
#include <stdio.h>
#include <libusb-1.0/libusb.h>
static void print_audio_interface(const struct libusb_interface_descriptor *intf) {
printf(" Audio Interface:\n");
printf(" Interface Number: %d\n", intf->bInterfaceNumber);
printf(" Interface Class: 0x%02X\n", intf->bInterfaceClass);
printf(" Interface SubClass: 0x%02X\n", intf->bInterfaceSubClass);
printf(" Interface Protocol: 0x%02X\n", intf->bInterfaceProtocol);
printf(" Endpoint Count: %d\n", intf->bNumEndpoints);
for (int e = 0; e < intf->bNumEndpoints; e++) {
const struct libusb_endpoint_descriptor *ep = &intf->endpoint[e];
printf(" EP 0x%02X: Attr=0x%02X MaxPacket=%d Interval=%d\n",
ep->bEndpointAddress, ep->bmAttributes,
ep->wMaxPacketSize, ep->bInterval);
}
}
static void check_device(libusb_device *dev) {
struct libusb_device_descriptor desc;
int ret = libusb_get_device_descriptor(dev, &desc);
if (ret != 0) return;
struct libusb_config_descriptor *config = NULL;
ret = libusb_get_active_config_descriptor(dev, &config);
if (ret != 0) return;
int has_audio = 0;
for (int i = 0; i < config->bNumInterfaces; i++) {
const struct libusb_interface *iface = &config->interface[i];
for (int a = 0; a < iface->num_altsetting; a++) {
if (iface->altsetting[a].bInterfaceClass == 0x01) {
if (!has_audio) {
printf("USB Audio Device Found:\n");
printf(" VID=0x%04X PID=0x%04X\n", desc.idVendor, desc.idProduct);
printf(" Device Class: 0x%02X SubClass: 0x%02X Protocol: 0x%02X\n",
desc.bDeviceClass, desc.bDeviceSubClass, desc.bDeviceProtocol);
printf(" Manufacturer: 0x%02X Product: 0x%02X Serial: 0x%02X\n",
desc.iManufacturer, desc.iProduct, desc.iSerialNumber);
printf(" Config Value: %d NumInterfaces: %d\n",
config->bConfigurationValue, config->bNumInterfaces);
has_audio = 1;
}
print_audio_interface(&iface->altsetting[a]);
}
}
}
libusb_free_config_descriptor(config);
}
int main(void) {
libusb_device **devs;
ssize_t cnt;
int ret = libusb_init(NULL);
if (ret < 0) {
fprintf(stderr, "libusb_init failed: %d\n", ret);
return 1;
}
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0) {
fprintf(stderr, "libusb_get_device_list failed\n");
libusb_exit(NULL);
return 1;
}
printf("Scanning %zd USB devices...\n\n", cnt);
for (ssize_t i = 0; i < cnt; i++) {
check_device(devs[i]);
}
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return 0;
}
编译与运行
gcc -o usb_audio_enum usb_audio_enum.c $(pkg-config --cflags --libs libusb-1.0)
sudo ./usb_audio_enum
需要sudo权限访问USB设备信息。
验证方法
运行程序后,观察输出:
- 若系统连接了USB音频设备(如USB声卡、USB耳机),程序会打印该设备的VID/PID及音频接口详情。
- 若没有音频设备,程序仅显示扫描到的设备总数,不打印设备信息。
- 可通过
lsusb命令交叉验证:lsusb -t查看设备树,或lsusb -v -d 1234:5678(替换为实际VID/PID)查看详细描述符,对比程序输出的接口类别是否为0x01。
判定通过条件:程序能正确识别并打印至少一个USB音频设备的音频接口信息,且接口类别字段为0x01,端点信息与lsusb -v输出一致。