C/C++ 获取 linux 的所有 USB声卡ID及其信息

  • 使用 `popen()` 函数
  • 参考1
  • 参考2

在 Linux 下,要获取 USB 声卡的 ID 和名称信息,通常你需要结合多个系统命令和接口,因为 C/C++ 标准库本身并不直接提供这样的功能。下面我将给出一个大致的方向,展示如何通过执行系统命令或使用 Linux 特有的库来实现这一目标。

使用 popen() 函数

在 Linux 中,popen 函数可以用来执行外部命令并捕获其输出,但它本身并不直接提供解析 USB 设备信息(如声卡 ID 和名称)的功能。通常,USB 声卡的 ID 可以通过 lsusb 命令获取,而声卡的名称则可能涉及到 ALSA(Advanced Linux Sound Architecture)的配置。

下面是一个使用 popen 来执行 lsusb 命令并尝试从中提取 USB 声卡信息的 C++ 示例。但请注意,直接通过 lsusb 的输出来准确识别声卡可能不是最可靠的方法,因为 lsusb 提供的是 USB 设备的通用信息,而声卡的名称和具体配置可能还需要通过 ALSA 的接口来查询。
也可以使用其他shell命令,例如rk3588上使用cat /proc/asound/cards | grep USB-Audio 获取USB声卡信息

#include 
#include 
#include 
#include 
#include 

std::vector<std::string> getUsbAudioDevices() {
    std::vector<std::string> devices;
    char buffer[1024];
    //FILE* pipe = popen("cat /proc/asound/cards | grep USB-Audio", "r"); //rk3588上的声卡
    FILE* pipe = popen("lsusb | grep -i audio", "r"); 
    if (!pipe) {
        std::cerr << "popen() failed!" << std::endl;
        return devices;
    }

    while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
        // 移除末尾的换行符(如果有的话)
        size_t len = strlen(buffer);
        if (len > 0 && buffer[len - 1] == '\n') {
            buffer[len - 1] = '\0';
        }
        devices.push_back(buffer);
    }

    pclose(pipe);
    return devices;
}

int main() {
    auto devices = getUsbAudioDevices();
    for (const auto& device : devices) {
        std::cout << "USB Audio Device: " << device << std::endl;
    }

    // 注意:这里没有直接获取 USB 声卡的名称,因为那通常需要通过 ALSA 接口
    // 你可以进一步使用 ALSA 的库函数(如 snd_card_info_t 等)来获取声卡的详细信息

    return 0;
}

如果你需要获取声卡的名称(即 ALSA 中的“card name”),你将需要使用 ALSA 的库函数。这通常涉及到使用 libasound2-dev(在 Debian/Ubuntu 上)提供的库。下面是一个简化的示例,说明如何开始使用 ALSA 来查询声卡信息,但请注意,这不会直接显示 USB ID,而是 ALSA 级别的声卡信息:

// 注意:这个示例没有直接给出,因为它需要更复杂的设置和错误处理
// 你可以查看 ALSA 的文档和示例代码来了解如何使用 snd_card_info_t 等结构

通常,你需要结合使用 lsusb(或 libusb)来获取 USB 设备的物理信息,以及 ALSA 的库来获取音频设备的详细信息。由于 ALSA 并不直接暴露 USB 设备的 VID/PID,你可能需要一些额外的逻辑来将这些信息关联起来,比如通过比较设备的位置或其他标识符。然而,这种方法可能不是 100% 可靠的,因为 ALSA 和 USB 堆栈之间的映射可能不是直接且唯一的。

参考1

在C语言中,popen 函数是一个非常有用的函数,它允许你执行一个外部命令,并通过一个管道与该命令的输入输出进行交互。这个函数定义在 头文件中。

popen 函数的原型如下:

#include 

FILE *popen(const char *command, const char *type);
  • command 是要执行的命令字符串。
  • type 指定了是向命令写入数据("w"),还是从命令读取数据("r")。

如果 popen 调用成功,它返回一个指向 FILE 的指针,该指针可以像其他文件指针一样用于 freadfwritefprintffscanf 等函数。如果调用失败,则返回 NULL

使用完 popen 返回的文件指针后,你应该使用 pclose 函数来关闭它,并等待命令执行完毕。pclose 的原型如下:

#include 

int pclose(FILE *stream);

pclose 函数会关闭由 popen 打开的管道,并等待命令执行完成。它会返回命令的退出状态,类似于 waitpid 函数的返回值。

以下是一个使用 popen 函数执行 ls 命令并读取输出的示例:

#include 
#include 

int main() {
    FILE *fp;
    char path[1035];

    // 执行 ls 命令并读取其输出
    fp = popen("ls -l", "r");
    if (fp == NULL) {
        printf("Failed to run command\n");
        exit(1);
    }

    // 读取命令的输出
    while (fgets(path, sizeof(path)-1, fp) != NULL) {
        printf("%s", path);
    }

    // 关闭管道并等待命令执行完毕
    pclose(fp);

    return 0;
}

然而,如果你想要获取 USB 声卡的 ID 和名称,并且假设这些信息可以通过某个命令(如 lsusb)的输出间接获得,你需要解析该命令的输出以找到相关的行。这通常涉及到字符串处理和可能的模式匹配。

请注意,lsusb 命令的输出格式可能会根据系统和安装的 lsusb 版本而有所不同,因此你可能需要编写一些灵活的代码来解析输出。此外,USB 声卡的名称(即 ALSA 中的声卡名称)通常不会直接通过 lsusb 显示,而是需要通过 ALSA 的 API 来查询。

参考2

在C语言中,fgets 函数用于从指定的文件流(FILE *)中读取一行数据,并将其存储在提供的字符数组中。这个函数非常有用,因为它能够自动在读取的字符串末尾添加一个空字符('\0')来标记字符串的结束,并且它还允许你指定读取的最大字符数,从而防止缓冲区溢出。

fgets 函数的原型定义在 头文件中,如下所示:

char *fgets(char *str, int n, FILE *stream);
  • str 是指向字符数组的指针,用于存储读取的字符串。
  • n 是要读取的最大字符数(包括最后的空字符)。
  • stream 是指向 FILE 对象的指针,表示要从中读取数据的文件流。

如果成功,fgets 将返回一个指向 str 的指针;如果到达文件末尾(EOF)或发生错误,它将返回 NULL。但是,请注意,如果到达文件末尾前已经读取了 n-1 个字符(并且第 n 个位置被设置为 '\0'),则 fgets 也会返回指向 str 的非空指针,即使它没有读取整行。

以下是一个使用 fgets 函数的示例,它从标准输入读取一行文本:

#include 

int main() {
    char buffer[100];

    printf("Enter a line of text: ");
    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        // fgets 会在字符串末尾添加一个 '\0',所以我们可以直接打印它
        printf("You entered: %s", buffer);

        // 注意:如果输入的文本长度超过了 buffer 的大小减一(因为还要存储 '\0'),
        // 那么 fgets 只会读取 buffer 大小减一个字符,并添加 '\0'。
        // 这意味着,如果输入的文本很长,它可能会被截断。
    } else {
        // fgets 返回 NULL 通常表示发生了错误或到达了文件末尾(对于 stdin 来说不太可能)
        printf("An error occurred or EOF reached.\n");
    }

    return 0;
}

请注意,由于 fgets 会保留换行符(如果它存在于读取的字符串中),因此如果你不希望换行符出现在你的字符串中,你可能需要在处理之前将其移除。这可以通过检查字符串的最后一个字符是否为 '\n' 并将其替换为 '\0' 来实现。但是,请注意,如果字符串长度等于 n-1(即已经读取了最大数量的字符),则最后一个字符可能是换行符,也可能是输入的最后一个字符,具体取决于输入内容。

你可能感兴趣的:(c语言,c++,linux)