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

WPF应用中使用微软标准组件实现16位PCM音频录播的技术问询

在WPF中实现16-bit PCM音频录制与播放的微软标准方案

你之前的判断完全没错——SoundPlayer、MediaElement和MediaPlayer确实不适合直接处理实时16-bit PCM字节数组块的录制与播放,它们更偏向于处理现成的音频文件,而非实时的原始音频数据。不过微软有专门的标准API能搞定你的需求,主要是基于Windows Runtime的媒体捕获与播放组件,WPF应用可以直接调用这些API,下面给你详细拆解实现思路:

一、录制16-bit PCM音频到字节数组块

我们可以用Windows.Media.Capture.MediaCapture这个类(属于Windows Runtime API,WPF项目里只要添加对Windows.winmd的引用就能用)来实现麦克风录制,只要把捕获格式配置成16-bit PCM,就能把捕获到的音频转成字节数组块。

核心实现步骤:

  • 先初始化MediaCapture,同时请求麦克风权限(这个是必须的,不然没法访问麦克风)。
  • 配置音频捕获的参数:指定采样率(比如常用的44100Hz)、通道数(单声道/立体声)、位深(16-bit),确保是标准的PCM格式。
  • 订阅音频数据捕获的事件,在回调里把原始的音频帧转换成16-bit PCM字节数组块,这样你就能拿到需要的实时数据了。

关键代码片段:

using Windows.Media.Capture;
using Windows.Media.MediaProperties;
using Windows.Storage.Streams;

private MediaCapture _mediaCapture;
private bool _isRecording = false;

public async Task InitializeCaptureAsync()
{
    _mediaCapture = new MediaCapture();
    var settings = new MediaCaptureInitializationSettings
    {
        StreamingCaptureMode = StreamingCaptureMode.Audio,
        AudioDeviceId = MediaCapture.GetDefaultAudioCaptureId(AudioDeviceRole.Default)
    };
    await _mediaCapture.InitializeAsync(settings);

    // 配置16-bit PCM格式:44100Hz采样率、单声道、16位深
    var audioEncodingProperties = AudioEncodingProperties.CreatePcm(44100, 1, 16);
    var effectDefinitions = MediaExtensionManager.GetAudioEffectDefinitions("AudioCaptureEffect");
    if (effectDefinitions.Any())
        _mediaCapture.AddAudioEffect(effectDefinitions[0]);

    // 启动音频帧读取器并订阅帧到达事件
    var reader = await _mediaCapture.CreateFrameReaderAsync(MediaFrameSourceKind.Audio);
    reader.FrameArrived += OnAudioFrameArrived;
    await reader.StartAsync();
    _isRecording = true;
}

private void OnAudioFrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
    using (var frame = sender.TryAcquireLatestFrame())
    {
        if (frame == null || !_isRecording) return;

        using (var audioBuffer = frame.AudioMediaFrame.Buffer)
        {
            byte[] pcmBytes = new byte[audioBuffer.Length];
            using (var stream = audioBuffer.AsStream())
            {
                stream.Read(pcmBytes, 0, pcmBytes.Length);
            }
            // 在这里处理你的PCM字节数组块——比如缓存、传输或者其他业务逻辑
        }
    }
}

二、播放16-bit PCM字节数组块

播放这块可以用Windows.Media.Playback.AudioGraph类,它专门用来处理实时音频流的播放,能直接把PCM字节数组块喂进去播放,完美匹配你的需求。

核心实现步骤:

  • 初始化AudioGraph,把输出设备设成默认扬声器。
  • 创建一个AudioFrameInputNode,这个节点就是用来注入PCM数据的入口。
  • 把16-bit PCM字节数组转换成AudioFrame,然后提交到AudioFrameInputNode,就能直接在扬声器播放了。

关键代码片段:

using Windows.Media.Playback;
using Windows.Media.Render;

private AudioGraph _audioGraph;
private AudioFrameInputNode _frameInputNode;

public async Task InitializePlaybackAsync()
{
    // 初始化AudioGraph
    var settings = new AudioGraphSettings(AudioRenderCategory.Media);
    var creationResult = await AudioGraph.CreateAsync(settings);
    if (creationResult.Status != AudioGraphCreationStatus.Success)
    {
        // 这里处理初始化失败的情况,比如提示用户音频设备不可用
        return;
    }
    _audioGraph = creationResult.Graph;

    // 创建默认扬声器的输出节点
    var outputNodeResult = await _audioGraph.CreateDeviceOutputNodeAsync();
    if (outputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
    {
        // 处理输出节点创建失败
        return;
    }

    // 配置输入格式,必须和录制的PCM格式完全一致
    var inputFormat = AudioEncodingProperties.CreatePcm(44100, 1, 16);
    _frameInputNode = _audioGraph.CreateFrameInputNode(inputFormat);
    _frameInputNode.AddOutgoingConnection(outputNodeResult.DeviceOutputNode);
    
    // 启动音频图开始播放
    _audioGraph.Start();
}

// 播放PCM字节数组块的方法
public void PlayPcmByteArray(byte[] pcmBytes)
{
    if (_frameInputNode == null || !_audioGraph.IsStarted) return;

    // 创建AudioFrame并填充PCM数据
    var audioFrame = new AudioFrame((uint)pcmBytes.Length);
    using (var buffer = audioFrame.LockBuffer(AudioBufferAccessMode.Write))
    using (var stream = buffer.CreateStream())
    {
        stream.Write(pcmBytes, 0, pcmBytes.Length);
    }

    // 提交音频帧到输入节点,开始播放
    _frameInputNode.AddFrame(audioFrame);
}

几个要注意的点

  • 确保你的WPF项目目标框架是.NET 6及以上,这样对Windows Runtime API的兼容性更好。
  • 如果是打包成MSIX的WPF应用,要在Package.appxmanifest里声明麦克风权限;如果是未打包的应用,要在运行时动态请求麦克风访问权限。
  • 录制和播放的音频参数必须完全一致(采样率、通道数、位深),不然播放的时候会出现杂音或者根本不出声的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:27:34