You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于NAudio的ASIO同时录音与播放实现需求

用ASIO实现低延迟音频录制+实时监听(基于NAudio)

嘿,刚好我之前做过类似的ASIO低延迟实时监听功能,用NAudio就能搞定!核心就是把asio_DataAvailable回调里的浮点音频数据转换成BufferedWaveProvider能识别的PCM字节数据,然后喂给播放设备就行。给你一步步拆解:

1. 准备工作

首先确保你已经通过NuGet安装了NAudio包——它自带完整的ASIO支持,不用额外依赖。

2. 核心代码实现

定义全局变量

先声明需要用到的ASIO设备、缓冲提供者和播放组件:

private AsioOut _asioDevice;
private BufferedWaveProvider _audioBuffer;
private WaveOutEvent _waveOutPlayer;
private WaveFormat _targetAudioFormat;

初始化设备与缓冲区

这里我们先选择ASIO设备,设置匹配的音频格式(尽量和ASIO硬件格式一致,避免额外转换延迟),然后启动捕获和播放:

// 列出所有可用ASIO驱动,也可以做个下拉框让用户选择
var asioDrivers = AsioOut.GetDriverNames();
if (asioDrivers.Length == 0)
{
    throw new InvalidOperationException("未检测到ASIO设备,请安装对应ASIO驱动");
}

// 初始化ASIO设备
_asioDevice = new AsioOut(asioDrivers[0]);

// 设置目标音频格式:示例用44.1kHz、16位、立体声,根据你的硬件调整
_targetAudioFormat = new WaveFormat(44100, 16, 2);

// 初始化缓冲提供者:设置2秒缓冲区平衡延迟与稳定性,溢出时自动丢弃旧数据
_audioBuffer = new BufferedWaveProvider(_targetAudioFormat);
_audioBuffer.BufferDuration = TimeSpan.FromSeconds(2);
_audioBuffer.DiscardOnBufferOverflow = true;

// 初始化播放设备并关联缓冲区
_waveOutPlayer = new WaveOutEvent();
_waveOutPlayer.Init(_audioBuffer);

// 绑定ASIO数据回调事件
_asioDevice.AudioAvailable += Asio_DataAvailable;

// 启动ASIO捕获和实时播放
_asioDevice.Play();
_waveOutPlayer.Play();

处理ASIO数据回调

这是最关键的一步:ASIO提供的是非交错的浮点采样数据(每个通道的采样连续存储),我们需要转换成PCM标准的交错格式,再写入BufferedWaveProvider:

private void Asio_DataAvailable(object sender, AsioAudioAvailableEventArgs e)
{
    // 计算输出缓冲区大小:采样数 × 通道数 × 单采样字节数(16位是2字节)
    int bufferSize = e.SamplesPerBuffer * _targetAudioFormat.Channels * (_targetAudioFormat.BitsPerSample / 8);
    byte[] outputBuffer = new byte[bufferSize];
    
    int outputIndex = 0;
    for (int sampleIdx = 0; sampleIdx < e.SamplesPerBuffer; sampleIdx++)
    {
        // 遍历每个通道,将浮点采样转成16位PCM并交错写入
        for (int channelIdx = 0; channelIdx < _targetAudioFormat.Channels; channelIdx++)
        {
            // 获取当前通道的浮点采样值(范围[-1,1])
            float floatSample = e.WaveBuffer[channelIdx * e.SamplesPerBuffer + sampleIdx];
            // 限制值范围,防止溢出失真
            floatSample = Math.Clamp(floatSample, -1f, 1f);
            // 转换成16位整数
            short intSample = (short)(floatSample * short.MaxValue);
            // 按小端模式写入字节数组
            outputBuffer[outputIndex++] = (byte)(intSample & 0xFF);
            outputBuffer[outputIndex++] = (byte)(intSample >> 8);
        }
    }
    
    // 将转换好的PCM数据写入缓冲提供者,供播放设备读取
    _audioBuffer.AddSamples(outputBuffer, 0, outputBuffer.Length);
}

资源清理

记得在程序退出或停止功能时释放资源,避免内存泄漏:

private void CleanupAudioResources()
{
    _asioDevice?.Stop();
    _asioDevice?.Dispose();
    _waveOutPlayer?.Stop();
    _waveOutPlayer?.Dispose();
}

3. 关键注意事项

  • 格式匹配优先:尽量让ASIO设备的采样率、通道数和你设置的_targetAudioFormat完全一致,若必须转换可使用NAudio的WaveFormatConversionStream,但会增加额外延迟。
  • 调整缓冲区大小:ASIO硬件缓冲区越小,延迟越低,但系统负载越高,容易出现爆音;BufferedWaveProvider的缓冲区建议设为1-2秒,平衡延迟和播放稳定性。
  • ASIO路由设置:部分消费级声卡的ASIO驱动需要手动设置输入输出路由,确保输入信号能被正确捕获并输出到监听设备。

内容的提问来源于stack exchange,提问作者Mnaukal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:00:10