在C#中实现向捕获设备(含虚拟捕获驱动)输入音频的可行方案及NAudio报错解决方案咨询
解决方案:用C#(NAudio)向虚拟捕获设备注入音频
咱先把你遇到的错误说透:你代码里用WasapiOut操作捕获设备,但WasapiOut是专门给渲染(播放)设备用的,Loopback模式是用来抓取渲染设备输出的,给捕获设备用肯定触发0x88890003错误——系统已经明确提示“Loopback标志设了,但设备是捕获设备不是渲染设备”。
好消息是:完全不用转C++,C#结合NAudio就能搞定你的需求,下面分两种常用场景给你具体方案:
场景1:用主流虚拟音频驱动(比如VB-Cable、Voicemeeter)
这类驱动会同时创建“虚拟渲染设备”和“虚拟捕获设备”——你把音频输出到虚拟渲染设备,对应的虚拟捕获设备就能捕获到这个音频,其他程序直接选择该捕获设备即可,这是最通用、最稳定的方案。
代码示例:
using NAudio.CoreAudioApi; using NAudio.Wave; using System.Threading; var enumerator = new MMDeviceEnumerator(); // 找到你的虚拟渲染设备(比如VB-Cable的输出设备,名字一般带"Cable"关键词) MMDevice virtualRenderDevice = enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active) .FirstOrDefault(d => d.FriendlyName.Contains("Cable")); if (virtualRenderDevice == null) { Console.WriteLine("未找到虚拟渲染设备,请先安装VB-Cable或同类虚拟音频驱动"); return; } // 加载要注入的音频(这里以本地音频文件为例,也可以替换为实时生成的WaveStream) using var audioStream = new AudioFileReader("your-target-audio.wav"); using var wasapiOut = new WasapiOut(virtualRenderDevice, AudioClientShareMode.Shared, false, 0); wasapiOut.Init(audioStream); wasapiOut.Play(); // 保持程序运行,直到音频播放完成 while (wasapiOut.PlaybackState == PlaybackState.Playing) { Thread.Sleep(100); }
运行这段代码后,打开微信、Zoom等需要使用音频的程序,选择对应的虚拟捕获设备,就能获取你注入的音频了。
场景2:直接向虚拟捕获设备注入音频(跳过渲染设备)
如果你的虚拟驱动支持直接向捕获端注入音频(大部分主流虚拟驱动都支持),可以用NAudio直接操作捕获设备的AudioClient,获取IAudioRenderClient来推送音频数据:
代码示例:
using NAudio.CoreAudioApi; using NAudio.CoreAudioApi.Interfaces; using NAudio.Wave; using System.Runtime.InteropServices; using System.Threading; var enumerator = new MMDeviceEnumerator(); // 获取目标虚拟捕获设备 MMDevice virtualCaptureDevice = enumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Multimedia); using var audioClient = virtualCaptureDevice.AudioClient; // 设置音频格式(需与设备兼容,这里以44.1kHz、16位、双声道为例) var waveFormat = new WaveFormat(44100, 16, 2); // 初始化AudioClient,注意使用Shared模式,不要设置Loopback标志 audioClient.Initialize( AudioClientShareMode.Shared, AudioClientStreamFlags.None, 0, 0, waveFormat, Guid.Empty); // 获取RenderClient,用于向捕获设备推送音频 var renderClient = audioClient.GetService<IAudioRenderClient>(); int bufferSize = audioClient.BufferSize; // 加载要注入的音频 using var audioFile = new AudioFileReader("your-target-audio.wav"); var audioBuffer = new byte[bufferSize * waveFormat.BlockAlign]; audioClient.Start(); while (audioFile.Read(audioBuffer, 0, audioBuffer.Length) > 0) { IntPtr bufferPtr; // 申请缓冲区 renderClient.GetBuffer(bufferSize, out bufferPtr); // 将音频数据复制到系统缓冲区 Marshal.Copy(audioBuffer, 0, bufferPtr, audioBuffer.Length); // 释放缓冲区,推送音频数据 renderClient.ReleaseBuffer(bufferSize, AudioClientBufferFlags.None); // 控制推送速度,避免音频播放过快 Thread.Sleep((int)(bufferSize / (double)waveFormat.SampleRate * 1000)); } audioClient.Stop();
关键提醒
- 物理麦克风这类真实捕获设备不支持注入音频,这是硬件层面的限制,和开发语言无关,必须使用虚拟捕获驱动才能实现需求。
- NAudio已经封装了几乎所有Core Audio API的功能,完全能覆盖你的需求,没必要转用C++。
内容的提问来源于stack exchange,提问作者Saliom




