讲师中心 微信公众号

工具推荐

视频效率加速
剧云
剧云

中文短剧剧本制作平台

立刻MV
立刻MV

低成本歌曲 MV、视频生成

Seko
Seko

AI短剧一键生成成片

updream

一键生成高质量推广成片

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

千敏姑娘_7186

千敏姑娘_7186

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

|

502人浏览过

|

来源于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++免费学习笔记(深入)”;

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

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

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工具

更多
咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

相关专题

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

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

569

2023.09.22

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

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

1698

2024.03.01

printf用法大全
printf用法大全

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

948

2023.06.20

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

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

1029

2023.11.28

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

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

18020

2023.12.04

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

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

1263

2024.02.23

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

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

9670

2025.06.11

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

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

3842

2025.08.07

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

20

2026.11.12

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn