You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

NAudio同时录制系统扬声器与麦克风音频时生成无声音/失真文件的问题排查求助

NAudio同时录制系统扬声器与麦克风音频时生成无声音/失真文件的问题排查求助

看起来你已经基于NAudio搭好了同时录制系统音频和麦克风的框架,但遇到了录出来的文件无声音或失真的问题,我帮你梳理几个核心排查点和修正建议:


1. 先定位单个设备的录制问题

先排除是单个设备的问题,分别测试只录扬声器、只录麦克风:

  • 注释掉麦克风相关的代码(_micCapture_micBuffer、混音部分),只录扬声器,看生成的文件是否有声音;
  • 再注释掉扬声器部分,只录麦克风,确认麦克风录制是否正常。
    这样能快速判断是单个设备的录制逻辑有问题,还是混音环节出了问题。

2. 确保混音输入的格式完全统一

MixingSampleProvider要求所有输入的ISampleProvider必须具有完全相同的WaveFormat(采样率、声道数),哪怕你都转成了16000Hz单声道,也要确认细节:

  • WasapiLoopbackCapture的默认格式通常是32位浮点,而WaveInEvent(麦克风)默认是16位PCM,转成ISampleProvider后都是浮点格式,但要确保采样率、声道数完全一致;
  • 建议统一指定目标格式,避免格式不匹配导致混音失败:
// 统一目标格式:16000Hz、16位、单声道PCM
var targetWaveFormat = new WaveFormat(16000, 16, 1);

// 初始化麦克风时直接用目标格式,减少后续转换
_micCapture = new WaveInEvent();
_micCapture.WaveFormat = targetWaveFormat;

// 处理扬声器流:统一转成目标采样率和单声道
ISampleProvider speakerSample = _speakerBuffer.ToSampleProvider();
speakerSample = new WdlResamplingSampleProvider(speakerSample, targetWaveFormat.SampleRate);
if (speakerSample.WaveFormat.Channels > 1)
    speakerSample = speakerSample.ToMono();

// 处理麦克风流:因为已经用了目标格式,只需转成SampleProvider(如果需要转单声道的话)
ISampleProvider micSample = _micBuffer.ToSampleProvider();
// 如果麦克风设备本身是多声道,这里再转单声道
if (micSample.WaveFormat.Channels > 1)
    micSample = micSample.ToMono();

// 现在两个SampleProvider格式统一,再初始化混音器
_mixer = new MixingSampleProvider(new[] { speakerSample, micSample }) { ReadFully = true };

3. 确保选择了正确的音频设备

  • 对于扬声器录制:WasapiLoopbackCapture默认用系统默认播放设备,但如果你用AirPods、外接音箱等,可能需要主动指定当前正在使用的设备:
    // 获取当前默认的播放设备
    var defaultPlaybackDevice = WasapiLoopbackCapture.GetDefaultLoopbackCaptureDevice();
    _speakerCapture = new WasapiLoopbackCapture(defaultPlaybackDevice);
    
  • 对于麦克风录制:如果有多个麦克风设备,WaveInEvent默认用系统默认麦克风,你可以添加设备枚举逻辑,让用户选择,或者指定设备ID:
    // 枚举所有麦克风设备,选第一个可用的,或者让用户选择
    int targetMicDeviceId = 0; // 可以改成用户选择的ID
    _micCapture = new WaveInEvent { DeviceNumber = targetMicDeviceId, WaveFormat = targetWaveFormat };
    

4. 完善资源释放和异常处理

你的代码里有Dispose()调用,但没实现具体逻辑,而且用了空的catch块,会隐藏错误:

  • 实现Dispose方法,正确释放所有NAudio资源:
    private void Dispose()
    {
        _speakerCapture?.StopRecording();
        _micCapture?.StopRecording();
        
        _speakerCapture?.Dispose();
        _micCapture?.Dispose();
        _writer?.Dispose();
        
        _speakerBuffer = null;
        _micBuffer = null;
        _mixer = null;
    }
    
  • 把空的catch块改成记录异常,方便调试:
    _speakerCapture.DataAvailable += (s, a) => {
        try {
            _speakerBuffer?.AddSamples(a.Buffer, 0, a.BytesRecorded);
        } catch (Exception ex) {
            Console.WriteLine($"扬声器数据捕获错误: {ex.Message}\n{ex.StackTrace}");
        }
    };
    
    // 录制任务里的异常处理
    _recordingTask = Task.Run(() => {
        var buffer = new byte[finalProvider.WaveFormat.AverageBytesPerSecond / 10];
        while (_isRecording) {
            try {
                int read = finalProvider.Read(buffer, 0, buffer.Length);
                if (read > 0) _writer?.Write(buffer, 0, read);
                else Thread.Sleep(10);
            } catch (Exception ex) {
                Console.WriteLine($"录制写入错误: {ex.Message}\n{ex.StackTrace}");
                break; // 或者根据情况处理
            }
        }
        _writer?.Flush();
    });
    

5. 优化录制停止时的资源同步

StopRecording时,确保先停止捕获,等待录制任务完全结束,再释放资源,避免文件损坏:

public void StopRecording()
{
    if (!_isRecording) return;
    
    _isRecording = false;
    
    // 先停止捕获,避免新的数据进来
    try { _speakerCapture?.StopRecording(); }
    catch (Exception ex) { Console.WriteLine($"停止扬声器捕获错误: {ex.Message}"); }
    
    try { _micCapture?.StopRecording(); }
    catch (Exception ex) { Console.WriteLine($"停止麦克风捕获错误: {ex.Message}"); }
    
    // 等待录制任务完成,确保所有数据写入文件
    try {
        if (_recordingTask?.Wait(TimeSpan.FromSeconds(10)) == false)
            Console.WriteLine("录制任务超时,可能存在未写入的数据");
    } catch (Exception ex) { Console.WriteLine($"等待录制任务错误: {ex.Message}"); }
    
    // 最后释放资源
    Dispose();
}

按照这些步骤逐一排查,尤其是先单独测试单个设备的录制情况,应该能快速定位到无声音/失真的原因,解决问题后,你就能正常录制并混音系统音频和麦克风音频了。

火山引擎 最新活动