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

如何在Rust中捕获Linux(Pipewire/Alsa)下其他应用的播放音频?

在Linux(PipeWire/ALSA)下用Rust捕获应用播放音频的方案

要捕获Chrome等应用的播放音频,核心是要获取系统的音频输出监听流(而非麦克风输入),以下是针对PipeWire和ALSA环境的具体实现方案:

一、优先用PipeWire原生方案(推荐)

PipeWire本身支持直接捕获应用的音频流,无需额外创建回环设备,用官方Rust绑定pipewire-rs可以直接操作:

  1. 添加依赖
    在Cargo.toml中加入:
[dependencies]
pipewire = "0.7" # 请使用最新稳定版本
  1. 捕获默认输出监听流的示例代码
use pipewire::{
    context::Context,
    core::Core,
    stream::{Stream, StreamFlags},
    properties::Properties,
};
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    // 初始化PipeWire上下文与核心
    let context = Context::new()?;
    let core = Core::new(&context)?;
    let main_loop = pipewire::main_loop::MainLoop::new()?;
    let loop_handle = main_loop.handle();

    // 设置流属性:指定捕获输出监听流
    let props = Properties::new([
        ("media.class", "Audio/Sink/Media"),
        ("audio.position", "FL,FR"),
        ("stream.capture.monitor", "true"), // 关键:开启监听模式
    ]);

    // 创建音频捕获流
    let mut stream = Stream::new(&core, "app-audio-capture", &props)?;

    // 注册音频数据处理回调
    stream.add_listener_local()
        .process(move |stream| {
            let buffer = stream.dequeue_buffer().unwrap();
            // 这里的buffer就是捕获到的应用音频数据,格式为f32(可根据配置调整)
            let audio_samples = buffer.data::<f32>();
            // 在此处将数据传给你的可视化模块
            println!("捕获到 {} 个音频采样", audio_samples.len());
            stream.queue_buffer(buffer);
        })
        .register();

    // 连接流到PipeWire音频图
    stream.connect(None, StreamFlags::AUTOCONNECT | StreamFlags::MAP_BUFFERS, None)?;

    // 启动主循环持续捕获
    main_loop.run();

    Ok(())
}

二、ALSA回环设备方案(兼容传统ALSA环境)

如果需要基于ALSA实现,需先创建回环设备并路由音频:

  1. 加载ALSA回环模块
sudo modprobe snd-aloop
  1. 添加依赖
[dependencies]
alsa = "0.7"
  1. 捕获回环设备音频的示例代码
use alsa::{pcm, ValueOr};
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    // 打开ALSA回环捕获设备(子设备1是捕获端,子设备0是输出端)
    let pcm = pcm::PCM::new("hw:Loopback,1,0", pcm::Direction::Capture, false)?;
    
    // 配置音频参数:双声道、44100采样率、16位有符号整数
    let hwp = pcm::HwParams::any(&pcm)?;
    hwp.set_channels(2)?;
    hwp.set_rate(44100, ValueOr::Nearest)?;
    hwp.set_format(pcm::Format::s16())?;
    hwp.set_access(pcm::Access::RWInterleaved)?;
    pcm.set_hw_params(&hwp)?;

    let io = pcm.io_i16()?;
    let mut buffer = [0; 44100 * 2]; // 1秒长度的缓冲区

    loop {
        let captured_frames = io.readi(&mut buffer)?;
        // 处理捕获到的音频数据,传给可视化模块
        println!("捕获到 {} 帧音频", captured_frames);
    }
}
  1. 路由应用音频
    用pavucontrol工具,将Chrome的音频输出切换到Loopback设备,即可从捕获端拿到数据。

三、用你熟悉的cpal实现

cpal也能捕获监听流,只需找到正确的设备:

use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let host = cpal::default_host();
    // 枚举输入设备,找到名称含"Monitor"或"Loopback"的监听设备
    let target_device = host.input_devices()?
        .find(|device| {
            let device_name = device.name().unwrap_or_default();
            device_name.contains("Monitor") || device_name.contains("Loopback")
        })
        .ok_or("未找到音频监听设备")?;

    println!("使用设备:{}", target_device.name()?);
    let default_config = target_device.default_input_config()?;

    // 创建捕获流并处理数据
    let stream = target_device.build_input_stream(
        &default_config.into(),
        move |audio_data: &[f32], _| {
            // 此处处理音频数据,用于可视化
            println!("捕获到 {} 个采样", audio_data.len());
        },
        move |err| eprintln!("捕获错误:{}", err),
    )?;

    stream.play()?;
    loop {} // 保持程序运行
}

注意事项

  • 确保用户属于audio组,避免权限问题:sudo usermod -aG audio $USER
  • 用pavucontrol可以直观查看和调整音频路由,方便定位监听设备
  • 捕获到的音频数据格式(采样率、位深、通道数)需与可视化模块兼容,必要时做格式转换

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 07:07:42