MAUI 8中使用NAudio混音录制音频出现失真问题求助
解决NAudio混音音频失真问题
核心问题分析
- Resampler被提前释放:代码中用
using包裹micResampler和speakerResampler,导致创建混音器后立即释放资源,后续录制过程无法正常处理音频数据。 - 扬声器数据流未关联缓冲提供者:
WasapiLoopbackCapture未绑定DataAvailable事件,扬声器音频数据从未写入speakerProvider,混音时数据异常。 - 音频叠加导致削波失真:两个音频流直接叠加可能超出float音频的幅值范围(-1.0到1.0),引发失真。
- 资源释放时机错误:提前释放关键处理组件,而非在录制停止时统一清理。
修复后的代码
private BufferedWaveProvider _micProvider; private BufferedWaveProvider _speakerProvider; private MediaFoundationResampler _micResampler; private MediaFoundationResampler _speakerResampler; private MixingSampleProvider _mixer; private bool _isRecording = false; public void StartRecording(int micIndex, int speakerIndex) { var devices = new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active); var selectedDevice = devices[speakerIndex]; _captureSpeaker = new WasapiLoopbackCapture(selectedDevice) { WaveFormat = new WaveFormat(48000, 32, 2) }; _captureSpeaker.DataAvailable += OnSpeakerDataAvailable; _captureSpeaker.RecordingStopped += (s, e) => { _captureSpeaker?.Dispose(); }; _waveIn = new WaveInEvent { DeviceNumber = micIndex, WaveFormat = new WaveFormat(48000, 32, 2) }; _waveIn.DataAvailable += OnDataAvailable; _waveIn.RecordingStopped += OnRecordingStopped; _micProvider = new BufferedWaveProvider(_waveIn.WaveFormat); _speakerProvider = new BufferedWaveProvider(_captureSpeaker.WaveFormat); // 设置缓冲时长避免数据溢出 _micProvider.BufferDuration = TimeSpan.FromSeconds(5); _speakerProvider.BufferDuration = TimeSpan.FromSeconds(5); var targetFormat = WaveFormat.CreateIeeeFloatWaveFormat(48000, 2); // 改为类成员变量,避免提前释放 _micResampler = new MediaFoundationResampler(_micProvider, targetFormat) { ResamplerQuality = 30 }; _speakerResampler = new MediaFoundationResampler(_speakerProvider, targetFormat) { ResamplerQuality = 30 }; // 调整音量并添加限幅器防止削波 var micSample = _micResampler.ToSampleProvider().VolumeSampleProvider(0.707f); var speakerSample = _speakerResampler.ToSampleProvider().VolumeSampleProvider(0.707f); var limitedMic = new SampleProviderConverters.LimitingSampleProvider(micSample); var limitedSpeaker = new SampleProviderConverters.LimitingSampleProvider(speakerSample); _mixer = new MixingSampleProvider(new[] { limitedMic, limitedSpeaker }); _writer = new WaveFileWriter(_outputFilePath, _mixer.WaveFormat); _isRecording = true; // 启动独立线程处理混音写入,避免阻塞录制流程 Task.Run(() => { var buffer = new float[_mixer.WaveFormat.SampleRate * _mixer.WaveFormat.Channels]; while (_isRecording && (read = _mixer.Read(buffer, 0, buffer.Length)) > 0) { _writer.WriteSamples(buffer, 0, read); } }); _waveIn.StartRecording(); _captureSpeaker.StartRecording(); } private void OnDataAvailable(object sender, WaveInEventArgs e) { _micProvider.AddSamples(e.Buffer, 0, e.BytesRecorded); } private void OnSpeakerDataAvailable(object sender, WaveInEventArgs e) { _speakerProvider.AddSamples(e.Buffer, 0, e.BytesRecorded); } private void OnRecordingStopped(object sender, StoppedEventArgs e) { _isRecording = false; _waveIn?.Dispose(); _captureSpeaker?.StopRecording(); _micResampler?.Dispose(); _speakerResampler?.Dispose(); _writer?.Flush(); _writer?.Dispose(); }
关键修改说明
- 移除Resampler的using块:将处理组件改为类成员,在录制停止时统一释放,保证录制全程资源可用。
- 绑定扬声器数据事件:新增
OnSpeakerDataAvailable方法,将扬声器音频数据写入缓冲提供者,确保混音器能获取到完整数据流。 - 添加音量控制与限幅器:通过
VolumeSampleProvider给每个音频流降3dB(0.707f),再用LimitingSampleProvider限制幅值范围,彻底解决削波失真。 - 独立线程处理混音写入:避免混音操作阻塞录制线程,保证音频数据实时处理。
- 优化缓冲设置:设置合理的缓冲时长,防止数据溢出或丢失。
内容的提问来源于stack exchange,提问作者shri
相关产品推荐
相关产品推荐

