如何用C#实现客户端录制内录+麦克风音频并流式传输至服务器
C#实现系统音频+麦克风录制合并并流式传输到服务器
核心依赖
首先需要用到NAudio库(NuGet安装NAudio),它简化了Windows音频捕获、处理和流式操作,是实现无杂音音频处理的关键。
1. 客户端:双音频源捕获
要同时捕获系统内部声音(比如Spotify)和麦克风输入,必须确保两个捕获设备的音频格式完全一致(采样率、位深度、通道数),这是避免杂音的基础。
捕获系统内部声音
使用WasapiLoopbackCapture捕获系统输出音频:
var loopbackCapture = new WasapiLoopbackCapture(); // 统一设置为44.1kHz 16位立体声(可根据需求调整) loopbackCapture.WaveFormat = new WaveFormat(44100, 16, 2);
捕获麦克风输入
使用WasapiCapture(或WaveInEvent)捕获麦克风,强制匹配系统音频格式:
var micCapture = new WasapiCapture(); micCapture.WaveFormat = loopbackCapture.WaveFormat;
2. 无杂音音频合并
直接叠加原始音频字节会导致音量过载(破音),必须使用NAudio的MixingSampleProvider进行线性混合,它会自动处理音量平衡,避免异常音频问题:
// 将两个捕获设备转换为SampleProvider var loopbackProvider = loopbackCapture.ToSampleProvider(); var micProvider = micCapture.ToSampleProvider(); // 创建混合器并添加两个音频源 var mixer = new MixingSampleProvider(new[] { loopbackProvider, micProvider }); mixer.WaveFormat = loopbackCapture.WaveFormat; // 确保混合格式与输入一致
3. 客户端流式传输到服务器
使用TcpClient建立TCP连接,先发送音频格式信息(服务器需用此解析音频),再流式发送混合后的音频数据:
// 连接服务器 var client = new TcpClient("服务器IP", 8888); var stream = client.GetStream(); // 先发送WaveFormat的长度和字节数据 byte[] formatBytes = loopbackCapture.WaveFormat.ToByteArray(); stream.Write(BitConverter.GetBytes(formatBytes.Length), 0, 4); stream.Write(formatBytes, 0, formatBytes.Length); // 转换混合音频为WaveProvider,开始读取并发送 var waveProvider = mixer.ToWaveProvider(); byte[] buffer = new byte[4096]; int bytesRead; // 启动音频捕获 loopbackCapture.StartRecording(); micCapture.StartRecording(); while ((bytesRead = waveProvider.Read(buffer, 0, buffer.Length)) > 0) { try { stream.Write(buffer, 0, bytesRead); stream.Flush(); } catch (IOException) { // 处理连接断开情况 break; } } // 停止捕获并清理资源 loopbackCapture.StopRecording(); micCapture.StopRecording(); client.Close();
4. 服务器端接收与处理
服务器使用TcpListener监听连接,先接收音频格式,再持续接收音频数据(可保存为文件或实时处理):
var listener = new TcpListener(IPAddress.Any, 8888); listener.Start(); while (true) { var client = listener.AcceptTcpClient(); var stream = client.GetStream(); // 读取WaveFormat信息 byte[] lengthBuffer = new byte[4]; stream.Read(lengthBuffer, 0, 4); int formatLength = BitConverter.ToInt32(lengthBuffer, 0); byte[] formatBytes = new byte[formatLength]; stream.Read(formatBytes, 0, formatLength); var waveFormat = WaveFormat.FromByteArray(formatBytes); // 示例:将接收的音频保存为WAV文件 using (var writer = new WaveFileWriter("received_audio.wav", waveFormat)) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0) { writer.Write(buffer, 0, bytesRead); } } client.Close(); }
关键注意事项(避免杂音/异常)
- 强制统一音频格式:所有捕获设备和混合器必须使用相同的采样率、位深度和通道数,否则会出现音频错位、杂音。
- 使用SampleProvider混合:绝对不要手动叠加字节数组,
MixingSampleProvider会自动处理音频样本的线性混合,防止音量过载。 - 缓冲区大小适配:选择4096或8192字节的缓冲区,过小会导致卡顿,过大则增加延迟。
- 异常处理:捕获IO异常、设备断开等情况,避免程序崩溃。
内容的提问来源于stack exchange,提问作者Errant Wanderer
相关产品推荐
相关产品推荐

