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

如何用Rust与pipewire-rs获取默认音视频输入输出设备?

获取PipeWire默认音视频设备的解决方案

PipeWire的默认设备信息并不直接暴露在Device对象中,而是需要通过Node对象(PipeWire中用于音频/视频流的端点实体)来识别。以下是两种可行的实现方案:


方案1:监听Node对象识别默认设备

PipeWire的默认音频输入、输出和视频输出对应特定的Node,这些Node会带有node.is-default=true的属性标识。你需要在Registry监听中添加对ObjectType::Node的处理,通过属性筛选出默认设备:

修改后的完整代码:

use std::thread;
use std::thread::JoinHandle;
use gtk::glib::ExitCode;
use pipewire::{Context, Core, MainLoop};
use pipewire::spa::ReadableDict;
use pipewire::types::ObjectType;

pub fn mypipewrite_spawn_mainloop() -> JoinHandle<ExitCode> {
    let pw_thread = thread::spawn(|| {
        let mainloop = MainLoop::new().expect("failed to get main loop");
        let context = Context::new(&mainloop).expect("failed to get context");
        let core = context.connect(None).expect("failed to get core");
        let registry = core.get_registry().expect("failed to get registry");
   
        let _listener = registry
            .add_listener_local()
            .global(|global| {
                if global.type_ == ObjectType::Port {
                    // 原Port处理逻辑不变
                    let props = global.props.as_ref().unwrap();
                    let port_name = props.get("port.name");
                    let port_alias = props.get("port.alias");
                    let object_path = props.get("object.path");
                    let format_dsp = props.get("format.dsp");
                    let audio_channel = props.get("audio.channel");
                    let port_id = props.get("port.id");
                    let port_direction = props.get("port.direction");
                    println!("Port: Name: {:?} Alias: {:?}  Id: {:?} Direction: {:?} AudioChannel: {:?} Object Path: {:?} FormatDsp: {:?}",
                        port_name, port_alias, port_id, port_direction, audio_channel, object_path, format_dsp
                    );
                } else if global.type_ == ObjectType::Device {
                    // 原Device处理逻辑不变
                    let props = global.props.as_ref().unwrap();
                    let device_name = props.get("device.name");
                    let device_nick = props.get("device.nick");
                    let device_description = props.get("device.description");
                    let device_api = props.get("device.api");
                    let media_class = props.get("media.class");
                    println!("Device: Name: {:?} Nick: {:?} Desc: {:?} Api: {:?} MediaClass: {:?}",
                        device_name, device_nick, device_description, device_api, media_class
                    );
                } else if global.type_ == ObjectType::Node {
                    let props = global.props.as_ref().unwrap();
                    let node_name = props.get("node.name");
                    let node_description = props.get("node.description");
                    let media_class = props.get("media.class");
                    let device_id = props.get("device.id");
                    let is_default = props.get("node.is-default");

                    // 识别默认音频输出
                    if media_class == Some("Audio/Sink") && is_default == Some("true") {
                        println!("默认音频输出Node: Name: {:?} Desc: {:?} 所属Device ID: {:?}",
                            node_name, node_description, device_id
                        );
                    }
                    // 识别默认音频输入
                    if media_class == Some("Audio/Source") && is_default == Some("true") {
                        println!("默认音频输入Node: Name: {:?} Desc: {:?} 所属Device ID: {:?}",
                            node_name, node_description, device_id
                        );
                    }
                    // 识别默认视频输出(摄像头)
                    if media_class == Some("Video/Source") && is_default == Some("true") {
                        println!("默认视频输出Node: Name: {:?} Desc: {:?} 所属Device ID: {:?}",
                            node_name, node_description, device_id
                        );
                    }
                }
            })
            .register();

        mainloop.run();
        ExitCode::FAILURE
    });
    pw_thread
}

方案2:直接调用Core的默认节点查询API

pipewire-rs的Core结构体提供了get_default_node方法,可以直接查询指定类型的默认节点,这种方式更简洁(需要异步处理):

// 在core创建后添加以下异步查询逻辑
use pipewire::core::NodeType;
use tokio::runtime::Runtime;

// 初始化Tokio运行时处理异步调用
let runtime = Runtime::new().unwrap();
runtime.block_on(async {
    // 查询默认音频输出
    if let Ok(default_sink) = core.get_default_node(NodeType::AudioSink).await {
        let props = default_sink.props().unwrap();
        println!("默认音频输出: {:?}", props.get("node.description"));
    }
    // 查询默认音频输入
    if let Ok(default_source) = core.get_default_node(NodeType::AudioSource).await {
        let props = default_source.props().unwrap();
        println!("默认音频输入: {:?}", props.get("node.description"));
    }
    // 查询默认视频输出
    if let Ok(default_video_source) = core.get_default_node(NodeType::VideoSource).await {
        let props = default_video_source.props().unwrap();
        println!("默认视频输出: {:?}", props.get("node.description"));
    }
});

关键说明

  • PipeWire中Device是硬件设备抽象,Node是实际可用于流传输的端点,默认设备对应带有node.is-default=true属性的Node
  • 如果node.is-default属性不存在,可通过node.priority值判断,优先级最高的即为默认设备
  • 视频输出设备通常对应Video/Source类型的Node,对应摄像头等视频采集设备

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 13:45:52