简介基于微软虚拟音频设备示例MSVAD的虚拟声卡实现源码包面向Windows音频驱动开发学习者与底层编程爱好者旨在演示如何通过软件模拟创建虚拟音频设备并实现DirectSound、WASAPI/Core Audio等接口的对接。压缩包共91个文件以42个头文件和22个C源文件为主体辅以makefile、sources工程配置、htm说明文档及inf安装信息整体约132KB结构紧凑。已有829人浏览学习。代码覆盖WDM驱动模型、音频信号处理、多线程同步、设备模拟等关键环节并提供simple、pcmex、multstr、ac3、drmmult等多个示例子模块分别展示不同音频格式与功能扩展适合对照源码理解虚拟声卡从驱动到应用的完整链路也可作为二次开发的工程蓝本。1. virtual audio 虚拟声卡系统只认一块声卡但你的使用场景远不止一块做直播或者录网课的人应该都遇到过这个局面想让观众听到游戏背景音、你的声音还要放一首歌当垫乐但系统录音面板里只有“麦克风”一个输入可选。选麦克风电脑里播放的视频声音录不进去选“立体声混音”又把自己说话的声音丢了。virtual audio虚拟声卡解决的就是这件事——它在你本机的物理声卡之外用软件再虚拟出一整套“输入输出”音频设备让系统和应用以为你又插了一块能干活儿的声卡。于是你可以把系统声音送到虚拟输出把麦克风声音单独接进来再由录音软件从虚拟输入把它们收进来各路声音各走各路最后汇成一路输出。适合直播、在线会议、音乐制作甚至音频开发调试的人用核心价值就三个字可路由。这篇文章把它的原理、配置、常见坑和排查方法讲透让你照着做就能落地。2. 它到底是什么音频端点、驱动模型与三层路由2.1 系统怎么看待一块声卡音频端点与默认设备Windows 把声卡抽象成“端点Endpoint”每一个端点代表一个物理或虚拟的连接点。你打开“声音设置”看到的“扬声器Realtek Audio”是一个播放端点“麦克风Realtek Audio”是一个录制端点两者组成一组采集/回放能力。系统不关心声卡具体长什么样只关心有没有端点可用以及哪个端点被设为默认设备。虚拟声卡的本质就是安装一个驱动让系统列出额外的端点比如“CABLE Output”作为播放端点、“CABLE Input”作为录制端点。应用向“CABLE Output”播放声音驱动把这些音频数据在后台原样转发给“CABLE Input”于是录音软件从“CABLE Input”录到的就是应用播放的内容。这个转发动作发生在内核态驱动层对系统和应用完全透明。理解端点概念才能在后面配置时知道哪条声音走到了哪里。你改的默认播放设备只是改变“系统铃声和应用无指定设备时”的出口指向而录音软件里要单独选输入端点两者并不总是自动配对。很多人在这一步就翻车播放设成虚拟输出录音却还在用物理麦克风结果什么都录不到。2.2 虚拟声卡驱动在工作链路中的位置音频在 Windows 里至少要穿过三层应用层调用音频 APIMME、DirectSound、WASAPI、ASIO 等操作系统音频服务AudioSrv把数据路由到设备端点最后由驱动送到硬件或虚拟目标。虚拟声卡驱动工作在最底层它注册成一组内核端点看起来和物理声卡没有任何区别。常见的虚拟声卡方案有两类。一是内核驱动型这类方案的驱动在系统里挂一个设备节点使用上最接近真实硬件几乎所有应用都能直接识别稳定性较好二是用户态路由型由后台进程截获音频流并转发但个别应用可能认不到延迟也略高。日常做直播、录音建议选内核驱动型的成熟方案调试成本最低。这里需要知道一个关键点WASAPI 是 Windows 默认音频 API支持共享模式和独占模式。共享模式下系统做混音所有应用可同时播放独占模式下应用独享端点延迟更低但其他应用不能出声。虚拟声卡驱动同样受影响——如果你的录音软件用独占模式占用了虚拟端点那么其他应用就放不出声音这个现象别误以为是虚拟声卡坏了。2.3 选型先想清楚你要路由还是内录选择哪套虚拟声卡方案取决于你的核心需求我可以按实际用途大致分成三类。第一类是纯内录也就是把系统里正在播放的声音原样录下来。这种需求用回环能力就够了只需要一对播放/录制虚拟端点系统声音送到虚拟输出录音软件收虚拟输入链路最短、最不容易出问题。第二类是分流与混音比如直播时要让背景音乐不经过麦克风、又能让观众同时听到两者。这类需求要求虚拟声卡支持多端点或者可配合立体声混音通过软件把两路音频合成一路再推给直播软件配置上需要多花些心思。第三类是效果处理比如给麦克风挂电音、混响、EQ 机架。这类需求要求音频链路里能插入第三方效果插件一般会配合音频宿主软件使用需要虚拟声卡驱动的稳定性和低延迟表现都足够好否则实时处理时爆音会折磨到你怀疑人生。选型时先回答一个问题我到底要不要“分开控制每路声音”不需要就选最简方案需要就用支持多端点的中级以上方案。把这个想清楚后面的配置才不会越搞越乱。3. 从零配一个能用的虚拟声卡设备管理、端点配对与采样率3.1 安装后先做的事确认设备被系统认到装完虚拟声卡驱动第一件事不是打开录音软件而是先确认系统是否认到了新端点。很多人装完直接进软件选设备结果列表里找不到其实是驱动安装被系统拦截或者端点没有正确注册。按 Win X 打开设备管理器展开“音频输入和输出”应能看到新出现的播放端点和录制端点。如果端点没出现先在“声音设置”里点“管理声音设备”看“输出”和“输入”区域是否有未启用的设备。某些方案安装后设备默认禁用需要手动启用。想快速确认设备状态用 PowerShell 枚举更直观。打开 PowerShell 执行Get-PnpDevice -Class AudioEndpoint | Select-Object FriendlyName, Status, InstanceId | Format-Table -AutoSize这段命令的原理是查询系统里所有音频端点类设备FriendlyName 显示设备名称Status 显示当前状态InstanceId 则返回设备实例标识。执行后重点看 Status 是否为 OK以及 FriendlyName 是否包含虚拟声卡方案的标识名称。如果出现 Unknown 或 Error 状态说明驱动没正确加载需要检查安装过程是否有签名拦截。如果看到设备但名字不认得在设备管理器里右键查看“属性-详细信息-硬件 ID”对比驱动说明就能确认是否是目标设备。3.2 播放端点与录制端点配对设备确认后重点来了必须让“播放去哪”和“录音从哪来”形成一条闭环链路。物理声卡的播放和录像是天然一体虚拟声卡则拆成两个独立端点需要手动配对。我的做法是打开“声音设置”把“输出设备”选成虚拟输出的播放端点系统声音就进入虚拟链路了打开任意录音软件的声音输入设置选择虚拟输入的录制端点。此时录音软件录到的就是系统当前播放的声音。为了确认回环是否成功可以在放歌的同时看录音软件的输入电平表有没有跳动如果安静如鸡说明配对没做对。有一个容易被忽略的环节是“默认通信设备”。Windows 的“声音控制面板-播放”里有“默认设备”和“默认通信设备”两个概念语音通话应用默认走通信设备。如果你只改了默认设备而微信、QQ 通话用的是通信设备它们的声音就不会进虚拟链路。我一般把两者都设为同一个虚拟输出避免讲话时声音莫名消失。另外提醒一句“立体声混音”和虚拟声卡是两回事。立体声混音是部分物理声卡自带的内录能力能录系统声音但当录音软件要同时选两个输入时它就没办法虚拟声卡则能同时提供多个端点。能不用立体声混音就别用它的位置在“录制设备”里不少驱动默认还隐藏着需要右键显示禁用的设备才能看到。3.3 采样率、位深与缓冲不先设好后面全是玄学虚拟声卡最容易被人忽略却又最影响音质的是采样率和位深的统一。两个端点如果采样率不一致系统会强制重采样结果就是声音发闷、轻微加速或者偶尔爆音。音频界把这个叫“看不见的重采样损耗”听感上很难立刻察觉录完做后期才发现高频细节没了。我处理这类问题时的标准流程是先确认虚拟声卡驱动的设备格式上限再让所有相关设备统一成一个采样率。操作路径是“声音控制面板 → 播放/录制设备 → 属性 → 高级”在“默认格式”里选同一个采样率。比如我的物理声卡、虚拟声卡和录音软件全部设为 48kHz 24bit这是最通用的直播与视频录制组合。常用采样率配置可以参考采样率位深适用场景备注44100 Hz16bit音乐播放、CD 音质老方案默认偏保守48000 Hz24bit直播、视频录制、语音通话最通用推荐使用96000 Hz24bit混音后期、效果处理需要电脑性能足够另外缓冲大小也要关注。录音软件里通常有缓冲设置缓冲越小延迟越低但小到一定程度就会爆音缓冲越大越稳定但延迟会升高到无法接受。我的经验是从 256 样本起步烧录失败再往 512 调。如果是做直播建议优先保证不爆音延迟略高一点观众感知不到如果是自己弹唱录音延迟超过 20ms 就很难受了需要尽量压低缓冲。4. 实战多应用分流、内录与机架效果4.1 场景A把网页视频和麦克风同时送进录音软件这是最常见的用途录网课、录比赛解说、录游戏复盘需要电脑发出的一切声音和自己说话的声音同时被录到一条轨道。配置分三步。第一步把系统“输出设备”设为虚拟输出让所有通过扬声器出声的应用走虚拟链路比如浏览器、播放器、游戏客户端。第二步在声音设置里把“输入设备”保持为物理麦克风让麦克风这个独立输入节点不被虚拟链路占用。第三步打开录音软件音频输入选择“虚拟输入”此时软件收到的就是系统声音。但你会发现一个关键问题麦克风的声音没有进去。此时要在录音软件里打开“混音台”或“多输入”模式把“虚拟输入”轨和“麦克风”轨同时启用两轨声音才能混合进最终录音。不同录音软件的开关位置不一样通常在设置的声音输入区域找“同时录音多个设备”或者按 Shift 键多选输入设备。有个细节容易忽略麦克风也是通过系统音频端点工作的如果虚拟输出被设为默认播放设备个别应用在调用麦克风时可能也会被虚拟链路干扰造成回声或无声。稳妥做法是在录音软件里只把麦克风接到专用轨不要把系统输入设备改成虚拟输入。4.2 场景B让某几个应用单独走一条通道很多人以为虚拟声卡只能“要么全走虚拟要么全走物理”实际它能按应用分流只是要借助应用自身的音频输出设置。Windows 10/11 的声音设置里“高级声音选项-应用音量与设备首选项”可以对每个应用单独指定输出设备。操作方法是打开“设置-系统-声音-高级声音选项-应用音量与设备首选项”会列出当前正在播放声音的应用列表。对每个应用右下角都有输出设备下拉菜单。比如想让游戏声音走物理声卡自己耳朵听让音乐和语音走虚拟输出推给直播软件就在这个面板里分别指定。注意这个面板只对正在运行且使用系统默认音频 API 的应用生效。个别游戏使用独占模式会绕过应用级设置直接占住默认设备。遇到这种情况需要进游戏音频设置里手动改成 Windows 默认设备或关掉独占模式。还有一种做法同时开多个虚拟声卡端点比如方案支持两对独立的虚拟输入输出把音乐软件路由到第一对把语音路由到第二对录音软件分别接收。这样各路声音在系统层就彻底分离后面混音时不会互相干扰。这也是专业直播场景的常规思路。4.3 没有专业声卡时用代码做一个简易环回路由如果不想装驱动或者需要把声音处理后再转发Python 配合某开源音频库就能实现一个用户态环回路由。这类开源库把底层 PortAudio 接口封装成了 Python API可以在本机上读取一个输入设备的音频数据处理后写入另一个输出设备。下面这段代码实现的是从默认麦克风采集声音混入一个来自播放设备捕获到的系统声音把混音结果送入扬声器输出。这在思路上就是虚拟声卡的分流雏形。import sounddevice as sd import numpy as np # 这里的参数按实际设备索引调整先用 sd.query_devices() 查看 input_mic 0 output_speaker 3 sample_rate 48000 block_size 256 def callback(indata, outdata, frames, time, status): # indata 形状为 (frames, 1) 的麦克风信号 # 模拟混入一条固定增益的系统音频流 system_ref np.zeros_like(indata) # 接入真实系统源时替换为实际数据 outdata[:] indata * 0.8 system_ref * 0.6 with sd.Stream(device(input_mic, output_speaker), sampleratesample_rate, blocksizeblock_size, callbackcallback): print(输入 CtrlC 停止) while True: sd.sleep(1000)代码逻辑很直白sd.Stream 同时打开输入和输出设备callback 每处理一个数据块就执行一次回调。indata 是麦克风采集到的样本块outdata 是准备送给扬声器的样本块。我们把麦克风信号乘以 0.8 的增益再叠加上一路模拟的系统参考信号乘以 0.6完成最简单的混音。需要注意参数含义device 元组的两个数字分别对应输入和输出设备的索引用 sd.query_devices() 可以先查询本机设备列表确认samplerate 要设成两端设备都支持的采样率否则回调会报错blocksize 是每次回调处理的样本数这个值越小延迟越低但低于设备最低限制时会出现缓冲区溢出报错需要针对机器实际调。这个脚本本身不直接读系统声音做示例演示混音链路真正接入系统声音时要把 system_ref 替换成另一条输入流的数据这就要配合虚拟声卡驱动来实现了。4.4 给麦克风挂电音、混响机架效果虚拟声卡的另一个高频用法是接机架效果器。思路是麦克风物理输入先进效果宿主软件经过插件处理后输出到虚拟声卡的录制端点录音软件或直播软件再从这个虚拟端点取声音。这样观众听到的就是处理过的声音而你自己可以听到干声。具体连接是物理麦克风 → 音频宿主软件输入端宿主软件输出端 → 虚拟声卡录制端点录音软件输入选择虚拟声卡录制端点。关键在于宿主软件音频设备设置里要选对输入和输出许多人在这一步选成了物理输出导致处理后的声音直接进了扬声器而不是虚拟链路直播软件里听到的全是干声白忙一场。如果出现“自己听到处理声、观众听到干声”的反向问题检查宿主软件的输出设备是否指向了虚拟端点。这个坑我踩过不止一次每换一个宿主软件都要重新核对它的音频设备路由因为它不会自动跟随 Windows 默认设备变化。机架效果器的延迟主要来自 ASIO 缓冲。如果宿主软件支持 ASIO 模式建议把缓冲设在 128256 样本之间既能保证实时效果又不会频繁爆音。如果用的是 Wave 模式延迟会大不少讲话时能感觉到明显的“滞后感”这在直播里非常影响体验。5. 避坑排查虚拟声卡最常见的五个翻车现场5.1 设备管理器里看不到新设备现象驱动安装完成后声音设置里找不到任何新的虚拟端点设备管理器也没有新增音频设备。原因多数情况是驱动没有签名或安装方式不对。Windows 64 位系统只加载有签名驱动的内核音频驱动部分方案需要手动进入“禁用驱动程序强制签名”模式才能装成功。解决重启电脑在启动画面时按 F8或使用高级启动选项进入“禁用驱动程序强制签名”模式再重新安装驱动。装完正常重启即可。另外某些方案安装后不能立即看到设备需要重启一次让服务生效所以装完重启再查设备。5.2 设置成默认后系统彻底没声音现象把默认播放设备设成虚拟输出后扬声器、耳机全部无声连系统提示音也没了。原因这其实是链路没打通。播放设备虽然指向虚拟输出但虚拟输出的另一端录制端点没有被任何应用读取数据就断在里面了。系统把声音送到虚拟驱动后驱动找不到下游消费者直接丢弃。解决打开任意录音软件把输入设备选为虚拟输入并开始录制让虚拟链路形成回路。如果暂时不想开录音软件在声音控制面板的“录制”选项卡里找到虚拟输入端点右键属性 → 监听勾选“侦听此设备”并在下方选择“扬声器”作为回放设备系统声音就能通过虚拟链路绕回扬声器。诊断时这招很管用但平时别开着否则会听到回声。5.3 录出来的声音有持续爆音和杂音现象录音软件录音时波形每隔一段就出现尖锐爆点人声像隔着一层沙子。原因绝大多数是采样率或位深不匹配。物理声卡是 44100Hz虚拟声卡是 48000Hz系统重采样时产生周期性失真或者录音软件缓冲太小驱动来不及取数。解决把所有参与链路的设备、包括应用程序设置里的音频选项统一切到 48kHz 24bit。录音软件里把缓冲从 256 调到 512 或 1024逐个试。如果爆音集中在刚打开某个应用时也可能是该应用独占模式抢占端点导致的关掉应用的独占模式或者把默认通信设备调整到正确的端点。5.4 延迟大得像在对讲机现象对着麦克风吹口气耳机里要过半秒才能听到唱歌时伴奏跟人声错位严重。原因延迟来源主要有三个音频缓冲太大、链路中经过了不必要的软件处理比如还挂着机架效果器但没在用、宿主软件的 Wave 模式造成额外等待。解决先检查宿主软件和录音软件缓冲调至 128256 样本。如果不需要效果处理临时关闭宿主软件直接让麦克风进虚拟端点延迟会立刻降下来。对于需要实时监听的场景尽量使用支持 ASIO 的虚拟方案或者给宿主软件安装通用 ASIO 驱动它的低延迟表现比系统默认 API 好很多。5.5 录音音量忽大忽小、伴奏人声比例不对现象录出来的声音人声和背景音乐比例在不断变化有时音乐压过人声有时几乎没人声或者整体音量忽高忽低。原因录音软件默认自动增益控制AGC在起作用它会根据输入音量自动调增益也可能是你没有在混音台里分别控制两条输入轨的音量系统擅自把两路信号做了动态压缩。解决在录音软件设置里关闭自动增益把增益改成固定值。混音台里给“虚拟输入”轨和“麦克风”轨分别设置音量经验值一般是从人声轨 0dB、音乐轨 -6dB 起步再根据实际听感微调。另外检查虚拟声卡驱动的混音界面看看有没有隐藏的总线增益设置把它固定到 0dB 不要让它自动浮动。6. 进阶用信号流验证延迟与稳定性别靠耳朵猜配置虚拟声卡最忌讳的就是凭感觉调。你觉得延迟高了调小缓冲结果爆音了你觉得声音闷改采样率结果系统重采样又引入了新问题。这些折腾其实可以用一组测量手段来定量验证核心是测量从播放到录制的环回延迟。环回延迟测量的思路很简单用播放端点放一段具有明显特征的参考信号同时从录制端点采回来通过计算两段信号的互相关峰值位置就得到精准延迟。这里我常用 Python 脚本快速完成import sounddevice as sd import numpy as np duration 3.0 sr 48000 t np.linspace(0, duration, int(sr * duration), endpointFalse) ref np.sin(2 * np.pi * 1000 * t) # 1kHz 正弦波可以作为参考信号 # 播放端点索引和录制端点索引按实际设备修改 playback_dev 4 record_dev 5 rec sd.playrec(ref, sampleratesr, device(playback_dev, record_dev), channels1) sd.wait() # 互相关估算延迟把播放信号和录制信号对齐 corr np.correlate(rec[:, 0], ref, modefull) lag np.argmax(corr) - (len(ref) - 1) delay_ms lag / sr * 1000 print(f环回延迟: {delay_ms:.2f} ms)这段代码的原理是sd.playrec 同时播放参考信号并录音完成后再用 numpy 的互相关找出录制信号相对播放信号的偏移量最后换算成毫秒。关键参数有三个playback_dev 和 record_dev 分别是播放端点和录制端点索引需要先用 sd.query_devices() 查出来channel 设为 1 表示单声道回环测试ref 信号的频率选 1kHz 是因为人声区域频段能直观听出是否清晰。这个方法的价值在于它能定量告诉你当前配置的真实延迟。如果你在虚拟链路前挂了机架效果也能用同样的方式对比宿主软件开与关两条链路的延迟差异。通过一次测量就能确定缓冲设多少满足你的使用场景而不是反复试错听出来的玄学结果。从那以后我每次换驱动、改采样率或者调整缓冲都会强制执行一步环回延迟测量把结果记录成表格哪套配置适合录音、哪套适合直播一目了然。这个习惯让我少走了很多弯路。希望这些拆解和验证方法能帮到你愿你在音频路由的路上一路顺畅。本文还有配套的精品资源点击获取