0

0

C++如何读取系统音频输入设备列表?(PortAudio或WASAPI枚举)

穿越時空

穿越時空

发布时间:2026-02-21 09:17:27

|

402人浏览过

|

来源于php中文网

原创

portaudio 列出所有音频输入设备需先调用 pa_initialize() 确保成功,再用 pa_getdevicecount() 获取总数,循环调用 pa_getdeviceinfo(i) 并检查 info->maxinputchannels > 0 才视为有效输入设备,设备名取 info->name。

c++如何读取系统音频输入设备列表?(portaudio或wasapi枚举)

PortAudio 怎么列出所有音频输入设备

PortAudio 的 Pa_GetDeviceCount()Pa_GetDeviceInfo() 是唯一可靠入口,别想绕过它查系统注册表或调用底层 API —— 那样既跨平台失效,又容易漏掉虚拟设备(比如 VB-Cable、Voicemeeter 虚拟线)。

常见错误是只调用一次 Pa_Initialize() 就开始枚举,但实际必须确保初始化成功且未被提前终止;还有人忽略 PaDeviceInfo::maxInputChannels > 0 这个关键判断,把纯输出设备也当输入设备列出来。

  • 先调用 Pa_Initialize(),检查返回值是否为 paNoError
  • Pa_GetDeviceCount() 获取总数,再循环调用 Pa_GetDeviceInfo(i)
  • 对每个设备指针,检查 info->maxInputChannels > 0 才算有效输入设备
  • 设备名取 info->name,别依赖 info->hostApi 做分类——WASAPI 和 DirectSound 设备可能共享同一 host API ID
int deviceCount = Pa_GetDeviceCount();
for (int i = 0; i < deviceCount; ++i) {
    const PaDeviceInfo* info = Pa_GetDeviceInfo(i);
    if (info && info->maxInputChannels > 0) {
        printf("Input device %d: %s\n", i, info->name);
    }
}

WASAPI 枚举输入设备时为什么 GetDefaultAudioEndpoint 失败

IMMDeviceEnumerator::GetDefaultAudioEndpoint() 默认只返回“默认通信设备”或“默认播放/录制设备”,不是全量列表。想拿到全部输入设备,必须用 EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED),否则插着的麦克风都可能被过滤掉。

另一个高频坑是没正确设置 COM 初始化模式:WASAPI 必须在单线程公寓(STA)下初始化,CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) 缺一不可;用 COINIT_MULTITHREADED 会导致后续接口调用静默失败或返回 E_NOINTERFACE

立即学习C++免费学习笔记(深入)”;

科大讯飞-AI虚拟主播
科大讯飞-AI虚拟主播

科大讯飞推出的移动互联网智能交互平台,为开发者免费提供:涵盖语音能力增强型SDK,一站式人机智能语音交互解决方案,专业全面的移动应用分析;

下载
  • 必须先调用 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)
  • enumerator->EnumAudioEndpoints(eCapture, ...),别用 GetDefaultAudioEndpoint()
  • 遍历 IMMDeviceCollection 时,对每个 IMMDevice 调用 OpenPropertyStore(STGM_READ) 读取 PKEY_Device_FriendlyName
  • 注意释放 IMMDeviceIMMDeviceCollection,否则设备句柄泄漏

PortAudio 和 WASAPI 枚举结果不一致怎么办

PortAudio 在 Windows 上默认走 WASAPI 后端,但它的设备索引和 WASAPI 的 IMMDevice GUID 完全无关——PortAudio 内部做了抽象映射,且会跳过某些被标记为“禁用”或“未连接”的设备(哪怕物理上插着),而 WASAPI 的 DEVICE_STATE_UNPLUGGED 可能仍把它列出来。

更麻烦的是:PortAudio 的 Pa_GetDeviceInfo() 返回的采样率范围(defaultSampleRate)是 host 推荐值,不是设备真实能力;WASAPI 则可通过 IAudioClient::IsFormatSupported() 实际探测,但 PortAudio 不暴露这层。

  • 不要假设 PortAudio 索引 i 对应 WASAPI 第 i 个设备——它们没有对应关系
  • 若需精确匹配,只能靠设备名字符串粗略比对(info->name vs PKEY_Device_FriendlyName),但注意空格、括号、驱动附加后缀(如 “(VB-Audio Voicemeeter VAIO)”)
  • PortAudio 不报告设备是否支持独占模式,WASAPI 可通过 IAudioClient::GetSharedModeEnginePeriod() 判断,这点常被忽略

为什么枚举出来的设备名中文乱码或显示为英文

PortAudio 的 PaDeviceInfo::name 是 UTF-8 编码的 C 字符串,但 Windows 控制台默认用本地 ANSI(如 GBK)解码,直接 printf 会乱码;WASAPI 的 PKEY_Device_FriendlyName 是 UTF-16,用 wprintf 或转成 UTF-8 才能正常显示。

最容易被忽略的是:即使你用了 SetConsoleOutputCP(CP_UTF8),如果程序启动时控制台编码已被父进程锁定(比如从 VS 调试器启动),该设置可能无效。

  • PortAudio 设备名:用 MultiByteToWideChar(CP_UTF8, ...) 转宽字符再输出,或确保终端支持 UTF-8
  • WASAPI 设备名:用 wprintf(L"%s", friendlyName),别用 printf("%S", ...) —— 后者行为不可靠
  • 发布时别依赖控制台编码设置,优先写入日志文件并用 UTF-8 BOM 标记

设备名本身不含路径、权限或实时状态信息,它只是个静态标识符。真要区分同名设备(比如两个 USB 麦克风),得靠底层硬件 ID(WASAPI 的 PKEY_Device_InstanceId)或 PortAudio 的 hostApi + PaHostApiInfo::type 组合,但这部分 PortAudio 不对外暴露,只能自己 patch 或换 WASAPI。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

246

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

806

2024.03.01

printf用法大全
printf用法大全

php中文网为大家提供printf用法大全,以及其他printf函数的相关文章、相关下载资源以及各种相关课程,供大家免费下载体验。

76

2023.06.20

fprintf和printf的区别
fprintf和printf的区别

fprintf和printf的区别在于输出的目标不同,printf输出到标准输出流,而fprintf输出到指定的文件流。根据需要选择合适的函数来进行输出操作。更多关于fprintf和printf的相关文章详情请看本专题下面的文章。php中文网欢迎大家前来学习。

298

2023.11.28

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

198

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

307

2024.02.23

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

275

2025.06.11

c++标识符介绍
c++标识符介绍

本专题整合了c++标识符相关内容,阅读专题下面的文章了解更多详细内容。

160

2025.08.07

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

796

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 9.8万人学习

C 教程
C 教程

共75课时 | 4.9万人学习

C++教程
C++教程

共115课时 | 18.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号