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

如何通过Rust的windows-rs正确调用Core Audio API捕获Windows系统音频?

使用windows-rs调用Windows Core Audio捕获系统回环音频的正确步骤

你当前的代码遗漏了多个Core Audio回环捕获的关键步骤,以下是修正要点和完整实现:

关键遗漏点说明

  • 必须使用默认渲染设备:系统音频回环捕获依赖音频渲染设备(而非捕获设备)的IAudioClient接口,需要先通过MMDeviceEnumerator获取默认的渲染设备。
  • 初始化参数不能直接传0:Initialize的延迟参数需要先调用GetDevicePeriod获取设备支持的最小延迟值,否则可能导致初始化失败。
  • 未启动音频客户端:必须调用IAudioClient::Start()才能开始捕获音频流。
  • GetBuffer的正确调用与缓冲区释放:调用GetBuffer时需要正确传递指针参数,处理完数据后必须调用ReleaseBuffer释放缓冲区,否则会引发资源泄漏或死锁。
  • 释放COM分配的格式内存:GetMixFormat返回的WAVEFORMATEX是通过COM分配的,使用完毕后需要用CoTaskMemFree释放。
  • 循环中等待音频事件:空循环会占用大量CPU,应通过IAudioClient::GetEventHandle获取事件句柄,等待缓冲区可用后再处理数据。

完整修正代码

use windows::{
    core::Result,
    Win32::{
        Media::Audio::{
            IAudioCaptureClient, IAudioClient, IMMDevice, IMMDeviceEnumerator,
            AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, CLSCTX_ALL,
        },
        System::Com::{CoCreateInstance, CoInitializeEx, CoTaskMemFree, CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED},
        System::Threading::WaitForSingleObject,
        Foundation::HANDLE,
    },
};

fn capture_system_audio() -> Result<()> {
    unsafe {
        // 初始化COM环境
        CoInitializeEx(std::ptr::null_mut(), COINIT_APARTMENTTHREADED)?;

        // 创建MMDeviceEnumerator实例
        let enumerator: IMMDeviceEnumerator = CoCreateInstance(&MMDeviceEnumerator::CLSID, None, CLSCTX_INPROC_SERVER)?;

        // 获取默认音频渲染设备(回环捕获必须用渲染设备)
        let device: IMMDevice = enumerator.GetDefaultAudioEndpoint(0, 0)?;

        // 激活IAudioClient接口
        let audio_client: IAudioClient = device.Activate(IAudioClient::IID, CLSCTX_ALL, std::ptr::null_mut())?;

        // 获取设备支持的混合格式
        let wave_format_ptr = audio_client.GetMixFormat()?;
        let wave_format = &*wave_format_ptr;

        // 获取设备支持的最小延迟
        let mut default_device_period = 0;
        let mut minimum_device_period = 0;
        audio_client.GetDevicePeriod(&mut default_device_period, &mut minimum_device_period)?;

        // 初始化IAudioClient,启用回环模式
        audio_client.Initialize(
            AUDCLNT_SHAREMODE_SHARED,
            AUDCLNT_STREAMFLAGS_LOOPBACK,
            default_device_period,
            0,
            wave_format,
            None,
        )?;

        // 获取IAudioCaptureClient服务
        let capture_client: IAudioCaptureClient = audio_client.GetService()?;

        // 获取音频事件句柄,用于等待缓冲区可用
        let event_handle = audio_client.GetEventHandle()?;

        // 启动音频客户端
        audio_client.Start()?;

        loop {
            // 等待音频缓冲区可用
            WaitForSingleObject(HANDLE(event_handle), u32::MAX);

            // 获取缓冲区数据
            let mut data_ptr: *mut u8 = std::ptr::null_mut();
            let mut num_frames_available: u32 = 0;
            let mut flags: u32 = 0;
            capture_client.GetBuffer(&mut data_ptr, &mut num_frames_available, &mut flags, None, None)?;

            if !data_ptr.is_null() && num_frames_available > 0 {
                // 计算音频数据的字节数:帧数 × 每个帧的字节数(nBlockAlign)
                let data_size = num_frames_available as usize * wave_format.nBlockAlign as usize;
                // 将原始音频数据转换为切片(示例中仅打印数据长度,可根据格式处理PCM数据)
                let audio_data = std::slice::from_raw_parts(data_ptr, data_size);
                println!("捕获到音频数据:{}字节", audio_data.len());

                // 释放缓冲区
                capture_client.ReleaseBuffer(num_frames_available)?;
            }
        }

        // 注意:实际应用中需要处理退出逻辑,这里省略,退出时需要释放资源
        // CoTaskMemFree(wave_format_ptr as *mut _);
        // audio_client.Stop()?;
        // CoUninitialize();
    }
}

fn main() -> Result<()> {
    capture_system_audio()
}

额外说明

  • 音频格式(WAVEFORMATEX)包含了PCM数据的采样率、位深、声道数等信息,你可以根据这些信息将原始字节转换为具体的音频样本(例如16位单声道/立体声数据)。
  • 循环退出逻辑需要自行实现(比如监听控制台输入信号),否则程序会一直运行。
  • COM环境的初始化和清理要配对,示例中省略了退出时的CoUninitialize和格式内存释放,实际应用中必须添加。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 14:40:21