naudio / NAudio

Audio and MIDI library for .NET
MIT License
5.58k stars 1.1k forks source link

这个库可以实现同时录制麦克风和电脑音频吗 #1169

Open 1592363624 opened 4 months ago

1592363624 commented 4 months ago

这个库可以实现同时录制麦克风和电脑音频吗 我的代码总是有些问题

using System; using System.Threading.Tasks; using NAudio.Wave; using NAudio.Wave.SampleProviders;

namespace CallRecording.Models { public class Recorder { private readonly object _lockObject = new(); private readonly Logger _logger; private bool _isRecording; private string _outputFileName; private WaveFileWriter _waveFile; private WasapiLoopbackCapture _systemSource; private WaveInEvent _micSource; private MixingSampleProvider _mixer; private BufferedWaveProvider _systemBuffer; private BufferedWaveProvider _micBuffer;

    public Recorder(Logger logger)
    {
        _logger = logger;
    }

    // 开始录音
    public void StartRecording(string savePath, string softwareName)
    {
        lock (_lockObject)
        {
            if (_isRecording) return;

            // 生成输出文件名
            _outputFileName = Utils.GenerateFilename(savePath, softwareName);

            // 初始化系统声音捕获
            _systemSource = new WasapiLoopbackCapture();
            _systemSource.DataAvailable += OnSystemDataAvailable;
            _systemSource.RecordingStopped += OnRecordingStopped;

            // 初始化麦克风捕获
            _micSource = new WaveInEvent();
            _micSource.DataAvailable += OnMicDataAvailable;
            _micSource.RecordingStopped += OnRecordingStopped;

            // 初始化缓冲区
            _systemBuffer = new BufferedWaveProvider(_systemSource.WaveFormat);
            _micBuffer = new BufferedWaveProvider(_micSource.WaveFormat);

            // 将输入转换为相同的WaveFormat
            var systemSampleProvider = _systemBuffer.ToSampleProvider();
            var micSampleProvider = _micBuffer.ToSampleProvider();

            // 混音器
            _mixer = new MixingSampleProvider(new[] { systemSampleProvider, micSampleProvider })
            {
                ReadFully = true
            };

            // 创建WaveFileWriter,用于写入录音文件
            _waveFile = new WaveFileWriter(_outputFileName, _mixer.WaveFormat);

            // 开始录音
            _systemSource.StartRecording();
            _micSource.StartRecording();
            _isRecording = true;

            // 记录日志
            _logger.LogMessage("开始录音...", softwareName);

            // 启动一个后台任务来写入混音数据
            Task.Run(() => WriteMixedData());
        }
    }

    // 处理系统音频数据
    private void OnSystemDataAvailable(object sender, WaveInEventArgs e)
    {
        _systemBuffer.AddSamples(e.Buffer, 0, e.BytesRecorded);
    }

    // 处理麦克风音频数据
    private void OnMicDataAvailable(object sender, WaveInEventArgs e)
    {
        _micBuffer.AddSamples(e.Buffer, 0, e.BytesRecorded);
    }

    // 后台任务写入混音数据
    private void WriteMixedData()
    {
        var buffer = new float[_mixer.WaveFormat.SampleRate * _mixer.WaveFormat.Channels];
        while (_isRecording)
        {
            int samplesRead = _mixer.Read(buffer, 0, buffer.Length);
            if (samplesRead > 0)
            {
                lock (_lockObject)
                {
                    if (_waveFile != null)
                    {
                        _waveFile.WriteSamples(buffer, 0, samplesRead);
                        _waveFile.Flush();
                    }
                }
            }
        }
    }

    // 处理录音停止事件
    private void OnRecordingStopped(object sender, StoppedEventArgs e)
    {
        lock (_lockObject)
        {
            try
            {
                _systemSource?.Dispose();
                _micSource?.Dispose();
                _waveFile?.Dispose();
                _systemSource = null;
                _micSource = null;
                _waveFile = null;

                if (e.Exception != null)
                {
                    _logger.LogMessage($"录音停止时发生异常: {e.Exception.Message}", "录音器");
                }
                else
                {
                    _logger.LogMessage($"录音已保存到: {_outputFileName}", "录音器");
                }
            }
            catch (Exception ex)
            {
                _logger.LogMessage($"在处理录音停止事件时发生异常: {ex.Message}", "录音器");
            }
        }
    }

    // 停止录音
    public void StopRecording()
    {
        lock (_lockObject)
        {
            if (!_isRecording) return;

            try
            {
                _systemSource.StopRecording();
                _micSource.StopRecording();
                _logger.LogMessage("录音停止,文件已保存。", "录音器");
            }
            catch (Exception ex)
            {
                _logger.LogMessage($"停止录音时发生异常: {ex.Message}", "录音器");
            }

            _isRecording = false;
        }
    }

    // 检查是否正在录音
    public bool IsRecording()
    {
        lock (_lockObject)
        {
            return _isRecording;
        }
    }
}

// 用于将IWaveProvider转换为WaveProvider
public class WaveInProvider : IWaveProvider
{
    private readonly IWaveIn _source;
    private readonly WaveFormat _waveFormat;
    private readonly BufferedWaveProvider _bufferedWaveProvider;

    public WaveInProvider(IWaveIn source)
    {
        _source = source;
        _waveFormat = source.WaveFormat;
        _bufferedWaveProvider = new BufferedWaveProvider(_waveFormat)
        {
            BufferLength = 10 * 1024 * 1024 // 设置为10MB的缓冲区大小
        };
        _source.DataAvailable += (s, a) => _bufferedWaveProvider.AddSamples(a.Buffer, 0, a.BytesRecorded);
    }

    public WaveFormat WaveFormat => _waveFormat;

    public int Read(byte[] buffer, int offset, int count)
    {
        return _bufferedWaveProvider.Read(buffer, offset, count);
    }
}

}